Merge lp:~apw/britney/britney1-ubuntu--fix-bug-blocks into lp:britney

Proposed by Andy Whitcroft
Status: Superseded
Proposed branch: lp:~apw/britney/britney1-ubuntu--fix-bug-blocks
Merge into: lp:britney
Diff against target: 7386 lines (+7242/-0)
28 files modified
README (+104/-0)
britney (+584/-0)
fauxpkg/FauxPackages (+69/-0)
fauxpkg/README (+50/-0)
fauxpkg/fauxpkg.py (+193/-0)
fauxpkg/noremove.d/README (+3/-0)
scripts/backlog-report (+95/-0)
scripts/ood_report.py (+101/-0)
scripts/udeb-report (+49/-0)
update_out/.gitignore (+6/-0)
update_out/Makefile (+33/-0)
update_out/README (+32/-0)
update_out/assert.c (+11/-0)
update_out/britney-py.c (+871/-0)
update_out/checklib.c (+185/-0)
update_out/dpkg-lib.cpp (+34/-0)
update_out/dpkg.c (+2013/-0)
update_out/dpkg.h (+207/-0)
update_out/freelist.c (+188/-0)
update_out/freelist.h (+14/-0)
update_out/index.html (+18/-0)
update_out/memory.c (+389/-0)
update_out/memory.h (+47/-0)
update_out/memory2.c (+20/-0)
update_out/memory3.c (+209/-0)
update_out/templates.h (+277/-0)
update_out/thoughts (+13/-0)
update_out/update_out.py (+1427/-0)
To merge this branch: bzr merge lp:~apw/britney/britney1-ubuntu--fix-bug-blocks
Reviewer Review Type Date Requested Status
Ubuntu Package Archive Administrators Pending
Review via email: mp+380628@code.launchpad.net

Commit message

When searching against a distribution we only actually will find tasks on
bugs open against development. This leads us to miss bugs which either
have a closed development task or have no development task at all. This
affects bugs in then development series which have no general development
task, and those nominated to older series and have a closed development
task. In particular these forms are seen with kernel tracking bugs.

Enhance the blocking bug search to search in both the distribution and
the associated series.

This has been run in unit-test against development and produces the same
block list there. It has been tested against the current live stable
releases and seems to produce believeable block lists, and significantly
longer ones in those releases.

To post a comment you must log in.

Unmerged revisions

329. By Andy Whitcroft

britney: identify bug blocks against the nominated series as well as devel

When searching against a distribution we only actually will find tasks on
bugs open against development. This leads us to miss bugs which either
have a closed development task or have no development task at all. This
affects bugs in then development series which have no general development
task, and those nominated to older series and have a closed development
task. In particular these forms are seen with kernel tracking bugs.

Enhance the blocking bug search to search in both the distribution and the
associated series.

This has been run in unit-test against development and produces the same
block list there. It has been tested against the current live stable
releases and seems to produce believeable block lists, and significantly
longer ones in those releases.

Signed-off-by: Andy Whitcroft <email address hidden>

328. By Adam Conrad

eoan -> focal

327. By Adam Conrad

[rbalint, r=adconrad] List bugs tagged as update-excuse(-<release>) in ExcuseBugs

326. By Łukasz Zemczak

Once again enable sru-regression e-mails.

325. By Iain Lane

turn off sru-regression emails

they are sending false positives and Łukasz is going to look into it

324. By Iain Lane

fauxpkg.py: Check all directories for packages

If a package exists in the release pocket, we should not write a faux package
just because it doesn't exist in proposed.

323. By Iain Lane

fauxpkg.py: Don't look at source names

Faux packages are *binary* package names. When considering if there are
duplicates, we should only look at the binaries in the input Packages file and
not the sources as we have been previously doing.

322. By Iain Lane

fauxpkg.py: Print the full path when skipping FauxPackage entries

there's something wrong here - we're skipping things we shouldn't be; would be
helpful to see what's going wrong

321. By Iain Lane

Put the gnome-shell FauxPackage back

We still need this on eoan. It shouldn't break other releases any more, since
r319. If it does, let's fix that instead.

320. By Łukasz Zemczak

Switch off the dry-run enforcement for sru regression notification.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'README'
2--- README 1970-01-01 00:00:00 +0000
3+++ README 2020-03-12 14:58:23 +0000
4@@ -0,0 +1,104 @@
5+Britney is run from /org/release.debian.org/britney. Some notes about
6+how it works, what to do and what not:
7+
8+ * the code is in code/b1, which is a git repo. Changes must be
9+ approved by Release Managers first, and all changes must be commited
10+ (i.e. nothing uncommited is allowed there).
11+
12+ Commit emails will be send to britney@release.debian.org, you can
13+ subscribe to that if you want them (along with cron mail from
14+ britney).
15+
16+ * the main script is code/b1/britney. It accepts a list of "actions"
17+ to perform. See ~release/etc/crontab.release for the default list,
18+ and see the "Actions" and "Re-running" sections below.
19+
20+ * input/ contains FauxPackages, edit if if you need, and an urgencies/
21+ subdirectory where dinstall places a summary of the uploads of that
22+ day.
23+
24+ * Heidi/, ssh/: see the "save" action below.
25+
26+ * d-i/: udeb handling is done by the release team too. See d-i/README
27+ for details (when Dato writes it; Dato takes care of udebs until then).
28+
29+
30+Actions
31+=======
32+
33+The main actions (read, the ones that are invoked from cron) are:
34+
35+ * urgencies: updates var/data/testing/Urgency with the data provided
36+ by dinstall.
37+
38+ * bugs: fetches bug counts from bugs.debian.org.
39+
40+ * pkglists: generates all needed Packages files according to the
41+ latest dinstall.
42+
43+ * run: the main action, running the update_out.py script. Takes
44+ hints, packages files, and tries to migrate stuff. When done, it
45+ writes a HeidiResult file used by "save" below *and rewrites the
46+ var/data/testing/Packags_* files*. That is important.
47+
48+ * save: commits the HeidiResult provided by update_out above. This is
49+ done by:
50+
51+ - taking HeidiResult, stripping unwanted stuff (faux packages),
52+ and put the result into a file under Heidi/set, named after the
53+ current timestamp.
54+
55+ - changing the "current" symlink under Heidi/set to point to this
56+ new file, gzipping the previous current.
57+
58+ - signaling ftpmaster scripts to import the new file. This is done
59+ with a ssh trigger, whose key is in ssh/.
60+
61+ IF YOU NEED TO UNDO ONE IMPORT: gunzip the previous file, point
62+ the "current" symlink to it, and:
63+
64+ % ssh -2 -i % ~release/britney/ssh/ftp-master_trigger_key dak@ries.debian.org
65+
66+ * stats: copies the resulting update.OUTPUT and update.EXCUSES files
67+ to www/britney, and checks for uninstallabilities.
68+
69+
70+Re-running
71+==========
72+
73+Re-runs can be incremental or not:
74+
75+ * incremental means that you run britney against the results of the
76+ previous run. This is done by just issuing `./britney run`.
77+
78+ WARNING: even if you don't save the results of an incremental
79+ re-run, following re-runs will start with the state the previous one
80+ left. This means it's a very very bad idea to use incremental
81+ re-runs to test force-hint hints; please always use a private
82+ britney instead.
83+
84+ * non-incremental means that you start from scratch against the state
85+ of the previous install. To do this, you need to do "pkglists" prior
86+ to "run".
87+
88+ IF THERE WERE ANY SUCCESSFUL HINTS IN THE PREVIOUS RUN, YOU MUST
89+ CHECK WITH THEIR OWNERS WHETHER IT'S OK TO RUN FROM SCRATCH. Or, in
90+ the worst case, you should check whether they have cleaned up their
91+ hints already, since in that case their work will be lost.
92+
93+ (For this reason it's not very wise to clean your hints before your
94+ stuff is dinstalled.)
95+
96+If you're satisfied with the result of your re-run, run `./britney save`.
97+
98+
99+Private britneys
100+================
101+
102+It is ok to run private britneys if you nice them, though Ganneff
103+prefers if you don't do it while dinstall is running.
104+
105+Do NOT run your britney against britney/var/data directly, use a
106+copy of your own.
107+
108+TODO(dato): Some HOWTO here.
109
110=== added file 'britney'
111--- britney 1970-01-01 00:00:00 +0000
112+++ britney 2020-03-12 14:58:23 +0000
113@@ -0,0 +1,584 @@
114+#!/bin/bash
115+
116+set -e
117+set -u
118+
119+ulimit -d 8000000 -m 8000000 -v 8000000
120+umask 002
121+
122+
123+OPTIONS="$@"
124+qoption () {
125+ for a in $OPTIONS; do if [ "$a" = "$1" ]; then return 0; fi; done
126+ return 1
127+}
128+
129+option () {
130+ for a in $OPTIONS; do if [ "$a" = "$1" ]; then date -uR; return 0; fi; done
131+ return 1
132+}
133+
134+LP_SERVICE="${LP_SERVICE:-production}"
135+DISTRIBUTION="${DISTRIBUTION:-ubuntu}"
136+DEFAULT_SERIES=focal
137+SERIES="${SERIES:-$DEFAULT_SERIES}"
138+
139+# DATE
140+NOW=`date +"%F/%T" -u`
141+
142+# Dirs:
143+BASE=/home/ubuntu-archive/proposed-migration
144+DAK_LOCKDIR=/srv/ftp-master.debian.org/lock
145+FTP_MIRROR=/home/ubuntu-archive/mirror/$DISTRIBUTION
146+
147+D_I=$BASE/d-i
148+VAR=$BASE/var
149+SSH=$BASE/ssh
150+HEIDI=$BASE/Heidi
151+INPUT=$BASE/input
152+CODE=$BASE/code/b1
153+
154+DATA=$VAR/data
155+LOCKDIR=$VAR/lock
156+HEIDI_SET=$HEIDI/set
157+SCRIPTS=$CODE/scripts
158+FAUXDIR=$CODE/fauxpkg
159+UPDATE_OUT=$CODE/update_out
160+URGENCIES=$INPUT/urgencies
161+
162+LOCK=$LOCKDIR/britney-$DISTRIBUTION-$SERIES.lock
163+DAK_LOCK=$DAK_LOCKDIR/daily.lock
164+DAK_STOP=$DAK_LOCKDIR/archive.stop
165+
166+TESTING=$DATA/$SERIES
167+UNSTABLE=$DATA/$SERIES-proposed
168+TPU=$DATA/testing-proposed-updates
169+
170+FAUXPKG_SCRIPT=$FAUXDIR/fauxpkg.py
171+SSH_KEY=$SSH/ftp-master_trigger_key
172+
173+HTML=/home/ubuntu-archive/public_html/proposed-migration
174+if [ "$DISTRIBUTION" != ubuntu ]; then
175+ HTML="$HTML/$DISTRIBUTION"
176+fi
177+BOOTSTRAP_DIR=/home/ubuntu-archive/public_html/bootstrap
178+
179+# Britney 2
180+DATA_B2=$VAR/data-b2
181+CODE_B2=$BASE/code/b2
182+B2_OUTPUT=$DATA_B2/output
183+B2_CONFIG=${B2_CONFIG:-$CODE_B2/britney.conf}
184+B2_CONFIG_NOBREAKALL=${B2_CONFIG_NOBREAKALL:-$CODE_B2/britney_nobreakall.conf}
185+B2_AMQP_PASSWORD="$(cat $BASE/amqp-password.txt)"
186+
187+if [ -f $DAK_STOP ]; then
188+ echo "$DAK_STOP exists, not running"
189+ exit 1
190+fi
191+
192+# 10800 seconds = 3 hours
193+# 129600 seconds = 36 hours
194+if ! lockfile -r0 -l129600 $LOCK 2>/dev/null >/dev/null; then
195+ echo "Could not get britney lockfile!"
196+ ls -l "$LOCK"
197+ exit 1
198+fi
199+
200+trap exit_function 0
201+exit_function () {
202+ rm -f $LOCK
203+}
204+
205+#eval $( dak admin config db-shell )
206+
207+suite_info () {
208+ python -c '
209+from __future__ import print_function
210+
211+import os
212+import sys
213+
214+from launchpadlib.launchpad import Launchpad as _Launchpad
215+
216+# Work around non-multiple-instance-safety of launchpadlib (bug #459418).
217+class Launchpad(_Launchpad):
218+ @classmethod
219+ def _get_paths(cls, service_root, launchpadlib_dir=None):
220+ service_root, launchpadlib_dir, cache_path, service_root_dir = (
221+ _Launchpad._get_paths(
222+ service_root, launchpadlib_dir=launchpadlib_dir))
223+ cache_path += "-proposed-migration"
224+ if not os.path.exists(cache_path):
225+ os.makedirs(cache_path, 0o700)
226+ return service_root, launchpadlib_dir, cache_path, service_root_dir
227+
228+launchpad = Launchpad.login_anonymously("proposed-migration", sys.argv[1])
229+distro = launchpad.distributions[sys.argv[2]]
230+series_name = sys.argv[3].split("-")[0]
231+series = distro.getSeries(name_or_version=series_name)
232+'"$1" "$LP_SERVICE" "$DISTRIBUTION" "$2"
233+}
234+
235+suite_arches () {
236+ suite_info 'print(" ".join(arch.architecture_tag for arch in series.architectures))' "$1"
237+}
238+
239+suite_archindep () {
240+ suite_info 'print(series.nominatedarchindep.architecture_tag)' "$1"
241+}
242+
243+if ! qoption allowdaklock; then
244+ while [ -f $DAK_LOCK ]; do
245+ echo `date` $DAK_LOCK exists. Sleeping in 10 more minutes.
246+ sleep 600
247+ done
248+fi
249+
250+urgencies () {
251+ echo URGENCIES:
252+ cd $BASE
253+ for u in $URGENCIES/install-urgencies-*; do
254+ [ -e "$u" ] || continue
255+ cat "$u" >> $1/$SERIES/Urgency # XXX I'd rather not have this in $DATA --dato
256+ rm "$u"
257+ done
258+}
259+
260+if option urgencies; then
261+ urgencies $DATA_B2
262+fi
263+
264+bugs () {
265+ for suite in $SERIES $SERIES-proposed; do
266+ x="$1/${suite}/BugsV"
267+ wget --quiet -O "${x}.new" http://bugs.debian.org/release-critical/britney/${suite}-nr
268+ if [ -s ${x}.new ]; then mv ${x}.new $x; else rm $x.new; exit 1; fi
269+ done
270+}
271+if option bugs; then
272+ echo BUGS:
273+ bugs $DATA_B2
274+fi
275+
276+if option bugs_b1; then
277+ echo BUGS_B1:
278+ bugs $DATA
279+fi
280+
281+if option bugs_b2; then
282+ echo BUGS_B2:
283+ bugs $DATA_B2
284+fi
285+
286+excuse_bugs() {
287+ tagged_bugs $1 update-excuse ExcuseBugs
288+}
289+
290+blocks () {
291+ tagged_bugs $1 block-proposed Blocks
292+}
293+
294+tagged_bugs () {
295+ local tag_template tags output_file
296+ tag_template=$2
297+ output_file=$3
298+ [ "$DISTRIBUTION" = ubuntu ] || return 0
299+ mkdir -p "$1/$SERIES-proposed"
300+ if [ "$SERIES" = "$DEFAULT_SERIES" ]; then
301+ tags="$tag_template $tag_template-$SERIES"
302+ else
303+ tags="$tag_template-$SERIES"
304+ fi
305+ python -c '
306+from __future__ import print_function
307+
308+import calendar
309+import os
310+import sys
311+try:
312+ from urllib.parse import urlsplit
313+except ImportError:
314+ from urlparse import urlsplit
315+
316+from launchpadlib.launchpad import Launchpad as _Launchpad
317+
318+# Work around non-multiple-instance-safety of launchpadlib (bug #459418).
319+class Launchpad(_Launchpad):
320+ @classmethod
321+ def _get_paths(cls, service_root, launchpadlib_dir=None):
322+ service_root, launchpadlib_dir, cache_path, service_root_dir = (
323+ _Launchpad._get_paths(
324+ service_root, launchpadlib_dir=launchpadlib_dir))
325+ cache_path += "-proposed-migration"
326+ if not os.path.exists(cache_path):
327+ os.makedirs(cache_path, 0o700)
328+ return service_root, launchpadlib_dir, cache_path, service_root_dir
329+
330+launchpad = Launchpad.login_with("proposed-migration", sys.argv[1])
331+distro = launchpad.distributions[sys.argv[2]]
332+tags = sys.argv[3].split()
333+series = distro.getSeries(name_or_version=sys.argv[4])
334+blocks = set()
335+tasks = list(series.searchTasks(omit_targeted=False, tags=tags))
336+tasks += list(distro.searchTasks(omit_targeted=False, tags=tags))
337+block_detail = {}
338+for task in tasks:
339+ target = task.target
340+ bug = task.bug
341+ if urlsplit(target.resource_type_link).fragment in (
342+ "distribution_source_package", "source_package"):
343+ date = block_detail.get(bug.id)
344+ if date is None:
345+ for action in reversed(
346+ [a for a in bug.activity if a.whatchanged == "tags"]):
347+ oldtags = action.oldvalue.split()
348+ newtags = action.newvalue.split()
349+ gained_block = False
350+ for tag in tags:
351+ if tag not in oldtags and tag in newtags:
352+ gained_block = True
353+ break
354+ if gained_block:
355+ date = action.datechanged
356+ break
357+ else:
358+ date = bug.date_created
359+ block_detail[bug.id] = date
360+ blocks.add("%s %d %d" %
361+ (os.path.basename(target.self_link), bug.id,
362+ calendar.timegm(date.timetuple())))
363+print("\n".join(sorted(blocks)))
364+' "$LP_SERVICE" "$DISTRIBUTION" "$tags" "$SERIES" >"$1/$SERIES-proposed/$output_file.new"
365+ mv "$1/$SERIES-proposed/$output_file.new" "$1/$SERIES-proposed/$output_file"
366+}
367+if option blocks; then
368+ echo BLOCKS:
369+ blocks $DATA_B2
370+fi
371+if option excuse_bugs; then
372+ echo EXCUSE BUGS:
373+ excuse_bugs $DATA_B2
374+fi
375+
376+pkg_lists () {
377+ for suite in $SERIES $SERIES-proposed; do
378+ mkdir -p $1/$suite
379+ suite_dirs=$FTP_MIRROR/dists/$suite
380+ if [ "$suite" = "$SERIES" ]; then
381+ suite_dirs="$suite_dirs $FTP_MIRROR/dists/$SERIES-updates"
382+ fi
383+ >$1/$suite/Sources
384+ for suite_dir in $suite_dirs; do
385+ gzip -t $suite_dir/{main,restricted,universe,multiverse}/source/Sources.gz
386+ zcat $suite_dir/{main,restricted,universe,multiverse}/source/Sources.gz >>$1/$suite/Sources
387+ done
388+ for arch in `suite_arches $suite`; do
389+ >$1/$suite/Packages_$arch
390+ for suite_dir in $suite_dirs; do
391+ gzip -t $suite_dir/{main,restricted,universe,multiverse}/binary-$arch/Packages.gz
392+ zcat $suite_dir/{main,restricted,universe,multiverse}/binary-$arch/Packages.gz >>$1/$suite/Packages_$arch
393+ gzip -t $suite_dir/{main,restricted,universe,multiverse}/debian-installer/binary-$arch/Packages.gz
394+ zcat $suite_dir/{main,restricted,universe,multiverse}/debian-installer/binary-$arch/Packages.gz >>$1/$suite/Packages_$arch
395+ done
396+ done
397+ done
398+ $FAUXPKG_SCRIPT generate $1/$SERIES $1/$SERIES-proposed
399+}
400+
401+lite_sync () {
402+ cat <<EOF | rsync -a --files-from=- $1 $2
403+$SERIES/Dates
404+$SERIES/BugsV
405+$SERIES/Urgency
406+$SERIES-proposed/BugsV
407+$SERIES-proposed/Hints
408+EOF
409+
410+}
411+
412+if option pkglists; then
413+ echo PKGLISTS:
414+ cd $DATA_B2
415+ pkg_lists $DATA_B2
416+fi
417+
418+if option sync_b2; then
419+ rsync -ar $DATA/ $DATA_B2
420+fi
421+
422+# Give options to run a b2 from scratch after b1 has finished
423+if option pkglists_b2; then
424+ echo PKGLISTS_B2:
425+ cd $DATA_B2
426+ pkg_lists $DATA_B2
427+fi
428+
429+if option pkglists_b1; then
430+ echo PKGLISTS_B1:
431+ cd $DATA
432+ pkg_lists $DATA
433+fi
434+
435+if option sync_b2_lite; then
436+ lite_sync $DATA $DATA_B2
437+fi
438+
439+if option sync_b1; then
440+ rsync -ar $DATA_B2/ $DATA
441+fi
442+
443+if option sync_b1_lite; then
444+ lite_sync $DATA_B2 $DATA
445+fi
446+
447+make_hints_branch () {
448+ if [ -d "$1" ]; then
449+ bzr pull -q -d "$1" --remember --overwrite "$2"
450+ else
451+ bzr branch "$2" "$1"
452+ fi
453+}
454+
455+if option hints_bzr; then
456+ echo HINTS_BZR:
457+ if [ "$DISTRIBUTION" = ubuntu ]; then
458+ if [ "$SERIES" = "$DEFAULT_SERIES" ]; then
459+ branch="lp:~ubuntu-release/britney/hints-ubuntu"
460+ else
461+ branch="lp:~ubuntu-sru/britney/hints-ubuntu-$SERIES"
462+ fi
463+ make_hints_branch "$DATA_B2/$SERIES-proposed/Hints" "$branch"
464+ if [ "$SERIES" = "$DEFAULT_SERIES" ]; then
465+ make_hints_branch \
466+ "$DATA_B2/$SERIES-proposed/Hints/ubuntu-touch" \
467+ "lp:~ubuntu-touch-release/britney/hints-ubuntu-touch"
468+ else
469+ rm -rf "$DATA_B2/$SERIES-proposed/Hints/ubuntu-touch"
470+ fi
471+ elif [ "$DISTRIBUTION" = ubuntu-rtm ]; then
472+ make_hints_branch \
473+ "$DATA_B2/$SERIES-proposed/Hints" \
474+ lp:~ubuntu-release/britney/hints-ubuntu-rtm
475+ fi
476+fi
477+
478+run_b1 () {
479+ cd $UPDATE_OUT
480+ ./update_out.py $TESTING $UNSTABLE $TPU
481+}
482+
483+b2_diff () {
484+ tmp_dir=`mktemp -d`
485+ master="b2"
486+ [ "$master" = "b1" ] && secondary="b2" || secondary="b1"
487+ (cd $tmp_dir
488+
489+ sort $TESTING/HeidiResult >HeidiResult_b1
490+ sort $B2_OUTPUT/$SERIES/HeidiResult >HeidiResult_b2
491+
492+ sed -e '/^<p>Generated: /d' $CODE/update_out/update.EXCUSES_py >excuses_b1.html
493+ sed -e '/^<p>Generated: /d' $B2_OUTPUT/$SERIES/excuses.html >excuses_b2.html
494+
495+ touch -m -r $TESTING/HeidiResult HeidiResult_b1
496+ touch -m -r $B2_OUTPUT/$SERIES/HeidiResult HeidiResult_b2
497+
498+ touch -m -r $CODE/update_out/update.EXCUSES_py excuses_b1.html
499+ touch -m -r $B2_OUTPUT/$SERIES/excuses.html excuses_b2.html
500+
501+ # NB: If you remove the "head" below, add a "|| true"; otherwise
502+ # set -e may not allow the HeidiResult diff to execute.
503+ diff -u excuses_${master}.html excuses_${secondary}.html | head -n 1000
504+ diff -u HeidiResult_${master} HeidiResult_${secondary} | head -n 1000)
505+ rm -rf $tmp_dir
506+}
507+
508+b2_diff_with_mail () {
509+ b2_diff
510+ b2_diff | ifne mail -s "britney2 diff `date -u +'%Y-%m-%d %H:%M'`" \
511+ -a "Reply-To: britney2@release.debian.org" britney2@release.debian.org
512+}
513+
514+make_b2_config () {
515+ local arches archindep
516+ arches=`suite_arches $SERIES`
517+ archindep=`suite_archindep $SERIES`
518+ sed -e "s/^\\(ARCHITECTURES *= \\).*/\\1$arches/" \
519+ -e "s/^\\(NOBREAKALL_ARCHES *= \\).*/\\1$archindep/" \
520+ -e "/^ADT_AMQP/ s@:password@:${B2_AMQP_PASSWORD//@/\\@}@" \
521+ "$1" >"$2"
522+ # precise does not yet have ppc64el
523+ if [ "$SERIES" = precise ]; then
524+ sed -i '/^ADT_ARCHES/ s/ppc64el//' "$2"
525+ fi
526+ # only do the email thing for the default series
527+ #
528+ # and
529+ #
530+ # only do SRU regression emails for the non default series
531+ if [ "$SERIES" != "$DEFAULT_SERIES" ]; then
532+ sed -i '/^EMAIL_ENABLE/ s/=.*$/= no/' "$2"
533+ sed -i '/^SRUREGRESSIONEMAIL_ENABLE/ s/=.*$/= yes/' "$2"
534+ fi
535+ case $arches in
536+ *s390x*)
537+ sed -i -e'/^ADT_ARCHES/ s/$/ s390x/' "$2"
538+ ;;
539+ esac
540+}
541+
542+make_b2_notest_config () {
543+ sed -e '/^NONINST_STATUS/ s/ *$/-notest/' \
544+ -e '/^EXCUSES_.*OUTPUT/ s%=.*$%= /dev/null%' \
545+ -e '/^UPGRADE_OUTPUT/ s/output.txt/output_notest.txt/' \
546+ -e '/^HEIDI_OUTPUT/ s/=.*$/=/' \
547+ -e '/^ADT_ENABLE/ s/yes/no/' \
548+ -e '/^EMAIL_ENABLE/ s/=.*$/= no/' \
549+ "$1" > "$2"
550+}
551+
552+run_b2 () {
553+ cd $BASE
554+ make_b2_config "$B2_CONFIG" "$B2_CONFIG.$DISTRIBUTION.$SERIES"
555+ $CODE_B2/britney.py -c "$B2_CONFIG.$DISTRIBUTION.$SERIES" -v --distribution=$DISTRIBUTION --series=$SERIES
556+
557+ if [ "$SERIES" = "$DEFAULT_SERIES" ]; then
558+ # for the devel series we also want an output.txt without tests, to make
559+ # it easier to untangle library transitions
560+ make_b2_notest_config "$B2_CONFIG.$DISTRIBUTION.$SERIES" "$B2_CONFIG.$DISTRIBUTION.$SERIES.notest"
561+ $CODE_B2/britney.py -c "$B2_CONFIG.$DISTRIBUTION.$SERIES.notest" --distribution=$DISTRIBUTION --series=$SERIES >/dev/null
562+ else
563+ rm -f $DATA_B2/output/$SERIES/output_notest.txt
564+ fi
565+}
566+
567+if option run; then
568+ echo RUN:
569+ run_b2
570+fi
571+
572+if option run_b1; then
573+ echo RUN_B1:
574+ run_b1
575+ # assume that this will have been run after a "run" which is b2
576+ b2_diff_with_mail
577+fi
578+
579+if option run_b2; then
580+ echo RUN_B2:
581+ run_b2
582+ b2_diff_with_mail
583+fi
584+
585+if option b2_diff; then
586+ b2_diff
587+fi
588+
589+lp_import() {
590+ # tell LP about the new delta
591+ promote-to-release -l "$LP_SERVICE" -d "$DISTRIBUTION" -s "$SERIES" -v "$1"
592+}
593+
594+save () {
595+ cd $BASE
596+ echo RESULTS:
597+ # process a delta
598+ if [ "$1" = "b1" ]; then
599+ DELTA="$TESTING/HeidiResultDelta"
600+ else
601+ DELTA="$B2_OUTPUT/$SERIES/HeidiResultDelta"
602+ fi
603+ echo Using data from $DELTA
604+ lp_import "$DELTA"
605+ printf " done\n"
606+}
607+
608+if option save_b1; then
609+ save b1
610+fi
611+if option save || option save_b2; then
612+ save b2
613+fi
614+
615+create_uninst_report () {
616+ $CODE_B2/britney.py -c $1 --distribution=$DISTRIBUTION --series=$SERIES --print-uninst >$HTML/$2.new
617+ echo -e "\n# Generated: `date -uR`" >>$HTML/$2.new
618+ mv $HTML/$2.new $HTML/$2
619+}
620+
621+create_ood_report () {
622+ $SCRIPTS/ood_report.py $1 >$HTML/$2.new
623+ echo -e "\n# Generated: `date -uR`" >>$HTML/$2.new
624+ mv $HTML/$2.new $HTML/$2
625+}
626+
627+stats () {
628+ echo STATS:
629+ mkdir -p "$HTML/$SERIES"
630+ if [ "$1" = "b1" ]; then
631+ cp $UPDATE_OUT/update.EXCUSES_py $HTML/$SERIES/update_excuses.html
632+ cp $UPDATE_OUT/update.OUTPUT_py $HTML/$SERIES/update_output.txt
633+ else
634+ cp $DATA_B2/output/$SERIES/excuses.html $HTML/$SERIES/update_excuses.html
635+ cp $DATA_B2/output/$SERIES/excuses.yaml $HTML/$SERIES/update_excuses.yaml
636+ cp $DATA_B2/output/$SERIES/output.txt $HTML/$SERIES/update_output.txt
637+ if [ -e $DATA_B2/output/$SERIES/output_notest.txt ]; then
638+ cp $DATA_B2/output/$SERIES/output_notest.txt $HTML/$SERIES/update_output_notest.txt
639+ else
640+ rm -f $HTML/$SERIES/update_output_notest.txt
641+ fi
642+ cp $DATA_B2/$SERIES-proposed/Blocks $HTML/$SERIES/blocks.txt
643+ cp $DATA_B2/$SERIES-proposed/ExcuseBugs $HTML/$SERIES/excuse-bugs.txt || true
644+ fi
645+ #gzip -9 < $HTML/$SERIES/update_excuses.html > $HTML/$SERIES/update_excuses.html.gz
646+ #gzip -9 < $HTML/$SERIES/update_output.txt > $HTML/$SERIES/update_output.txt.gz
647+ mkdir -p "$HTML/update_output/$SERIES/${NOW%/*}"
648+ mkdir -p "$HTML/update_excuses/$SERIES/${NOW%/*}"
649+ gzip -9c $HTML/$SERIES/update_output.txt > $HTML/update_output/$SERIES/$NOW.txt.gz
650+ gzip -9c $HTML/$SERIES/update_excuses.html > $HTML/update_excuses/$SERIES/$NOW.html.gz
651+ gzip -9c $HTML/$SERIES/update_excuses.yaml > $HTML/update_excuses/$SERIES/$NOW.yaml.gz
652+
653+ # TODO: {stable,unstable}_uninst.txt -- needs support in b2, talk to Fabio
654+ # TODO: this creates uninstallability reports against b2 results, not b1's
655+ make_b2_config "$B2_CONFIG" "$B2_CONFIG.$DISTRIBUTION.$SERIES"
656+ make_b2_config "$B2_CONFIG_NOBREAKALL" "$B2_CONFIG_NOBREAKALL.$DISTRIBUTION.$SERIES"
657+ create_uninst_report "$B2_CONFIG.$DISTRIBUTION.$SERIES" ${SERIES}_uninst.txt
658+ create_uninst_report "$B2_CONFIG_NOBREAKALL.$DISTRIBUTION.$SERIES" ${SERIES}_uninst_full.txt
659+
660+ #if grep -q -e '-meta-faux' $HTML/testing_uninst.txt; then
661+ # echo >&2 'Warning! Some -meta-faux package is uninstallable!'
662+ #fi
663+
664+ #create_ood_report $DATA_B2/stable stable_outdate.txt
665+ #create_ood_report $DATA_B2/testing testing_outdate.txt
666+
667+ $SCRIPTS/backlog-report -o $HTML/$SERIES/update_excuses.csv $HTML/$SERIES/update_excuses.html
668+}
669+
670+if option stats_b1; then
671+ stats b1
672+fi
673+if option stats || option stats_b2; then
674+ stats b2
675+fi
676+
677+if option summary; then
678+ cd $BASE
679+ echo "Out of dates holding up testing:"
680+ TERM=vt100 w3m -dump $HTML/$SERIES/update_excuses.html | sed -n 's/^ *[^ ] *[^ ]*out of date on \([^ ]*\): .*$/\1/p' | sort | uniq -c | sort -n
681+ echo "Uninstallables holding up testing:"
682+ sed < $HTML/$SERIES/update_excuses.html -n 's/^ *<li>[^ ]* (\([^, ]*\),.*) uninstallable.*$/\1/p' | sort | uniq -c | sort -n
683+ #echo "wanna-build stats:"
684+ #for a in alpha arm hppa hurd-i386 i386 ia64 m68k mips mipsel powerpc s390 sparc; do
685+ # printf " %-12s " "$a:"
686+ # /srv/wanna-build/bin/wanna-build-statistics --database=$a/build-db |
687+ # grep "if also counting" || echo "-"
688+ #done
689+fi
690+
691+if option archivedata; then
692+ echo ARCHIVE:
693+ cd $VAR
694+ tar czf data_bkup/data-$(date +"%Y.%m.%d").tgz data/{stable,testing,unstable,testing-proposed-updates}
695+fi
696+
697+echo -n "Finished at: "; date -uR
698
699=== added directory 'fauxpkg'
700=== added file 'fauxpkg/FauxPackages'
701--- fauxpkg/FauxPackages 1970-01-01 00:00:00 +0000
702+++ fauxpkg/FauxPackages 2020-03-12 14:58:23 +0000
703@@ -0,0 +1,69 @@
704+Package: wine1.4-i386
705+Source: wine1.6
706+Version: ${unstable-version}
707+Architecture: amd64
708+Provides: wine-i386
709+Multi-Arch: foreign
710+
711+Package: wine1.6-i386
712+Source: wine1.6
713+Version: ${unstable-version}
714+Architecture: amd64
715+Provides: wine-i386
716+Multi-Arch: foreign
717+
718+Package: ocaml-mingw-w64-x86-64
719+Source: mingw-ocaml
720+Version: ${unstable-version}
721+Architecture: i386
722+Multi-Arch: foreign
723+
724+Package: claws-mail-extra-plugins-dbg
725+Version: 1:1
726+
727+Package: claws-mail-html2-viewer
728+Version: 1:1
729+
730+Package: ubuntu-emulator-images
731+Source: android
732+Version: ${unstable-version}
733+Architecture: amd64 armhf
734+Multi-Arch: foreign
735+
736+Package: ubuntu-emulator-runtime
737+Source: android
738+Version: ${unstable-version}
739+Architecture: amd64 armhf
740+Multi-Arch: foreign
741+
742+Package: libnss-mdns-i386
743+Source: nss-mdns
744+Version: ${unstable-version}
745+Architecture: amd64
746+Multi-Arch: foreign
747+
748+Package: unity8
749+Version: ${unstable-version}
750+Architecture: powerpc ppc64el s390x
751+
752+Package: liboxideqt-qmlplugin
753+Source: oxide-qt
754+Version: ${unstable-version}
755+Architecture: powerpc ppc64el s390x
756+
757+Package: fenix
758+Version: ${unstable-version}
759+Architecture: amd64
760+
761+Package: fenix-plugins-system
762+Version: ${unstable-version}
763+Architecture: amd64
764+
765+Package: steam
766+Version: ${unstable-version}
767+Architecture: amd64
768+Multi-Arch: foreign
769+
770+Package: gnome-shell
771+Version: ${unstable-version}
772+Architecture: s390x
773
774=== added file 'fauxpkg/README'
775--- fauxpkg/README 1970-01-01 00:00:00 +0000
776+++ fauxpkg/README 2020-03-12 14:58:23 +0000
777@@ -0,0 +1,50 @@
778+Files and scripts in this directory are in charge on creating a list of
779+"faux" packages for britney. These are packages that do not exist in the
780+archive, but which we want britney to think they exist. At the moment
781+they are used for:
782+
783+ - allowing packages in contrib to migrate even if their dependencies
784+ are not satisfied within the archive. This is done by creating a
785+ faux package for each missing dependency.
786+
787+ - ensure some packages do not get accidentally removed, because they
788+ are needed by parts of testing which don't declare a Depends on
789+ them. In particular, to ensure packages needed by the installer and
790+ tasksel are not removed. This is done by creating faux packages that
791+ do depend on all packages which are not to be removed.
792+
793+To create packages of the first kind, just append suitable entries to
794+the toplevel FauxPackages file. These should have at least a Package and
795+Version fields. You can restrict their existance to certain architectures
796+by providing an Architecture field with a list of architectures. Other
797+fields are propagated verbatim to britney, eg. Provides.
798+
799+As for the second kind, you don't directly create faux packages, but
800+just append the packages which shouldn't be removed to the appropriate
801+file under the "noremove.d" directory. Those files just contain a list
802+of *binary* packages, one per line. A couple of important notes:
803+
804+ - if the binary package is not in testing, do not add it: wait until
805+ it migrates.
806+
807+ - if the binary package is not available on i386 (being arch:all would
808+ suffice), you have to qualify it with [arch], mentioning one arch in
809+ which it is available.
810+
811+ - the names of the files under noremove.d must be valid as package
812+ names, e.g. not contain underscores.
813+
814+The noremove.d/tasksel file is special: it gets generated automatically
815+by the fauxpkg.py script, by running the script with the "update-tasksel"
816+command. (Currently is it to be run by hand whenever the tasksel
817+maintainer notices our file is out of date.)
818+
819+One further caveat: if one of these faux meta-packages becomes uninstallable,
820+they stop working (since the removal of their dependencies does not increase
821+the uninstallability count). The britney script has a mechanism in place to
822+warn in case they become uninstallable. When adding packages to the lists,
823+make sure to watch the next britney mail, in case you added conflicting
824+packages. (In that case, you want to add such packages in different files
825+under noremove.d.)
826+
827+Please don't forget to commit your changes to files in this directory!
828
829=== added file 'fauxpkg/fauxpkg.py'
830--- fauxpkg/fauxpkg.py 1970-01-01 00:00:00 +0000
831+++ fauxpkg/fauxpkg.py 2020-03-12 14:58:23 +0000
832@@ -0,0 +1,193 @@
833+#! /usr/bin/python
834+## encoding: utf-8
835+#
836+# Copyright (c) 2008 Adeodato Simó (dato@net.com.org.es)
837+# Licensed under the terms of the MIT license.
838+
839+"""Handle the creation of britney faux packages.
840+
841+This program gets called from the "britney" script in order to append to the
842+Packages_<arch> files a list of faux packages. This is done with the "generate"
843+command, passing a list of britney suite directories:
844+
845+ % fauxpkg.py generate /home/release/britney/var/data/{testing,unstable}
846+
847+This automatically appeds to the Packages files the list of faux packages. See
848+the README file in this directory for the input files from which such list is
849+generated.
850+"""
851+
852+import os
853+import re
854+import sys
855+import glob
856+import tempfile
857+import subprocess
858+
859+from collections import defaultdict
860+
861+import apt_pkg
862+apt_pkg.init()
863+
864+##
865+
866+BASEDIR = os.path.dirname(__file__)
867+
868+NOREMOVE_DIR = os.path.join(BASEDIR, 'noremove.d')
869+FAUX_PACKAGES = os.path.join(BASEDIR, 'FauxPackages')
870+
871+DEFAULT_NOREMOVE_ARCH = 'amd64'
872+
873+##
874+
875+def main():
876+ if not sys.argv[1:]:
877+ print >>sys.stderr, 'Usage: %s <generate | update-tasksel> [ britney_suite_dir1 ... ]' % (
878+ os.path.basename(sys.argv[0]))
879+ sys.exit(1)
880+ else:
881+ command = sys.argv.pop(1)
882+
883+ if command == 'generate':
884+ if not sys.argv[1:]:
885+ print >>sys.stderr, 'E: need at least one britney suite directory'
886+ sys.exit(1)
887+ else:
888+ do_generate(sys.argv[1:])
889+ elif command == 'update-tasksel':
890+ if sys.argv[1:]:
891+ print >>sys.stderr, 'E: extra arguments not allowed'
892+ sys.exit(1)
893+ else:
894+ do_update_tasksel()
895+ else:
896+ print >>sys.stderr, 'E: unknown command %s' % (command,)
897+
898+##
899+
900+def do_generate(directories):
901+ arches = set()
902+ allfaux = {}
903+
904+ for dir_ in directories:
905+ arches.update([ re.sub(r'^.*/Packages_', '', x)
906+ for x in glob.glob(os.path.join(dir_, 'Packages_*')) ])
907+
908+ unstable_versions = {}
909+ all_packages = defaultdict(set)
910+ for dir_ in directories:
911+ with open(os.path.join(dir_, 'Sources')) as f:
912+ parser = apt_pkg.TagFile(f)
913+ for section in parser:
914+ if 'Package' in section and 'Version' in section:
915+ unstable_versions[section['Package']] = section['Version']
916+ for packages_file in glob.glob(os.path.join(dir_, 'Packages_*')):
917+ arch = re.sub(r'^.*/Packages_', '', packages_file)
918+ with open(packages_file, 'r') as f:
919+ with apt_pkg.TagFile(f) as tf:
920+ for section in tf:
921+ all_packages[arch] |= {section.get('Package')}
922+
923+ # First, FauxPackages
924+ try:
925+ parser = apt_pkg.TagFile(file(FAUX_PACKAGES))
926+ step = parser.step
927+ section = parser.section
928+ except AttributeError, e:
929+ parser = apt_pkg.ParseTagFile(file(FAUX_PACKAGES))
930+ step = parser.Step
931+ section = parser.Section
932+ while step():
933+ d = dict(section)
934+ d['Section'] = 'faux' # crucial; britney filters HeidiResult based on section
935+
936+ if not d.has_key('Architecture'):
937+ these_arches = arches
938+ else:
939+ these_arches = set(re.split(r'[, ]+', d['Architecture']))
940+
941+ d['Architecture'] = 'all' # same everywhere
942+
943+ if d.get('Version') == '${unstable-version}':
944+ source = d.get('Source', d.get('Package'))
945+ if source in unstable_versions:
946+ d['Version'] = unstable_versions[source]
947+
948+ for arch in these_arches:
949+ allfaux.setdefault(arch, []).append(d)
950+
951+ # Now, noremove.d
952+ for f in glob.glob(os.path.join(NOREMOVE_DIR, '*.list')):
953+ pkgs = {}
954+ basename = re.sub(r'.+/(.+)\.list', r'\1', f)
955+
956+ for line in file(f):
957+ line = line.strip()
958+ if re.match(r'^#', line):
959+ continue
960+ elif re.match(r'\S+$', line):
961+ pkg = line
962+ arch = DEFAULT_NOREMOVE_ARCH
963+ else:
964+ m = re.match(r'(\S+)\s+\[(.+)\]', line)
965+ if m:
966+ pkg, arch = m.groups()
967+ else:
968+ print >>sys.stderr, 'W: could not parse line %r' % (line,)
969+
970+ arch = re.split(r'[, ]+', arch)[0] # just in case
971+ pkgs.setdefault(arch, set()).add(pkg)
972+
973+ for arch in pkgs.keys():
974+ d = { 'Package': '%s-meta-faux' % (basename,), 'Version': '1',
975+ 'Section': 'faux', 'Architecture': '%s' % (arch,),
976+ 'Depends': ', '.join(pkgs[arch]) }
977+ allfaux.setdefault(arch, []).append(d)
978+
979+ # Write the result
980+ for arch in arches:
981+ if arch not in allfaux:
982+ continue
983+ for dir_ in directories:
984+ f = os.path.join(dir_, 'Packages_' + arch)
985+ if not os.path.exists(f):
986+ continue
987+ else:
988+ f = file(f, 'a')
989+ for d in allfaux[arch]:
990+ if d['Package'] in all_packages[arch]:
991+ print >>sys.stderr, 'W: skipping %s/%s (%s) as it is already known' % (d['Package'], arch, f.name)
992+ continue
993+ f.write('\n'.join('%s: %s' % (k, v) for k, v in d.iteritems()) + '\n\n')
994+
995+##
996+
997+def do_update_tasksel():
998+ p = subprocess.Popen('dak ls -f control-suite -s unstable -a source tasksel',
999+ shell=True, stdout=subprocess.PIPE)
1000+ p.wait()
1001+ version = p.stdout.readline().split()[1]
1002+
1003+ p = subprocess.Popen('dak ls -f control-suite -s unstable -S -a i386,all tasksel',
1004+ shell=True, stdout=subprocess.PIPE)
1005+ p.wait()
1006+ tasks = []
1007+
1008+ for line in p.stdout:
1009+ pkg = line.split()[0]
1010+
1011+ if pkg.startswith('task-'):
1012+ tasks.append(pkg)
1013+
1014+ # Write the new file
1015+ tmpfd, tmpname = tempfile.mkstemp(dir=NOREMOVE_DIR)
1016+ os.write(tmpfd, '# Generated from tasksel-data %s\n' % (version,))
1017+ os.write(tmpfd, '\n'.join(sorted(tasks)) + '\n')
1018+ os.close(tmpfd)
1019+ os.chmod(tmpname, 0644)
1020+ os.rename(tmpname, os.path.join(NOREMOVE_DIR, 'tasksel.list'))
1021+
1022+##
1023+
1024+if __name__ == '__main__':
1025+ main()
1026
1027=== added directory 'fauxpkg/noremove.d'
1028=== added file 'fauxpkg/noremove.d/README'
1029--- fauxpkg/noremove.d/README 1970-01-01 00:00:00 +0000
1030+++ fauxpkg/noremove.d/README 2020-03-12 14:58:23 +0000
1031@@ -0,0 +1,3 @@
1032+Packages listed in these files are protected against accidental removals
1033+from testing. Please mail debian-release@lists.debian.org if you think
1034+some package should be added to any of these lists.
1035
1036=== added directory 'scripts'
1037=== added file 'scripts/backlog-report'
1038--- scripts/backlog-report 1970-01-01 00:00:00 +0000
1039+++ scripts/backlog-report 2020-03-12 14:58:23 +0000
1040@@ -0,0 +1,95 @@
1041+#! /usr/bin/python
1042+#
1043+# Generate a report of the backlog in -proposed.
1044+
1045+from __future__ import print_function
1046+
1047+__metaclass__ = type
1048+
1049+import calendar
1050+import csv
1051+import gzip
1052+import io
1053+from optparse import OptionParser
1054+import os
1055+import re
1056+import sys
1057+import time
1058+
1059+
1060+generated_re = re.compile(r"^<p>Generated: (.*)</p>$")
1061+age_re = re.compile(r"^<li>([0-9]+) days old$")
1062+
1063+
1064+def import_excuses(csv_writer, path):
1065+ generated_time = None
1066+ valid_candidates = 0
1067+ not_considered = 0
1068+ ages = []
1069+ backlog = 0
1070+
1071+ if path.endswith(".gz"):
1072+ binary = gzip.open(path)
1073+ else:
1074+ binary = io.open(path, mode="rb")
1075+ try:
1076+ with io.BufferedReader(binary) as buffered:
1077+ with io.TextIOWrapper(buffered) as text:
1078+ for line in text:
1079+ match = generated_re.match(line)
1080+ age_match = age_re.match(line)
1081+ if match:
1082+ generated_time = time.strptime(
1083+ match.group(1), "%Y.%m.%d %H:%M:%S +0000")
1084+ elif age_match:
1085+ ages.append(int(age_match.group(1)))
1086+ backlog += max(int(age_match.group(1)) - 3, 0)
1087+ elif line.startswith("<li>Valid candidate"):
1088+ valid_candidates += 1
1089+ elif line.startswith("<li>Not considered"):
1090+ not_considered += 1
1091+ finally:
1092+ binary.close()
1093+
1094+ assert generated_time is not None
1095+
1096+ csv_writer.writerow({
1097+ "time": calendar.timegm(generated_time) * 1000,
1098+ "valid candidates": valid_candidates,
1099+ "not considered": not_considered,
1100+ "total": valid_candidates + not_considered,
1101+ "median age": ages[len(ages)/2],
1102+ "backlog": backlog,
1103+ })
1104+
1105+
1106+def main():
1107+ parser = OptionParser(description="Generate a backlog report.")
1108+ parser.add_option(
1109+ "-o", "--output", help="Write output to this file (default: stdout).")
1110+ options, args = parser.parse_args()
1111+
1112+ if options.output is not None:
1113+ csv_is_new = not os.path.exists(options.output)
1114+ if sys.version < "3":
1115+ output = open(options.output, "ab")
1116+ else:
1117+ output = open(options.output, "a", newline="")
1118+ else:
1119+ csv_is_new = True
1120+ output = sys.stdout
1121+
1122+ try:
1123+ csv_writer = csv.DictWriter(
1124+ output, ["time", "valid candidates", "not considered", "total", "median age", "backlog"])
1125+ if csv_is_new:
1126+ csv_writer.writeheader()
1127+ for arg in args:
1128+ import_excuses(csv_writer, arg)
1129+ finally:
1130+ if options.output is not None:
1131+ output.close()
1132+
1133+
1134+if __name__ == "__main__":
1135+ main()
1136
1137=== added file 'scripts/ood_report.py'
1138--- scripts/ood_report.py 1970-01-01 00:00:00 +0000
1139+++ scripts/ood_report.py 2020-03-12 14:58:23 +0000
1140@@ -0,0 +1,101 @@
1141+#! /usr/bin/python
1142+## encoding: utf-8
1143+#
1144+# Copyright (c) 2008 Adeodato Simó (dato@net.com.org.es)
1145+# Licensed under the terms of the MIT license.
1146+
1147+"""Create a report of packages that are out-of-date in each architecture.
1148+
1149+It expects a single "directory" argument, that should be a britney directory
1150+for a distribution, i.e. containing Packages_<arch> files and Sources.
1151+"""
1152+
1153+import os
1154+import re
1155+import sys
1156+import glob
1157+
1158+import apt_pkg
1159+apt_pkg.init()
1160+
1161+##
1162+
1163+def main():
1164+ if len(sys.argv) != 2:
1165+ print >>sys.stderr, 'Usage: %s <directory>'
1166+ sys.exit(1)
1167+ else:
1168+ directory = sys.argv[1]
1169+
1170+ pkgfiles = glob.glob(os.path.join(directory, 'Packages_*'))
1171+ versions = get_src_versions(os.path.join(directory, 'Sources'))
1172+
1173+ ood = {} # { arch1: { srcpk1: (oldver, [binpkg1, binpkg2, ...]), ... }, ... }
1174+
1175+ for pkgfile in pkgfiles:
1176+ arch = re.sub(r'^.*/Packages_', '', pkgfile)
1177+ try:
1178+ parser = apt_pkg.TagFile(file(pkgfile))
1179+ step = parser.step
1180+ get_section = parser.section
1181+ get_field = parser.section.get
1182+ except AttributeError, e:
1183+ parser = apt_pkg.ParseTagFile(file(pkgfile))
1184+ step = parser.Step
1185+ get_section = parser.Section
1186+ get_field = parser.Section.get
1187+ d = ood[arch] = {}
1188+
1189+ while step():
1190+ pkg = get_section['Package']
1191+ src = get_field('Source') or pkg
1192+
1193+ if ' ' in src:
1194+ m = re.match(r'(\S+) \((\S+)\)$', src)
1195+ src = m.group(1)
1196+ ver = m.group(2)
1197+ else:
1198+ ver = re.sub(r'\+b\d+$', '', get_section['Version'])
1199+
1200+ try:
1201+ distver = versions[src]
1202+ except KeyError:
1203+ pass # faux package
1204+ else:
1205+ if ver != distver:
1206+ d.setdefault(src, (ver, []))[1].append(pkg)
1207+
1208+ arches = sorted(ood.keys())
1209+
1210+ for arch in arches:
1211+ print '* %s' % (arch,)
1212+ for src, (oldver, binpkgs) in sorted(ood[arch].iteritems()):
1213+ # do not print binpkgs, I think it clutters the view too much
1214+ print ' %s (%s)' % (src, oldver)
1215+ print
1216+
1217+ print '* summary'
1218+ print '\n'.join(map(lambda x: '%4d %s' % (len(ood[x]), x), arches))
1219+
1220+##
1221+
1222+def get_src_versions(sources_file):
1223+ """Return a dict { srcname: version, ... }."""
1224+ mydict = {}
1225+ try:
1226+ parser = apt_pkg.TagFile(file(sources_file))
1227+
1228+ while parser.step():
1229+ mydict[parser.section['Package']] = parser.section['Version']
1230+ except AttributeError, e:
1231+ parser = apt_pkg.ParseTagFile(file(sources_file))
1232+
1233+ while parser.Step():
1234+ mydict[parser.Section['Package']] = parser.Section['Version']
1235+
1236+ return mydict
1237+
1238+##
1239+
1240+if __name__ == '__main__':
1241+ main()
1242
1243=== added file 'scripts/udeb-report'
1244--- scripts/udeb-report 1970-01-01 00:00:00 +0000
1245+++ scripts/udeb-report 2020-03-12 14:58:23 +0000
1246@@ -0,0 +1,49 @@
1247+#!/bin/sh
1248+
1249+# Generate a report with out-of-date udebs. Queries come from the
1250+# original "d-i" script by Jeroen van Wolffelaar. Modified not to emit
1251+# output for queries that return 0 rows by Adeodato Simó.
1252+
1253+# TODO(dato): rewrite these queries.
1254+
1255+export PAGER="cat"
1256+
1257+eval $(dak admin config db-shell)
1258+
1259+##
1260+
1261+maybe_print () {
1262+ if ! echo "$2" | grep -q -E '^\(0 rows\)$'; then
1263+ echo "$1"
1264+ echo "$2"
1265+ echo
1266+ fi
1267+}
1268+
1269+maybe_print "udeb's in testing that don't (anymore) correspond to any testing source:" \
1270+"`psql -c \"select b.package, b.version, (SELECT arch_string from
1271+architecture where b.architecture=architecture.id) as arch, s.source from
1272+bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s
1273+on (b.source=s.id) WHERE ba.suite=4 AND s.id NOT IN (SELECT source from
1274+src_associations WHERE suite=4) AND b.type = 'udeb' ORDER BY s.source,
1275+b.package, b.architecture;\"`"
1276+
1277+maybe_print "udeb's in unstable that should be in testing too:" \
1278+"`psql -c \"select b.package, b.version, (SELECT arch_string from
1279+architecture where b.architecture=architecture.id) as arch, s.source from
1280+bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s
1281+on (b.source=s.id) WHERE ba.suite=5 AND NOT EXISTS (SELECT 1 FROM
1282+bin_associations ba2 WHERE ba2.suite=4 AND ba2.bin=ba.bin) AND s.id IN (SELECT
1283+source from src_associations WHERE suite=4) AND b.type = 'udeb' AND
1284+b.architecture IN (SELECT architecture from suite_architectures where suite = 4)
1285+ORDER BY s.source, b.package, b.architecture;\"`"
1286+
1287+maybe_print "udeb's in t-p-u that should be in testing too:" \
1288+"`psql -c \"select b.package, b.version, (SELECT arch_string from
1289+architecture where b.architecture=architecture.id) as arch, s.source from
1290+bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s
1291+on (b.source=s.id) WHERE ba.suite=3 AND NOT EXISTS (SELECT 1 FROM
1292+bin_associations ba2 WHERE ba2.suite=4 AND ba2.bin=ba.bin) AND s.id IN (SELECT
1293+source from src_associations WHERE suite=4) AND b.type = 'udeb' AND
1294+b.architecture IN (SELECT architecture from suite_architectures where suite = 4)
1295+ORDER BY s.source, b.package, b.architecture;\"`"
1296
1297=== added directory 'update_out'
1298=== added file 'update_out/.gitignore'
1299--- update_out/.gitignore 1970-01-01 00:00:00 +0000
1300+++ update_out/.gitignore 2020-03-12 14:58:23 +0000
1301@@ -0,0 +1,6 @@
1302+*.o
1303+*.so
1304+/oldstuff
1305+/Makefile.dep
1306+/update.EXCUSES_py
1307+/update.OUTPUT_py
1308
1309=== added file 'update_out/Makefile'
1310--- update_out/Makefile 1970-01-01 00:00:00 +0000
1311+++ update_out/Makefile 2020-03-12 14:58:23 +0000
1312@@ -0,0 +1,33 @@
1313+
1314+CC = gcc
1315+CXX = g++
1316+CFLAGS = -fPIC -Wall -W -O2 -DNDEBUG -DMDEBUG0 -g -p # -DDIAGNOSE
1317+CXXFLAGS = $(CFLAGS)
1318+
1319+all : britneymodule.so # libajdpkg.a aptvercmp checklib freelist
1320+
1321+clean :
1322+ rm -f *.so *.o *~ Makefile.dep gmon.out
1323+ rm -f freelist aptvercmp checklib libajdpkg.a
1324+
1325+checklib : checklib.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
1326+ $(CC) $(CFLAGS) -o checklib $^ -lapt-pkg # -lccmalloc -ldl
1327+
1328+aptvercmp : dpkg-lib.cpp
1329+ $(CXX) $(CFLAGS) -DTESTBIN -o aptvercmp dpkg-lib.cpp -lapt-pkg
1330+
1331+freelist : freelist.c assert.o
1332+ $(CC) $(CFLAGS) -DTESTBIN -o $@ $^
1333+
1334+#libajdpkg.a : dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
1335+# ar rv $@ $^
1336+# ranlib $@
1337+
1338+britneymodule.so : britney-py.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
1339+ $(CXX) -shared -o britneymodule.so $^ -lapt-pkg
1340+
1341+Makefile.dep :
1342+ @gcc -MM *.c *.cpp > Makefile.dep
1343+ @echo Makefile.dep : Makefile *.c *.h >> Makefile.dep
1344+
1345+-include Makefile.dep
1346
1347=== added file 'update_out/README'
1348--- update_out/README 1970-01-01 00:00:00 +0000
1349+++ update_out/README 2020-03-12 14:58:23 +0000
1350@@ -0,0 +1,32 @@
1351+
1352+BUILDING
1353+========
1354+
1355+Install libapt-pkg-dev
1356+
1357+testing/ $ make
1358+testing/ $ mkdir old cur out
1359+testing/ $ cd testing
1360+testing/testing/ $ perl Makefile.PL
1361+testing/testing/ $ make
1362+
1363+Add old and new packages files into old and cur, respectively.
1364+
1365+testing/ $ ./checklib i386 alpha
1366+
1367+Will generate some test stuff in out/
1368+
1369+TODO
1370+====
1371+
1372+Need some way of actually updating archives.
1373+Need some way of judging differences between Packages files.
1374+ (so I can see what hasn't been updated and work out why;
1375+ so I can check that Packages.gz matches dpkg-scanpackages output)
1376+Need some way of automatically explaining why packages aren't upgraded.
1377+ (shouldn't be hard?)
1378+
1379+BUGS
1380+====
1381+
1382+out/ directory must exist for checklib, or segfault
1383
1384=== added file 'update_out/assert.c'
1385--- update_out/assert.c 1970-01-01 00:00:00 +0000
1386+++ update_out/assert.c 2020-03-12 14:58:23 +0000
1387@@ -0,0 +1,11 @@
1388+#include <stdio.h>
1389+#include <stdlib.h>
1390+
1391+int _myassertbug(int line, char *file, char *err) {
1392+ fprintf(stderr, "Assertion failed: %s:%d: %s\n", file, line, err);
1393+ fprintf(stderr, "I HATE YOU!!!");
1394+ ((void(*)())0)();
1395+ abort();
1396+ return 0;
1397+}
1398+
1399
1400=== added file 'update_out/britney-py.c'
1401--- update_out/britney-py.c 1970-01-01 00:00:00 +0000
1402+++ update_out/britney-py.c 2020-03-12 14:58:23 +0000
1403@@ -0,0 +1,871 @@
1404+#include <python2.7/Python.h>
1405+
1406+#include "dpkg.h"
1407+
1408+#define MAKE_PY_LIST(L,S,E,I,V) \
1409+ do { \
1410+ L = PyList_New(0); \
1411+ if (!L) break; \
1412+ for (S; E; I) { \
1413+ PyObject *EL; \
1414+ EL = Py_BuildValue V; \
1415+ if (!EL) { \
1416+ Py_DECREF(L); \
1417+ L = NULL; \
1418+ break; \
1419+ } \
1420+ PyList_Append(L, EL); \
1421+ Py_DECREF(EL); \
1422+ } \
1423+ if (L) PyList_Sort(L); \
1424+ } while(0)
1425+
1426+/**************************************************************************
1427+ * britney.Packages -- dpkg_packages wrapper
1428+ *******************************************/
1429+
1430+typedef enum { DONTFREE, FREE } dpkgpackages_freeme;
1431+typedef struct {
1432+ PyObject_HEAD
1433+ dpkg_packages *pkgs;
1434+ PyObject *ref; /* object packages are "in" */
1435+ dpkgpackages_freeme freeme; /* free pkgs when deallocing? */
1436+} dpkgpackages;
1437+
1438+staticforward PyTypeObject Packages_Type;
1439+
1440+static PyObject *dpkgpackages_new(dpkg_packages *pkgs,
1441+ dpkgpackages_freeme freeme, PyObject *ref)
1442+{
1443+ dpkgpackages *res;
1444+
1445+ res = PyObject_NEW(dpkgpackages, &Packages_Type);
1446+ if (res == NULL) return NULL;
1447+
1448+ res->pkgs = pkgs;
1449+ res->ref = ref; Py_INCREF(res->ref);
1450+ res->freeme = freeme;
1451+
1452+ return (PyObject *) res;
1453+}
1454+
1455+static void dpkgpackages_dealloc(dpkgpackages *self) {
1456+ if (self->freeme == FREE) free_packages(self->pkgs);
1457+ Py_XDECREF(self->ref);
1458+ self->pkgs = NULL;
1459+ self->ref = NULL;
1460+ PyObject_DEL(self);
1461+}
1462+
1463+
1464+static dpkg_collected_package *dpkgpackages_lookuppkg(dpkgpackages *self,
1465+ char *pkgname)
1466+{
1467+ dpkg_collected_package *cpkg = NULL;
1468+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1469+ if (!cpkg) {
1470+ PyErr_SetString(PyExc_ValueError, "Not a valid package");
1471+ }
1472+ return cpkg;
1473+}
1474+
1475+static PyObject *dpkgpackages_ispresent(dpkgpackages *self, PyObject *args) {
1476+ dpkg_collected_package *cpkg;
1477+ char *pkgname;
1478+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1479+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1480+ return cpkg ? Py_BuildValue("i", 1) : Py_BuildValue("i", 0);
1481+}
1482+
1483+static PyObject *dpkgpackages_getversion(dpkgpackages *self, PyObject *args) {
1484+ dpkg_collected_package *cpkg;
1485+ char *pkgname;
1486+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1487+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1488+ if (cpkg) return Py_BuildValue("s", cpkg->pkg->version);
1489+ else return Py_BuildValue("");
1490+}
1491+static PyObject *dpkgpackages_getsource(dpkgpackages *self, PyObject *args) {
1492+ dpkg_collected_package *cpkg;
1493+ char *pkgname;
1494+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1495+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1496+ if (cpkg) return Py_BuildValue("s", cpkg->pkg->source);
1497+ else return Py_BuildValue("");
1498+}
1499+static PyObject *dpkgpackages_getsourcever(dpkgpackages *self, PyObject *args) {
1500+ dpkg_collected_package *cpkg;
1501+ char *pkgname;
1502+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1503+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1504+ if (cpkg) return Py_BuildValue("s", cpkg->pkg->source_ver);
1505+ else return Py_BuildValue("");
1506+}
1507+static PyObject *dpkgpackages_isarchall(dpkgpackages *self, PyObject *args) {
1508+ dpkg_collected_package *cpkg;
1509+ char *pkgname;
1510+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1511+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1512+ if (cpkg) return Py_BuildValue("i", cpkg->pkg->arch_all);
1513+ else return Py_BuildValue("");
1514+}
1515+static PyObject *dpkgpackages_isntarchall(dpkgpackages *self, PyObject *args) {
1516+ dpkg_collected_package *cpkg;
1517+ char *pkgname;
1518+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1519+ cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
1520+ if (cpkg) return Py_BuildValue("i", !cpkg->pkg->arch_all);
1521+ else return Py_BuildValue("");
1522+}
1523+static PyObject *dpkgpackages_getfield(dpkgpackages *self, PyObject *args) {
1524+ char *field;
1525+ char *pkgname;
1526+ int i;
1527+ dpkg_collected_package *cpkg;
1528+ dpkg_paragraph *para;
1529+ if (!PyArg_ParseTuple(args, "ss", &pkgname, &field)) return NULL;
1530+ cpkg = dpkgpackages_lookuppkg(self, pkgname);
1531+ if (!cpkg) return NULL;
1532+ para = cpkg->pkg->details;
1533+ for (i = 0; i < para->n_entries; i++) {
1534+ if (strcasecmp(para->entry[i].name, field) == 0) {
1535+ return Py_BuildValue("s", para->entry[i].value);
1536+ }
1537+ }
1538+ return Py_BuildValue("");
1539+}
1540+static PyObject *dpkgpackages_isinstallable(dpkgpackages *self, PyObject *args)
1541+{
1542+ char *pkgname;
1543+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1544+ if (checkinstallable2(self->pkgs, pkgname)) {
1545+ return Py_BuildValue("i", 1);
1546+ } else {
1547+ return Py_BuildValue("");
1548+ }
1549+}
1550+static PyObject *dpkgpackages_isuninstallable(dpkgpackages *self,
1551+ PyObject *args)
1552+{
1553+ char *pkgname;
1554+ if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
1555+ if (!checkinstallable2(self->pkgs, pkgname)) {
1556+ return Py_BuildValue("i", 1);
1557+ } else {
1558+ return Py_BuildValue("");
1559+ }
1560+}
1561+static PyObject *dpkgpackages_unsatdeps(dpkgpackages *self, PyObject *args) {
1562+ /* arguments are:
1563+ * testingpkgs[arch].unsatisfiable_deps(unstablepkgs[arch], "netbase", "Depends")
1564+ * exciting, huh?
1565+ */
1566+
1567+ dpkgpackages *pkgpkgs;
1568+ char *pkgname, *fieldname;
1569+ dpkg_collected_package *cpkg;
1570+ int fieldidx;
1571+ int buflen = 100;
1572+ char *buf = malloc(buflen);
1573+ const char *fields[] = { "Pre-Depends", "Depends", "Recommends",
1574+ "Suggests", NULL };
1575+ satisfieddeplist *unsatdeps, *dl;
1576+ PyObject *res = Py_BuildValue("[]");
1577+
1578+ if (!PyArg_ParseTuple(args, "O!ss", &Packages_Type, &pkgpkgs, &pkgname, &fieldname)) return NULL;
1579+
1580+ cpkg = lookup_packagetbl(pkgpkgs->pkgs->packages, pkgname);
1581+ if (!cpkg) {
1582+ PyErr_SetString(PyExc_ValueError, "Not a valid package");
1583+ return NULL;
1584+ }
1585+
1586+ for (fieldidx = 0; fields[fieldidx]; fieldidx++) {
1587+ if (strcmp(fields[fieldidx], fieldname) == 0) break;
1588+ }
1589+ if (!fields[fieldidx]) {
1590+ PyErr_SetString(PyExc_ValueError, "Not a valid dependency field");
1591+ return NULL;
1592+ }
1593+
1594+ unsatdeps = checkunsatisfiabledeps(self->pkgs,
1595+ cpkg->pkg->depends[fieldidx]);
1596+ for (dl = unsatdeps; dl != NULL; dl = dl->next) {
1597+ int len;
1598+ packagelist *it;
1599+ PyObject *pkglist;
1600+ deplist *depl;
1601+ dependency *dep;
1602+
1603+ len = 0;
1604+ buf[0] = '\0';
1605+ for (depl = dl->value->depl; depl; depl = depl->next) {
1606+ dep = depl->value;
1607+ len += strlen(dep->package) + 4;
1608+ /* 4 = strlen(" | ") + 1 */
1609+ if (dep->op != dr_NOOP) {
1610+ len += strlen(dep->version) + 6;
1611+ /* 6 = strlen(" (>= )") */
1612+ }
1613+ if (len >= buflen) {
1614+ char *newbuf;
1615+ newbuf = realloc(buf, len + 100);
1616+ if (newbuf == NULL) {
1617+ free_satisfieddeplist(unsatdeps);
1618+ free(buf);
1619+ Py_DECREF(res);
1620+ PyErr_SetFromErrno(PyExc_MemoryError);
1621+ return NULL;
1622+ }
1623+ buf = newbuf;
1624+ buflen = len + 100;
1625+ }
1626+ if (buf[0] != '\0') strcat(buf, " | ");
1627+ strcat(buf, dep->package);
1628+ if (dep->op != dr_NOOP) {
1629+ sprintf(buf + strlen(buf), " (%s %s)",
1630+ dependency_relation_sym[dep->op],
1631+ dep->version);
1632+ }
1633+ }
1634+
1635+ MAKE_PY_LIST(pkglist, it = dl->value->pkgs, it, it = it->next,
1636+ ("s", it->value->package)
1637+ );
1638+
1639+ {
1640+ PyObject *depel = Py_BuildValue("(sN)", buf, pkglist);
1641+ PyList_Append(res, depel);
1642+ Py_DECREF(depel);
1643+ }
1644+ }
1645+
1646+ free_satisfieddeplist(unsatdeps);
1647+ free(buf);
1648+
1649+ return res;
1650+}
1651+
1652+static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) {
1653+ static struct PyMethodDef dpkgsources_methods[] = {
1654+ { "is_present", (binaryfunc) dpkgpackages_ispresent,
1655+ METH_VARARGS, NULL },
1656+ { "get_version", (binaryfunc) dpkgpackages_getversion,
1657+ METH_VARARGS, NULL },
1658+ { "get_source", (binaryfunc) dpkgpackages_getsource,
1659+ METH_VARARGS, NULL },
1660+ { "get_sourcever", (binaryfunc) dpkgpackages_getsourcever,
1661+ METH_VARARGS, NULL },
1662+ { "is_arch_all", (binaryfunc) dpkgpackages_isarchall,
1663+ METH_VARARGS, NULL },
1664+ { "isnt_arch_all", (binaryfunc) dpkgpackages_isntarchall,
1665+ METH_VARARGS, NULL },
1666+ { "get_field", (binaryfunc) dpkgpackages_getfield,
1667+ METH_VARARGS, NULL },
1668+ { "is_installable", (binaryfunc) dpkgpackages_isinstallable,
1669+ METH_VARARGS, NULL },
1670+ { "is_uninstallable", (binaryfunc)dpkgpackages_isuninstallable,
1671+ METH_VARARGS, NULL },
1672+ { "unsatisfiable_deps", (binaryfunc) dpkgpackages_unsatdeps,
1673+ METH_VARARGS, NULL },
1674+ { NULL, NULL, 0, NULL }
1675+ };
1676+
1677+ if (strcmp(name, "packages") == 0) {
1678+ PyObject *packages;
1679+ packagetbl_iter it;
1680+ MAKE_PY_LIST(packages,
1681+ it = first_packagetbl(self->pkgs->packages),
1682+ !done_packagetbl(it), it = next_packagetbl(it),
1683+ ("s", it.k)
1684+ );
1685+ return packages;
1686+ }
1687+
1688+ return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name);
1689+}
1690+
1691+static PyTypeObject Packages_Type = {
1692+ PyObject_HEAD_INIT(&PyType_Type)
1693+
1694+ 0, /* ob_size (0) */
1695+ "Packages", /* type name */
1696+ sizeof(dpkgpackages), /* basicsize */
1697+ 0, /* itemsize (0) */
1698+
1699+ (destructor) dpkgpackages_dealloc,
1700+ (printfunc) 0,
1701+ (getattrfunc) dpkgpackages_getattr,
1702+ (setattrfunc) 0,
1703+ (cmpfunc) 0,
1704+ (reprfunc) 0,
1705+
1706+ 0, /* number methods */
1707+ 0, /* sequence methods */
1708+ 0, /* mapping methods */
1709+
1710+ (hashfunc) 0, /* dict[x] ?? */
1711+ (ternaryfunc) 0, /* x() */
1712+ (reprfunc) 0 /* str(x) */
1713+};
1714+
1715+/**************************************************************************
1716+ * britney.Sources -- dpkg_sources wrapper
1717+ *****************************************/
1718+
1719+typedef struct {
1720+ PyObject_HEAD
1721+ dpkg_sources *srcs;
1722+} dpkgsources;
1723+
1724+staticforward PyTypeObject Sources_Type;
1725+
1726+static PyObject *dpkgsources_new(PyObject *self, PyObject *args) {
1727+ dpkgsources *res = NULL;
1728+ char *dir;
1729+ PyObject *arches;
1730+ char **archesStr = NULL;
1731+ int i, count;
1732+
1733+ (void)self; /* unused */
1734+
1735+ if (!PyArg_ParseTuple(args, "sO!", &dir, &PyList_Type, &arches)) {
1736+ goto end;
1737+ }
1738+
1739+ count = PyList_Size(arches);
1740+ if (count <= 0) {
1741+ PyErr_SetString(PyExc_TypeError, "No architectures specified");
1742+ goto end;
1743+ }
1744+
1745+ archesStr = malloc(sizeof(char *) * count);
1746+ if (!archesStr) {
1747+ PyErr_SetFromErrno(PyExc_MemoryError);
1748+ goto end;
1749+ }
1750+
1751+ for (i = 0; i < count; i++) {
1752+ PyObject *arch = PyList_GetItem(arches, i);
1753+ if (!PyString_Check(arch)) {
1754+ goto end;
1755+ }
1756+ archesStr[i] = PyString_AsString(arch);
1757+ }
1758+
1759+ res = PyObject_NEW(dpkgsources, &Sources_Type);
1760+ if (res == NULL) goto end;
1761+
1762+ res->srcs = read_directory(dir, count, archesStr);
1763+ if (!res->srcs) {
1764+ Py_DECREF(res);
1765+ res = NULL;
1766+ goto end;
1767+ }
1768+
1769+end:
1770+ if (archesStr) free(archesStr);
1771+ return (PyObject *) res;
1772+}
1773+
1774+static void dpkgsources_dealloc(dpkgsources *self) {
1775+ free_sources(self->srcs);
1776+ self->srcs = NULL;
1777+ PyObject_DEL(self);
1778+}
1779+
1780+static PyObject *dpkgsources_packages(dpkgsources *self, PyObject *args)
1781+{
1782+ char *arch;
1783+ dpkg_packages *pkgs;
1784+ if (!PyArg_ParseTuple(args, "s", &arch)) return NULL;
1785+ pkgs = get_architecture(self->srcs, arch);
1786+ return dpkgpackages_new(pkgs, FREE, (PyObject *) self);
1787+}
1788+
1789+static PyObject *dpkgsources_isfake(dpkgsources *self, PyObject *args) {
1790+ char *srcname;
1791+ dpkg_source *src;
1792+
1793+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
1794+ src = lookup_sourcetbl(self->srcs->sources, srcname);
1795+ if (src) return Py_BuildValue("i", src->fake);
1796+ else return Py_BuildValue("");
1797+}
1798+
1799+static PyObject *dpkgsources_getversion(dpkgsources *self, PyObject *args) {
1800+ char *srcname;
1801+ dpkg_source *src;
1802+
1803+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
1804+ src = lookup_sourcetbl(self->srcs->sources, srcname);
1805+ if (src) return Py_BuildValue("s", src->version);
1806+ else return Py_BuildValue("");
1807+}
1808+
1809+static PyObject *dpkgsources_getfield(dpkgsources *self, PyObject *args) {
1810+ char *srcname, *field;
1811+ dpkg_source *src;
1812+ int i;
1813+ dpkg_paragraph *para;
1814+
1815+ if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL;
1816+ src = lookup_sourcetbl(self->srcs->sources, srcname);
1817+ if (!src) {
1818+ PyErr_SetString(PyExc_ValueError, "Not a valid source package");
1819+ return NULL;
1820+ }
1821+ para = src->details;
1822+ if (para) {
1823+ for (i = 0; i < para->n_entries; i++) {
1824+ if (strcasecmp(para->entry[i].name, field) == 0) {
1825+ return Py_BuildValue("s", para->entry[i].value);
1826+ }
1827+ }
1828+ }
1829+ return Py_BuildValue("");
1830+}
1831+
1832+static PyObject *dpkgsources_ispresent(dpkgsources *self, PyObject *args) {
1833+ char *srcname;
1834+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
1835+ if (lookup_sourcetbl(self->srcs->sources, srcname)) {
1836+ return Py_BuildValue("i", 1);
1837+ } else {
1838+ return Py_BuildValue("i", 0);
1839+ }
1840+}
1841+
1842+static PyObject *dpkgsources_binaries(dpkgsources *self, PyObject *args) {
1843+ char *srcname, *arch;
1844+ int archnum;
1845+ dpkg_source *src;
1846+ PyObject *res;
1847+ ownedpackagelist *p;
1848+
1849+ if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL;
1850+
1851+ for (archnum = 0; archnum < self->srcs->n_arches; archnum++) {
1852+ if (strcmp(arch, self->srcs->archname[archnum]) == 0) break;
1853+ }
1854+ if (archnum == self->srcs->n_arches) {
1855+ PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
1856+ return NULL;
1857+ }
1858+
1859+ src = lookup_sourcetbl(self->srcs->sources, srcname);
1860+ if (src == NULL) {
1861+ PyErr_SetString(PyExc_ValueError, "Not a valid source package");
1862+ return NULL;
1863+ }
1864+
1865+ MAKE_PY_LIST(res, p = src->packages[archnum], p, p = p->next,
1866+ ("s", p->value->package)
1867+ );
1868+ return res;
1869+}
1870+
1871+static PyObject *dpkgsources_getattr(dpkgsources *self, char *name) {
1872+ static struct PyMethodDef dpkgsources_methods[] = {
1873+ { "Packages", (binaryfunc) dpkgsources_packages,
1874+ METH_VARARGS, NULL },
1875+ { "is_fake", (binaryfunc) dpkgsources_isfake,
1876+ METH_VARARGS, NULL },
1877+ { "get_version", (binaryfunc) dpkgsources_getversion,
1878+ METH_VARARGS, NULL },
1879+ { "get_field", (binaryfunc) dpkgsources_getfield,
1880+ METH_VARARGS, NULL },
1881+ { "is_present", (binaryfunc) dpkgsources_ispresent,
1882+ METH_VARARGS, NULL },
1883+ { "binaries", (binaryfunc) dpkgsources_binaries,
1884+ METH_VARARGS, NULL },
1885+ { NULL, NULL, 0, NULL }
1886+ };
1887+
1888+ if (strcmp(name, "arches") == 0) {
1889+ PyObject *arches;
1890+ int i;
1891+ MAKE_PY_LIST(arches, i = 0, i < self->srcs->n_arches, i++,
1892+ ("s", self->srcs->archname[i])
1893+ );
1894+ return arches;
1895+ } else if (strcmp(name, "sources") == 0) {
1896+ PyObject *sources;
1897+ sourcetbl_iter it;
1898+ MAKE_PY_LIST(sources,
1899+ it = first_sourcetbl(self->srcs->sources),
1900+ !done_sourcetbl(it), it = next_sourcetbl(it),
1901+ ("s", it.k)
1902+ );
1903+ return sources;
1904+ }
1905+
1906+ return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name);
1907+}
1908+
1909+static PyTypeObject Sources_Type = {
1910+ PyObject_HEAD_INIT(&PyType_Type)
1911+
1912+ 0, /* ob_size (0) */
1913+ "Sources", /* type name */
1914+ sizeof(dpkgsources), /* basicsize */
1915+ 0, /* itemsize (0) */
1916+
1917+ (destructor) dpkgsources_dealloc,
1918+ (printfunc) 0,
1919+ (getattrfunc) dpkgsources_getattr,
1920+ (setattrfunc) 0,
1921+ (cmpfunc) 0,
1922+ (reprfunc) 0,
1923+
1924+ 0, /* number methods */
1925+ 0, /* sequence methods */
1926+ 0, /* mapping methods */
1927+
1928+ (hashfunc) 0, /* dict[x] ?? */
1929+ (ternaryfunc) 0, /* x() */
1930+ (reprfunc) 0 /* str(x) */
1931+};
1932+
1933+/**************************************************************************
1934+ * britney.SourcesNote -- dpkg_sourcesnote wrapper
1935+ *************************************************/
1936+
1937+typedef struct {
1938+ PyObject_HEAD
1939+ dpkg_sources_note *srcsn;
1940+ PyObject *refs; /* list of referenced dpkgsources */
1941+} dpkgsrcsn;
1942+
1943+staticforward PyTypeObject SourcesNote_Type;
1944+
1945+static PyObject *dpkgsrcsn_new(PyObject *self, PyObject *args) {
1946+ dpkgsrcsn *res = NULL;
1947+ PyObject *arches;
1948+ char **archesStr = NULL;
1949+ int i, count;
1950+
1951+ (void)self; /* unused */
1952+
1953+ if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &arches)) {
1954+ goto end;
1955+ }
1956+
1957+ count = PyList_Size(arches);
1958+ if (count <= 0) {
1959+ PyErr_SetString(PyExc_TypeError, "No architectures specified");
1960+ goto end;
1961+ }
1962+
1963+ archesStr = malloc(sizeof(char *) * count);
1964+ if (!archesStr) {
1965+ PyErr_SetFromErrno(PyExc_MemoryError);
1966+ goto end;
1967+ }
1968+
1969+ for (i = 0; i < count; i++) {
1970+ PyObject *arch = PyList_GetItem(arches, i);
1971+ if (!PyString_Check(arch)) {
1972+ goto end;
1973+ }
1974+ archesStr[i] = PyString_AsString(arch);
1975+ }
1976+
1977+ res = PyObject_NEW(dpkgsrcsn, &SourcesNote_Type);
1978+ if (res == NULL) goto end;
1979+
1980+ res->refs = PyList_New(0);
1981+ res->srcsn = new_sources_note(count, archesStr);
1982+ if (!res->refs || !res->srcsn) {
1983+ Py_DECREF(res);
1984+ res = NULL;
1985+ goto end;
1986+ }
1987+
1988+end:
1989+ if (archesStr) free(archesStr);
1990+ return (PyObject *) res;
1991+}
1992+
1993+static void dpkgsrcsn_dealloc(dpkgsrcsn *self) {
1994+ if (self->srcsn) free_sources_note(self->srcsn);
1995+ self->srcsn = NULL;
1996+ Py_XDECREF(self->refs);
1997+ self->refs = NULL;
1998+
1999+ PyObject_DEL(self);
2000+}
2001+
2002+static PyObject *dpkgsrcsn_removesource(dpkgsrcsn *self, PyObject *args) {
2003+ char *name;
2004+ if (!PyArg_ParseTuple(args, "s", &name)) return NULL;
2005+ remove_source(self->srcsn, name);
2006+ return Py_BuildValue("");
2007+}
2008+static PyObject *dpkgsrcsn_upgradesource(dpkgsrcsn *self, PyObject *args) {
2009+ char *name;
2010+ dpkgsources *srcs;
2011+ dpkg_source *src;
2012+ if (!PyArg_ParseTuple(args, "O!s", &Sources_Type, &srcs, &name))
2013+ return NULL;
2014+ src = lookup_sourcetbl(srcs->srcs->sources, name);
2015+ if (!src) {
2016+ PyErr_SetString(PyExc_ValueError, "Source does not exist");
2017+ return NULL;
2018+ }
2019+ if (!PySequence_In(self->refs, (PyObject *)srcs))
2020+ PyList_Append(self->refs, (PyObject *)srcs);
2021+ upgrade_source(self->srcsn, src);
2022+ return Py_BuildValue("");
2023+}
2024+static PyObject *dpkgsrcsn_upgradearch(dpkgsrcsn *self, PyObject *args) {
2025+ char *name, *arch;
2026+ dpkgsources *srcs;
2027+ dpkg_source *src;
2028+ if (!PyArg_ParseTuple(args, "O!ss", &Sources_Type, &srcs, &name, &arch))
2029+ return NULL;
2030+ src = lookup_sourcetbl(srcs->srcs->sources, name);
2031+ if (!src) {
2032+ PyErr_SetString(PyExc_ValueError, "Source does not exist");
2033+ return NULL;
2034+ }
2035+ if (!PySequence_In(self->refs, (PyObject *)srcs))
2036+ PyList_Append(self->refs, (PyObject *)srcs);
2037+ upgrade_arch(self->srcsn, src, arch);
2038+ return Py_BuildValue("");
2039+}
2040+
2041+static PyObject *dpkgsrcsn_undochange(dpkgsrcsn *self, PyObject *args) {
2042+ if (!PyArg_ParseTuple(args, "")) return NULL;
2043+ undo_change(self->srcsn);
2044+ return Py_BuildValue("");
2045+}
2046+
2047+static PyObject *dpkgsrcsn_commitchanges(dpkgsrcsn *self, PyObject *args) {
2048+ if (!PyArg_ParseTuple(args, "")) return NULL;
2049+ commit_changes(self->srcsn);
2050+ return Py_BuildValue("");
2051+}
2052+
2053+static PyObject *dpkgsrcsn_writenotes(dpkgsrcsn *self, PyObject *args) {
2054+ char *dir;
2055+ if (!PyArg_ParseTuple(args, "s", &dir)) return NULL;
2056+ write_notes(dir, self->srcsn);
2057+ return Py_BuildValue("");
2058+}
2059+
2060+static PyObject *dpkgsrcsn_packages(dpkgsrcsn *self, PyObject *args) {
2061+ char *arch;
2062+ int archnum;
2063+ if (!PyArg_ParseTuple(args, "s", &arch)) return NULL;
2064+ for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) {
2065+ if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break;
2066+ }
2067+ if (archnum == self->srcsn->n_arches) {
2068+ PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
2069+ return NULL;
2070+ }
2071+ return dpkgpackages_new(self->srcsn->pkgs[archnum], DONTFREE,
2072+ (PyObject *) self);
2073+}
2074+
2075+static PyObject *dpkgsrcsn_getversion(dpkgsrcsn *self, PyObject *args) {
2076+ char *srcname;
2077+ dpkg_source_note *srcn;
2078+
2079+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
2080+ srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
2081+ if (srcn) return Py_BuildValue("s", srcn->source->version);
2082+ else return Py_BuildValue("");
2083+}
2084+static PyObject *dpkgsrcsn_getfield(dpkgsrcsn *self, PyObject *args) {
2085+ char *srcname, *field;
2086+ dpkg_source_note *srcn;
2087+ int i;
2088+ dpkg_paragraph *para;
2089+
2090+ if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL;
2091+ srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
2092+ if (!srcn) {
2093+ PyErr_SetString(PyExc_ValueError, "Not a valid source package");
2094+ return NULL;
2095+ }
2096+ para = srcn->source->details;
2097+ if (para) {
2098+ for (i = 0; i < para->n_entries; i++) {
2099+ if (strcasecmp(para->entry[i].name, field) == 0) {
2100+ return Py_BuildValue("s", para->entry[i].value);
2101+ }
2102+ }
2103+ }
2104+ return Py_BuildValue("");
2105+}
2106+static PyObject *dpkgsrcsn_ispresent(dpkgsrcsn *self, PyObject *args) {
2107+ char *srcname;
2108+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
2109+ if (lookup_sourcenotetbl(self->srcsn->sources, srcname)) {
2110+ return Py_BuildValue("i", 1);
2111+ } else {
2112+ return Py_BuildValue("i", 0);
2113+ }
2114+}
2115+
2116+static PyObject *dpkgsrcsn_isfake(dpkgsrcsn *self, PyObject *args) {
2117+ char *srcname;
2118+ dpkg_source_note *srcn;
2119+
2120+ if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
2121+ srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
2122+ if (srcn) return Py_BuildValue("i", srcn->source->fake);
2123+ else return Py_BuildValue("");
2124+}
2125+
2126+static PyObject *dpkgsrcsn_binaries(dpkgsrcsn *self, PyObject *args) {
2127+ char *srcname, *arch;
2128+ int archnum;
2129+ dpkg_source_note *srcn;
2130+ PyObject *res;
2131+ packagelist *p;
2132+
2133+ if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL;
2134+
2135+ for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) {
2136+ if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break;
2137+ }
2138+ if (archnum == self->srcsn->n_arches) {
2139+ PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
2140+ return NULL;
2141+ }
2142+
2143+ srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
2144+ if (srcn == NULL) {
2145+ PyErr_SetString(PyExc_ValueError, "Not a valid source package");
2146+ return NULL;
2147+ }
2148+
2149+ MAKE_PY_LIST(res, p = srcn->binaries[archnum], p, p = p->next,
2150+ ("s", p->value->package)
2151+ );
2152+ return res;
2153+}
2154+
2155+static PyObject *dpkgsrcsn_getattr(dpkgsrcsn *self, char *name) {
2156+ static struct PyMethodDef dpkgsrcsn_methods[] = {
2157+ { "remove_source", (binaryfunc) dpkgsrcsn_removesource,
2158+ METH_VARARGS, NULL },
2159+ { "upgrade_source", (binaryfunc) dpkgsrcsn_upgradesource,
2160+ METH_VARARGS, NULL },
2161+ { "upgrade_arch", (binaryfunc) dpkgsrcsn_upgradearch,
2162+ METH_VARARGS, NULL },
2163+
2164+ { "undo_change", (binaryfunc) dpkgsrcsn_undochange,
2165+ METH_VARARGS, NULL },
2166+ { "commit_changes", (binaryfunc) dpkgsrcsn_commitchanges,
2167+ METH_VARARGS, NULL },
2168+
2169+ { "write_notes", (binaryfunc) dpkgsrcsn_writenotes,
2170+ METH_VARARGS, NULL },
2171+
2172+ { "Packages", (binaryfunc) dpkgsrcsn_packages,
2173+ METH_VARARGS, NULL },
2174+
2175+ { "get_version", (binaryfunc) dpkgsrcsn_getversion,
2176+ METH_VARARGS, NULL },
2177+ { "get_field", (binaryfunc) dpkgsrcsn_getfield,
2178+ METH_VARARGS, NULL },
2179+ { "is_present", (binaryfunc) dpkgsrcsn_ispresent,
2180+ METH_VARARGS, NULL },
2181+ { "is_fake", (binaryfunc) dpkgsrcsn_isfake,
2182+ METH_VARARGS, NULL },
2183+ { "binaries", (binaryfunc) dpkgsrcsn_binaries,
2184+ METH_VARARGS, NULL },
2185+ { NULL, NULL, 0, NULL }
2186+ };
2187+
2188+ if (strcmp(name, "arches") == 0) {
2189+ PyObject *arches;
2190+ int i;
2191+ MAKE_PY_LIST(arches, i = 0, i < self->srcsn->n_arches, i++,
2192+ ("s", self->srcsn->archname[i])
2193+ );
2194+ return arches;
2195+ } else if (strcmp(name, "sources") == 0) {
2196+ PyObject *sources;
2197+ sourcenotetbl_iter it;
2198+ MAKE_PY_LIST(sources,
2199+ it = first_sourcenotetbl(self->srcsn->sources),
2200+ !done_sourcenotetbl(it),
2201+ it = next_sourcenotetbl(it),
2202+ ("s", it.k)
2203+ );
2204+ return sources;
2205+ } else if (strcmp(name, "can_undo") == 0) {
2206+ if (can_undo(self->srcsn)) {
2207+ return Py_BuildValue("i", 1);
2208+ } else {
2209+ return Py_BuildValue("");
2210+ }
2211+ }
2212+
2213+ return Py_FindMethod(dpkgsrcsn_methods, (PyObject *)self, name);
2214+}
2215+
2216+static PyTypeObject SourcesNote_Type = {
2217+ PyObject_HEAD_INIT(&PyType_Type)
2218+
2219+ 0, /* ob_size (0) */
2220+ "SourcesNote", /* type name */
2221+ sizeof(dpkgsrcsn), /* basicsize */
2222+ 0, /* itemsize (0) */
2223+
2224+ (destructor) dpkgsrcsn_dealloc,
2225+ (printfunc) 0,
2226+ (getattrfunc) dpkgsrcsn_getattr,
2227+ (setattrfunc) 0,
2228+ (cmpfunc) 0,
2229+ (reprfunc) 0,
2230+
2231+ 0, /* number methods */
2232+ 0, /* sequence methods */
2233+ 0, /* mapping methods */
2234+
2235+ (hashfunc) 0, /* dict[x] ?? */
2236+ (ternaryfunc) 0, /* x() */
2237+ (reprfunc) 0 /* str(x) */
2238+};
2239+
2240+/**************************************************************************
2241+ * britney.versioncmp() -- apt version compare function
2242+ ******************************************************/
2243+
2244+static PyObject *apt_versioncmp(PyObject *self, PyObject *args) {
2245+ char *l, *r;
2246+ int res;
2247+
2248+ (void)self; /* unused */
2249+
2250+ if (!PyArg_ParseTuple(args, "ss", &l, &r)) {
2251+ return NULL;
2252+ }
2253+
2254+ res = versioncmp(l,r);
2255+ return Py_BuildValue("i", res);
2256+}
2257+
2258+/**************************************************************************
2259+ * module initialisation
2260+ ***********************/
2261+
2262+static PyMethodDef britneymethods[] = {
2263+ { "Sources", dpkgsources_new, METH_VARARGS, NULL },
2264+ { "SourcesNote", dpkgsrcsn_new, METH_VARARGS, NULL },
2265+
2266+ { "versioncmp", apt_versioncmp, METH_VARARGS, NULL },
2267+
2268+ { NULL, NULL, 0, NULL }
2269+};
2270+
2271+void initbritney(void) {
2272+ Py_InitModule("britney", britneymethods);
2273+}
2274+
2275
2276=== added file 'update_out/checklib.c'
2277--- update_out/checklib.c 1970-01-01 00:00:00 +0000
2278+++ update_out/checklib.c 2020-03-12 14:58:23 +0000
2279@@ -0,0 +1,185 @@
2280+#include <stdlib.h>
2281+#include <unistd.h>
2282+
2283+#include <assert.h>
2284+
2285+#include "dpkg.h"
2286+
2287+#if 0
2288+static void checknewsrc(sourcetbl *srcstbl, dpkg_source *cur, void *data) {
2289+ dpkg_sources *oldsrc = data;
2290+ dpkg_source *old;
2291+ old = lookup_sourcetbl(oldsrc->sources, cur->package);
2292+ if (old == NULL) {
2293+ printf("New: %s (%s)\n", cur->package, cur->version );
2294+ } else if (strcmp(old->version, cur->version) != 0) {
2295+ printf("Updated: %s (%s, was %s)\n",
2296+ cur->package, cur->version, old->version );
2297+ } else {
2298+ dpkg_source *src2;
2299+ src2 = remove_sourcetbl(srcstbl, cur->package);
2300+ assert(cur == src2);
2301+ free_source(cur);
2302+ }
2303+}
2304+
2305+static void checkoldsrc(sourcetbl *oldsrctbl, dpkg_source *old, void *data) {
2306+ dpkg_sources *src = data;
2307+ dpkg_source *cur;
2308+ (void)oldsrctbl;
2309+ cur = lookup_sourcetbl(src->sources, old->package);
2310+ if (cur == NULL) {
2311+ printf("Removed: %s (was %s)\n", old->package, old->version );
2312+ }
2313+}
2314+
2315+static void checkuptodate(sourcetbl *srctbl, dpkg_source *src, void *data) {
2316+ int i;
2317+ int remove;
2318+ ownedpackagelist **p;
2319+ dpkg_sources *srcs = data;
2320+
2321+ (void)srctbl;
2322+
2323+ remove = 0;
2324+ for (i = 0; i < srcs->n_arches; i++) {
2325+ p = &src->packages[i];
2326+ while(*p != NULL) {
2327+ if (strcmp((*p)->value->source_ver, src->version) != 0) {
2328+ if (cmpversions((*p)->value->source_ver, GT, src->version)) {
2329+ printf("ALERT: old source: ");
2330+ } else {
2331+ printf("WARN: out of date: ");
2332+ }
2333+ printf("%s %s: %s binary: %s %s from %s\n",
2334+ src->package, src->version, srcs->archname[i],
2335+ (*p)->value->package, (*p)->value->version,
2336+ (*p)->value->source_ver);
2337+ delete_ownedpackagelist(p);
2338+ } else {
2339+ p = &(*p)->next;
2340+ }
2341+ }
2342+ if (src->packages[i] == NULL) {
2343+ printf("%s missing uptodate binaries for %s\n",
2344+ src->package, srcs->archname[i]);
2345+ remove = 1;
2346+ }
2347+ }
2348+ if (remove) {
2349+ dpkg_source *src2;
2350+ src2 = remove_sourcetbl(srcs->sources, src->package);
2351+ assert(src == src2);
2352+ free_source(src);
2353+ }
2354+}
2355+#endif
2356+
2357+static void upgrade(sourcetbl *srctbl, dpkg_source *src, void *data) {
2358+ static int i = 0;
2359+ dpkg_sources_note *srcsn = data;
2360+ (void)srctbl;
2361+ i++; i %= 1000;
2362+ if (can_undo(srcsn)) {
2363+ if (i % 29 == 1 || i % 31 == 1 || i % 7 == 5)
2364+ undo_change(srcsn);
2365+ if (i % 33 == 0) commit_changes(srcsn);
2366+ }
2367+ upgrade_source(data, src);
2368+}
2369+
2370+static void checkpkgs(packagetbl *pkgtbl, dpkg_collected_package *cpkg,
2371+ void *data)
2372+{
2373+ dpkg_packages *pkgs = data;
2374+ assert(pkgs->packages == pkgtbl);
2375+ printf("Trying %s (%s, %s)\n", cpkg->pkg->package, cpkg->pkg->version, pkgs->arch);
2376+ if (!checkinstallable2(pkgs, cpkg->pkg->package)) {
2377+ printf("Package: %s (%s, %s) is uninstallable\n",
2378+ cpkg->pkg->package, cpkg->pkg->version, pkgs->arch);
2379+ }
2380+}
2381+
2382+void print_memblock_summary(void);
2383+
2384+int main(int argc, char **argv) {
2385+ dpkg_sources *src = NULL, *oldsrc = NULL;
2386+ dpkg_sources_note *srcsn;
2387+ dpkg_source *srcpkg;
2388+ dpkg_packages *pkgs[10];
2389+ int n_pkgs;
2390+ int i,j;
2391+ int reps;
2392+
2393+ if (argc < 3) {
2394+ printf("Usage: %s <reps> <arch>...\n", argv[0]);
2395+ exit(EXIT_FAILURE);
2396+ }
2397+
2398+ reps = atoi(argv[1]);
2399+ if (reps < 1) {
2400+ printf("reps must be >= 1\n");
2401+ exit(EXIT_FAILURE);
2402+ }
2403+
2404+ src = read_directory("cur", argc - 2, argv + 2);
2405+ oldsrc = read_directory("old", argc - 2, argv + 2);
2406+ srcsn = new_sources_note(argc - 2, argv + 2);
2407+
2408+ printf("FINISHED LOADING\n"); fflush(stdout); /* sleep(5); */
2409+
2410+#if 0
2411+ iterate_sourcetbl(oldsrc->sources, checkoldsrc, src);
2412+
2413+ printf("FIRST\n");
2414+ iterate_sourcetbl(src->sources, checkuptodate, src);
2415+ printf("SECOND\n");
2416+ iterate_sourcetbl(src->sources, checkuptodate, src);
2417+ printf("END\n");
2418+
2419+ iterate_sourcetbl(src->sources, checknewsrc, oldsrc);
2420+#endif
2421+
2422+ n_pkgs = 0;
2423+ for (i = argc - 1; i > 1; i--) {
2424+ pkgs[n_pkgs++] = get_architecture(oldsrc, argv[i]);
2425+ }
2426+ for (j = 0; j < reps; j++) {
2427+ printf("Round %d/%d starting...\n", j + 1, reps);
2428+ for (i = 0; i < n_pkgs; i++) {
2429+ iterate_packagetbl(pkgs[i]->packages, checkpkgs, pkgs[i]);
2430+ }
2431+ printf("Round %d ended.\n", j+1);
2432+ }
2433+ iterate_sourcetbl(src->sources, upgrade, srcsn);
2434+ iterate_sourcetbl(oldsrc->sources, upgrade, srcsn);
2435+
2436+ for (i = 0; i < n_pkgs; i++) {
2437+ free_packages(pkgs[i]);
2438+ }
2439+
2440+ srcpkg = lookup_sourcetbl(oldsrc->sources, "omirr");
2441+ if (srcpkg != NULL) {
2442+ printf("Adding old\n");
2443+ upgrade_source(srcsn, srcpkg);
2444+ }
2445+ srcpkg = lookup_sourcetbl(src->sources, "omirr");
2446+ if (srcpkg != NULL) {
2447+ printf("Adding cur\n");
2448+ upgrade_source(srcsn, srcpkg);
2449+ }
2450+
2451+ printf("FINISHED PROCESSING\n"); fflush(stdout); /* sleep(5); */
2452+
2453+ write_directory("out", oldsrc);
2454+
2455+ printf("FINISHED WRITING\n"); fflush(stdout); /* sleep(5); */
2456+
2457+ free_sources_note(srcsn);
2458+ free_sources(src);
2459+ free_sources(oldsrc);
2460+
2461+ DEBUG_ONLY( print_memblock_summary(); )
2462+
2463+ return 0;
2464+}
2465
2466=== added file 'update_out/dpkg-lib.cpp'
2467--- update_out/dpkg-lib.cpp 1970-01-01 00:00:00 +0000
2468+++ update_out/dpkg-lib.cpp 2020-03-12 14:58:23 +0000
2469@@ -0,0 +1,34 @@
2470+
2471+#include <apt-pkg/debversion.h>
2472+
2473+extern "C" {
2474+
2475+#include "dpkg.h"
2476+
2477+int versioncmp(char *left, char *right) {
2478+ return debVS.CmpVersion(left, right);
2479+}
2480+
2481+int cmpversions(char *left, int op, char *right) {
2482+ int i = debVS.CmpVersion(left, right);
2483+
2484+ switch(op) {
2485+ case dr_LT: return i < 0;
2486+ case dr_LTEQ: return i <= 0;
2487+ case dr_EQ: return i == 0;
2488+ case dr_GTEQ: return i >= 0;
2489+ case dr_GT: return i > 0;
2490+ }
2491+ return 0;
2492+}
2493+
2494+}
2495+
2496+#ifdef TESTBIN
2497+int main(int argc, char **argv) {
2498+ if (argc != 3) { printf("Usage: %s <ver> <ver>\n", argv[0]); exit(1); }
2499+
2500+ printf("%d\n", versioncmp(argv[1], argv[2]));
2501+ return 0;
2502+}
2503+#endif
2504
2505=== added file 'update_out/dpkg.c'
2506--- update_out/dpkg.c 1970-01-01 00:00:00 +0000
2507+++ update_out/dpkg.c 2020-03-12 14:58:23 +0000
2508@@ -0,0 +1,2013 @@
2509+#include <stdio.h>
2510+#include <stdlib.h>
2511+#include <string.h>
2512+#include <ctype.h>
2513+#include <errno.h>
2514+
2515+#include "dpkg.h"
2516+#include "memory.h"
2517+
2518+
2519+// enlarge this is britney has issues to parse packages
2520+#define SIZEOFHASHMAP 16
2521+
2522+#define insert_packagenamelist(x,y) insert_l_packagenamelist(x,y,__LINE__)
2523+
2524+static void free_dependency(dependency *dep);
2525+static void free_package(dpkg_package *pkg);
2526+static void free_collected_package(dpkg_collected_package *pkg);
2527+static dpkg_paragraph *read_paragraph( FILE *f );
2528+static dpkg_package *read_package( FILE *f );
2529+static collpackagelist **get_matching_low(collpackagelist **addto,
2530+ dpkg_packages *pkgs, dependency *dep, int line);
2531+static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line);
2532+static deplist *read_dep_and(char *buf);
2533+static deplistlist *read_dep_andor(char *buf);
2534+static ownedpackagenamelist *read_packagenames(char *buf);
2535+static dpkg_sources *read_sources_file(char *filename, int n_arches);
2536+static dpkg_source *new_source(dpkg_sources *owner);
2537+static dpkg_source *read_source(FILE *f, dpkg_sources *owner);
2538+static deplist *read_deplist(char **buf, char sep, char end);
2539+static dependency *read_dependency(char **buf, char *end);
2540+static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
2541+ char *version, dpkg_collected_package *cpkg);
2542+static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
2543+ dpkg_collected_package *cpkg);
2544+static char *read_packagename(char **buf, char *end);
2545+static char *read_until_char(char **buf, char *end);
2546+static void add_package(dpkg_packages *pkgs, dpkg_package *pkg);
2547+static void remove_package(dpkg_packages *pkgs, dpkg_collected_package *pkg);
2548+static dpkg_source_note *copy_source_note(dpkg_source_note *srcn);
2549+
2550+#if 0
2551+static inline void *bm(size_t s, int n) { void *res = block_malloc(s); fprintf(stderr, "ALLOCED: %d %p %lu\n", n, res, s); return res; }
2552+static inline void bf(void *p, size_t s, int n) { block_free(p,s); fprintf(stderr, "FREED: %d %p %lu\n", n, p, s); }
2553+
2554+#define block_malloc(s) bm(s,__LINE__)
2555+#define block_free(p,s) bf(p,s,__LINE__)
2556+#endif
2557+
2558+#define block_malloc(s) block_malloc2(s, __LINE__)
2559+
2560+static char *priorities[] = {
2561+ "required",
2562+ "important",
2563+ "standard",
2564+ "optional",
2565+ "extra",
2566+ NULL
2567+};
2568+
2569+static char *dependency_title[] = {
2570+ "Pre-Depends", "Depends", "Recommends", "Suggests", NULL
2571+};
2572+
2573+static int dependency_counts[] = { 1, 1, 0, 0 };
2574+
2575+char *dependency_relation_sym[] = {"*", "<<", "<=", "=", ">=", ">>"};
2576+
2577+#define SMB_SIZE (1<<22)
2578+struct stringmemblock {
2579+ struct stringmemblock *next;
2580+ size_t last;
2581+ char mem[SMB_SIZE];
2582+};
2583+static struct stringmemblock *stringmemory = NULL;
2584+static int stringmemorycount = 0;
2585+static const unsigned long stringmemblocksizekib = (unsigned long) sizeof(struct stringmemblock) / 1024;
2586+
2587+char *my_strdup(char *foo) {
2588+ struct stringmemblock *which;
2589+ size_t len;
2590+
2591+ if (!foo) return NULL;
2592+
2593+ len = strlen(foo) + 1;
2594+
2595+ if (len > SMB_SIZE) return strdup(foo);
2596+
2597+ for (which = stringmemory; which; which = which->next) {
2598+ if (SMB_SIZE - which->last > len + 1) {
2599+ break;
2600+ }
2601+ }
2602+ if (!which) {
2603+ which = malloc(sizeof(struct stringmemblock));
2604+ if (!which) return NULL;
2605+ MDEBUG1_ONLY(fprintf(stderr,
2606+ "ALLOC: string memblock %d (%lu KiB, %lu KiB total)\n",
2607+ stringmemorycount, stringmemblocksizekib,
2608+ (stringmemorycount+1) * stringmemblocksizekib));
2609+ memset(which->mem, 0, SMB_SIZE);
2610+ which->last = 0;
2611+ which->next = stringmemory;
2612+ stringmemory = which;
2613+ stringmemorycount++;
2614+ }
2615+ strcpy(&which->mem[which->last], foo);
2616+ foo = &which->mem[which->last];
2617+ which->last += len;
2618+ return foo;
2619+}
2620+
2621+char *my_rep_strdup(char *foo) {
2622+ static char *repeats[1000] = {0};
2623+ int i;
2624+
2625+ for (i = 0; i < 1000; i++) {
2626+ if (repeats[i] == NULL) {
2627+ DEBUG_ONLY(fprintf(stderr, "REPEAT NR %d\n", i+1); )
2628+ return repeats[i] = my_strdup(foo);
2629+ }
2630+ if (strcmp(repeats[i], foo) == 0) return repeats[i];
2631+ }
2632+
2633+ return my_strdup(foo);
2634+}
2635+
2636+/* DIE **/
2637+
2638+static void die(char *orig_msg) {
2639+ char *msg = my_strdup(orig_msg);
2640+ if (*msg && msg[strlen(msg)-1] == ':') {
2641+ msg[strlen(msg)-1] = '\0';
2642+ perror(msg);
2643+ } else {
2644+ printf("%s\n", msg);
2645+ }
2646+ abort();
2647+}
2648+
2649+/*************************************************************************
2650+ * Dpkg Control/Packages/etc Operations
2651+ */
2652+
2653+static dpkg_paragraph *read_paragraph( FILE *f ) {
2654+ dpkg_paragraph *result;
2655+ static int line_size = 0;
2656+ static char *line = NULL;
2657+ char *pch;
2658+
2659+ dpkg_entry *c_entry = NULL;
2660+ char *c_value = NULL;
2661+
2662+ if (line == NULL) {
2663+ line_size = 10;
2664+ line = malloc(line_size);
2665+ if (line == NULL) die("read_paragraph alloc 0:");
2666+ }
2667+
2668+ result = block_malloc( sizeof(dpkg_paragraph) );
2669+ if (result == NULL) die("read_paragraph alloc 1:");
2670+
2671+ result->n_entries = 0;
2672+ result->entry = NULL;
2673+ result->n_allocated = 0;
2674+
2675+ while(fgets(line, line_size, f)) {
2676+ while (!feof(f) && *line && line[strlen(line)-1] != '\n') {
2677+ line = realloc(line, line_size * 2);
2678+ if (!line) die("read_paragraph realloc:");
2679+ fgets(line + strlen(line), line_size, f);
2680+ line_size *= 2;
2681+ }
2682+
2683+ if (line[0] == '\n') break;
2684+
2685+ if (isspace(line[0])) {
2686+ if (c_value == NULL)
2687+ die("read_paragraph early spaces");
2688+
2689+ if (c_entry == NULL) {
2690+ /* no need to bother */
2691+ } else {
2692+ /* extend the line */
2693+ c_value = realloc(c_value, strlen(c_value) + strlen(line) + 1);
2694+ if (c_value == NULL)
2695+ die("read_paragraph realloc c_value:");
2696+
2697+ strcat(c_value, line);
2698+ }
2699+ } else {
2700+ if (c_entry) {
2701+ c_entry->value = my_strdup(c_value);
2702+ c_value[0] = '\0';
2703+ free(c_value);
2704+ c_value = NULL;
2705+ } else if (c_value) {
2706+ free(c_value);
2707+ c_value = NULL;
2708+ }
2709+ pch = strchr(line, ':');
2710+ if (pch == NULL) {
2711+ fprintf(stderr, "the line was: \"%s\"\n", line);
2712+ die("read_paragraph: no colon");
2713+ }
2714+
2715+ *pch = '\0';
2716+ while(isspace(*++pch));
2717+
2718+ if (strcmp(line, "Description") == 0) {
2719+ c_value = strdup(pch);
2720+ c_entry = NULL;
2721+ } else {
2722+ assert(result->n_entries <= result->n_allocated);
2723+ if (result->n_entries >= result->n_allocated) {
2724+ result->n_allocated += 10;
2725+ result->entry = realloc( result->entry,
2726+ sizeof(dpkg_entry)
2727+ * result->n_allocated);
2728+ if (result->entry == NULL)
2729+ die("read_paragraph realloc entry:");
2730+ }
2731+
2732+ c_entry = &result->entry[result->n_entries++];
2733+ c_entry->name = my_rep_strdup(line);
2734+ c_value = strdup(pch);
2735+ }
2736+ }
2737+ }
2738+
2739+ if (c_entry) {
2740+ c_entry->value = my_strdup(c_value);
2741+ c_value[0] = '\0';
2742+ free(c_value);
2743+ c_value = NULL;
2744+ }
2745+
2746+ if (result->n_entries == 0) {
2747+ if (result->entry) free(result->entry);
2748+ block_free(result, sizeof(dpkg_paragraph));
2749+ return NULL;
2750+ } else {
2751+ result->entry = realloc(result->entry,
2752+ sizeof(result->entry[0]) * result->n_entries);
2753+ result->n_allocated = result->n_entries;
2754+ }
2755+
2756+ return result;
2757+}
2758+
2759+static void write_paragraph(FILE *f, dpkg_paragraph *p) {
2760+ int i;
2761+
2762+ for (i = 0; i < p->n_entries; i++) {
2763+ fprintf(f, "%s: %s", p->entry[i].name, p->entry[i].value);
2764+ }
2765+ fprintf(f, "\n");
2766+}
2767+
2768+
2769+static void free_paragraph(dpkg_paragraph *p) {
2770+ int i;
2771+
2772+ if (p == NULL) return;
2773+
2774+ for (i = 0; i < p->n_entries; i++) {
2775+ /* block_free(p->entry[i].name); */
2776+ /* block_free(p->entry[i].value); */
2777+ }
2778+ free(p->entry);
2779+ block_free(p, sizeof(dpkg_paragraph));
2780+}
2781+
2782+/*************************************************************************
2783+ * Basic Package Operations
2784+ */
2785+
2786+static dpkg_package *new_package(void) {
2787+ dpkg_package *result;
2788+
2789+ result = block_malloc(sizeof(dpkg_package));
2790+ if (result == NULL) die("new_package alloc:");
2791+
2792+ result->package = NULL;
2793+ result->version = NULL;
2794+
2795+ result->priority = 0;
2796+ result->arch_all = 0;
2797+
2798+ result->source = NULL;
2799+ result->source_ver = NULL;
2800+
2801+ result->depends[0] = NULL;
2802+ result->depends[1] = NULL;
2803+ result->depends[2] = NULL;
2804+ result->depends[3] = NULL;
2805+
2806+ result->conflicts = NULL;
2807+
2808+ result->provides = NULL;
2809+ result->details = NULL;
2810+
2811+ return result;
2812+}
2813+
2814+static dpkg_collected_package *new_collected_package(dpkg_package *pkg) {
2815+ dpkg_collected_package *result;
2816+
2817+ result = block_malloc(sizeof(dpkg_collected_package));
2818+ if (result == NULL) die("new_collected_package alloc:");
2819+
2820+ result->pkg = pkg;
2821+
2822+ result->installed = 0;
2823+ result->conflicted = 0;
2824+
2825+ result->installable = UNKNOWN;
2826+ result->mayaffect = NULL;
2827+
2828+ return result;
2829+}
2830+
2831+static void free_collected_package(dpkg_collected_package *cpkg) {
2832+ if (cpkg == NULL) return;
2833+ cpkg->pkg = NULL;
2834+ free_packagenamelist(cpkg->mayaffect);
2835+ cpkg->mayaffect = NULL;
2836+ block_free(cpkg, sizeof(dpkg_collected_package));
2837+}
2838+
2839+static void free_package(dpkg_package *pkg) {
2840+ int i;
2841+ if (pkg == NULL) return;
2842+
2843+ /* block_free(pkg->package);
2844+ * block_free(pkg->version);
2845+ * block_free(pkg->source);
2846+ * block_free(pkg->source_ver); */
2847+
2848+ for (i = 0; i < 4; i++)
2849+ free_deplistlist(pkg->depends[i]);
2850+
2851+ free_deplist(pkg->conflicts);
2852+ free_ownedpackagenamelist(pkg->provides);
2853+
2854+ free_paragraph(pkg->details);
2855+
2856+ block_free(pkg, sizeof(dpkg_package));
2857+}
2858+
2859+static dpkg_package *read_package( FILE *f ) {
2860+ dpkg_package *result;
2861+ dpkg_paragraph *para;
2862+ dpkg_entry *e;
2863+ int i;
2864+
2865+ para = read_paragraph(f);
2866+ if (para == NULL) return NULL;
2867+
2868+ result = new_package();
2869+ result->details = para;
2870+
2871+ for (e = &para->entry[0]; e < &para->entry[para->n_entries]; e++) {
2872+ if (strcasecmp("Package", e->name) == 0) {
2873+ result->package = my_strdup(e->value);
2874+ if (result->package == NULL)
2875+ die("read_package my_strdup:");
2876+ result->package[strlen(result->package)-1] = '\0';
2877+ }
2878+
2879+ if (strcasecmp("Version", e->name) == 0) {
2880+ result->version = my_strdup(e->value);
2881+ if (result->version == NULL)
2882+ die("read_package my_strdup:");
2883+ result->version[strlen(result->version)-1] = '\0';
2884+ }
2885+
2886+ if (strcasecmp("Priority", e->name) == 0) {
2887+ int i;
2888+ for (i = 0; priorities[i] != NULL; i++) {
2889+ if (strcasecmp(priorities[i], e->value))
2890+ break;
2891+ }
2892+ result->priority = i;
2893+ if (priorities[i] == NULL) {
2894+ die("read_package: unknown priority");
2895+ }
2896+ }
2897+
2898+ if (strcasecmp("Architecture", e->name) == 0) {
2899+ if (strncasecmp(e->value, "all", 3) == 0) {
2900+ if (!e->value[3] || isspace(e->value[3])) {
2901+ result->arch_all = 1;
2902+ }
2903+ }
2904+ }
2905+
2906+ for (i = 0; dependency_title[i] != NULL; i++) {
2907+ if (strcasecmp(dependency_title[i], e->name) == 0) {
2908+ result->depends[i] = read_dep_andor(e->value);
2909+ }
2910+ }
2911+
2912+ /*
2913+ * Support Breaks by treating them as Conflicts.
2914+ */
2915+ if (strcasecmp("Conflicts", e->name) == 0
2916+ || strcasecmp("Breaks", e->name) == 0) {
2917+ deplist *pkgs = read_dep_and(e->value);
2918+ if (result->conflicts == NULL)
2919+ result->conflicts = pkgs;
2920+ else {
2921+ // TODO(dato): create extend_deplist() in templates.h?
2922+ deplist *end = result->conflicts;
2923+ while (end->next)
2924+ end = end->next;
2925+ end->next = pkgs;
2926+ }
2927+ }
2928+
2929+ if (strcasecmp("Provides", e->name) == 0)
2930+ result->provides = read_packagenames(e->value);
2931+
2932+ if (strcasecmp("source", e->name) == 0) {
2933+ char *pch = e->value;
2934+
2935+ assert(result->source == NULL);
2936+ assert(result->source_ver == NULL);
2937+
2938+ result->source = my_strdup(read_packagename(&pch, "("));
2939+ if (result->source == NULL)
2940+ die("read_package: bad source header");
2941+
2942+ while(isspace(*pch)) pch++;
2943+ if (*pch == '(') {
2944+ pch++;
2945+ result->source_ver = my_strdup(read_until_char(&pch, ")"));
2946+ if (result->source_ver == NULL)
2947+ die("read_package: bad source version");
2948+ while(isspace(*pch)) pch++;
2949+ if (*pch != ')')
2950+ die("read_package: unterminated ver");
2951+ }
2952+ }
2953+ }
2954+
2955+ if (result->source == NULL) {
2956+ assert(result->source_ver == NULL);
2957+ result->source = my_strdup(result->package);
2958+ }
2959+ if (result->source_ver == NULL) {
2960+ result->source_ver = my_strdup(result->version);
2961+ }
2962+
2963+ return result;
2964+}
2965+
2966+static void freesize(void *p, size_t s) { (void)s; free(p); }
2967+
2968+LIST_IMPL(deplist, dependency*, free_dependency, block_malloc, block_free);
2969+LIST_IMPL(deplistlist, deplist*, free_deplist, block_malloc, block_free);
2970+
2971+LIST_IMPLX(packagenamelist, char*, KEEP(char*));
2972+
2973+LIST_IMPL(ownedpackagenamelist, char*, KEEP(char*), block_malloc, block_free);
2974+ /* ownedpackagenamelist stores the packagename in the string store */
2975+
2976+static int packagecmp(dpkg_package *l, dpkg_package *r) {
2977+ if (l->priority < r->priority) return -1;
2978+ if (l->priority > r->priority) return +1;
2979+ return strcmp(l->package, r->package);
2980+}
2981+
2982+/* container for owned pkgs */
2983+LIST_IMPL(ownedpackagelist, dpkg_package *, free_package,
2984+ block_malloc, block_free);
2985+
2986+/* container for existing pkgs */
2987+LIST_IMPL(packagelist, dpkg_package *, KEEP(dpkg_package *), block_malloc, block_free);
2988+
2989+LIST_IMPLX(collpackagelist, dpkg_collected_package *,
2990+ KEEP(dpkg_collected_package *))
2991+#define insert_collpackagelist(x,y) insert_l_collpackagelist(x,y,__LINE__)
2992+
2993+/*************************************************************************
2994+ * Operations on distributions (collections of packages)
2995+ */
2996+
2997+dpkg_packages *new_packages(char *arch) {
2998+ dpkg_packages *result;
2999+
3000+ result = block_malloc(sizeof(dpkg_packages));
3001+ if (result == NULL) die("new_packages alloc:");
3002+
3003+ result->arch = my_strdup(arch);
3004+ result->packages = new_packagetbl();
3005+ result->virtualpkgs = new_virtualpkgtbl();
3006+
3007+ return result;
3008+}
3009+
3010+static void add_package(dpkg_packages *pkgs, dpkg_package *pkg)
3011+{
3012+ ownedpackagenamelist *v;
3013+ dpkg_collected_package *cpkg;
3014+
3015+ if (lookup_packagetbl(pkgs->packages, pkg->package) != NULL)
3016+ return;
3017+
3018+ cpkg = new_collected_package(pkg);
3019+
3020+ add_packagetbl(pkgs->packages, cpkg->pkg->package, cpkg);
3021+
3022+ add_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package,
3023+ cpkg->pkg->version, cpkg);
3024+ for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
3025+ add_virtualpackage(pkgs->virtualpkgs, v->value, NULL, cpkg);
3026+ }
3027+}
3028+
3029+static void remove_package(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
3030+ ownedpackagenamelist *v;
3031+ packagenamelist *aff;
3032+ dpkg_collected_package *p;
3033+
3034+ for (aff = cpkg->mayaffect; aff != NULL; aff = aff->next) {
3035+ p = lookup_packagetbl(pkgs->packages, aff->value);
3036+ if (p == NULL) continue;
3037+ p->installable = UNKNOWN;
3038+ }
3039+
3040+ p = remove_packagetbl(pkgs->packages, cpkg->pkg->package);
3041+ if (p != cpkg) return;
3042+
3043+ remove_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package, cpkg);
3044+ for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
3045+ remove_virtualpackage(pkgs->virtualpkgs, v->value, cpkg);
3046+ }
3047+
3048+ free_collected_package(cpkg);
3049+}
3050+
3051+dpkg_packages *get_architecture(dpkg_sources *srcs, char *arch) {
3052+ int i, arch_index;
3053+ dpkg_packages *result;
3054+ sourcetbl_iter srci;
3055+ ownedpackagelist *p;
3056+
3057+ arch_index = -1;
3058+ for (i = 0; i < srcs->n_arches; i++) {
3059+ if (strcmp(srcs->archname[i], arch) == 0) {
3060+ arch_index = i;
3061+ break;
3062+ }
3063+ }
3064+ if (arch_index == -1) die("get_architecture: unknown arch");
3065+
3066+ result = new_packages(arch);
3067+
3068+ for (srci = first_sourcetbl(srcs->sources);
3069+ !done_sourcetbl(srci);
3070+ srci = next_sourcetbl(srci))
3071+ {
3072+ for (p = srci.v->packages[arch_index]; p != NULL; p = p->next) {
3073+ add_package(result, p->value);
3074+ }
3075+ }
3076+
3077+ return result;
3078+}
3079+
3080+void free_packages(dpkg_packages *pkgs) {
3081+ if (pkgs == NULL) return;
3082+ /* block_free(pkgs->arch); */
3083+ free_packagetbl(pkgs->packages);
3084+ free_virtualpkgtbl(pkgs->virtualpkgs);
3085+ block_free(pkgs, sizeof(dpkg_packages));
3086+}
3087+
3088+
3089+HASH_IMPL(packagetbl, char *, dpkg_collected_package *, SIZEOFHASHMAP, strhash, strcmp,
3090+ KEEP(char*),free_collected_package);
3091+HASH_IMPL(virtualpkgtbl, char *, virtualpkg *, SIZEOFHASHMAP, strhash, strcmp,
3092+ KEEP(char*), free_virtualpkg);
3093+
3094+/* dpkg_provision refers to memory allocated elsewhere */
3095+LIST_IMPL(virtualpkg, dpkg_provision, KEEP(dpkg_provision), block_malloc, block_free);
3096+
3097+static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
3098+ dpkg_collected_package *cpkg)
3099+{
3100+ virtualpkg *list;
3101+ virtualpkg **where;
3102+ list = lookup_virtualpkgtbl(vpkgs, pkgname);
3103+ assert(list != NULL);
3104+
3105+ where = &list;
3106+ while((*where)->value.pkg != cpkg) {
3107+ where = &(*where)->next;
3108+ assert(*where != NULL);
3109+ }
3110+
3111+ delete_virtualpkg(where);
3112+
3113+ if (list == NULL) {
3114+ remove_virtualpkgtbl(vpkgs, pkgname);
3115+ } else {
3116+ replace_virtualpkgtbl(vpkgs, pkgname, list);
3117+ }
3118+}
3119+
3120+static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
3121+ char *version, dpkg_collected_package *cpkg)
3122+{
3123+ dpkg_provision value;
3124+ virtualpkg *list, **addto;
3125+ int shouldreplace;
3126+
3127+ value.pkg = cpkg;
3128+ value.version = version;
3129+
3130+ list = lookup_virtualpkgtbl(vpkgs, package);
3131+ shouldreplace = (list != NULL);
3132+
3133+ addto = &list;
3134+ while (*addto != NULL
3135+ && packagecmp(cpkg->pkg, (*addto)->value.pkg->pkg) >= 0)
3136+ {
3137+ addto = &(*addto)->next;
3138+ }
3139+ insert_virtualpkg(addto, value);
3140+
3141+ if (shouldreplace) {
3142+ replace_virtualpkgtbl(vpkgs, package, list);
3143+ /* old list is included in new list, so we don't need to free */
3144+ } else {
3145+ add_virtualpkgtbl(vpkgs, package, list);
3146+ }
3147+}
3148+
3149+/*************************************************************************
3150+ * Parsing Helper Functions
3151+ */
3152+
3153+static ownedpackagenamelist *read_packagenames(char *buf) {
3154+ ownedpackagenamelist *result = NULL;
3155+ ownedpackagenamelist **addto = &result;
3156+
3157+ DEBUG_ONLY( char *strend = buf + strlen(buf); )
3158+
3159+ char *sub;
3160+
3161+ while ((sub = my_strdup(read_packagename(&buf, ",")))) {
3162+ insert_ownedpackagenamelist(addto, sub);
3163+ addto = &(*addto)->next;
3164+
3165+ while(isspace(*buf)) buf++;
3166+ if (*buf == ',') {
3167+ buf++;
3168+ continue;
3169+ }
3170+ if (*buf == '\0') {
3171+ break;
3172+ }
3173+
3174+ die("read_packagenames no/bad seperator");
3175+ }
3176+
3177+ DEBUG_ONLY( assert(buf <= strend); )
3178+
3179+ return result;
3180+}
3181+
3182+static char *read_until_char(char **buf, char *end) {
3183+ static char *result = NULL;
3184+ char *start;
3185+ DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
3186+ int n;
3187+
3188+ while(isspace(**buf)) (*buf)++;
3189+
3190+ start = *buf;
3191+ while (**buf && !isspace(**buf) && strchr(end, **buf) == NULL) {
3192+ (*buf)++;
3193+ }
3194+
3195+ n = *buf - start;
3196+ if (n == 0) return NULL;
3197+
3198+ result = realloc(result, n + 1);
3199+ if (result == NULL) die("read_until_char alloc:");
3200+
3201+ strncpy(result, start, n);
3202+ result[n] = '\0';
3203+
3204+ while(isspace(**buf)) (*buf)++;
3205+
3206+ DEBUG_ONLY( assert(*buf <= strend); )
3207+
3208+ return result;
3209+}
3210+
3211+static char *read_packagename(char **buf, char *end) {
3212+ return read_until_char(buf, end);
3213+}
3214+
3215+static deplist *read_dep_and(char *buf) {
3216+ return read_deplist(&buf, ',', '\0');
3217+}
3218+
3219+static deplist *read_deplist(char **buf, char sep, char end) {
3220+ deplist *result = NULL;
3221+ deplist **addto = &result;
3222+
3223+ char separs[3] = { sep, end, '\0' };
3224+
3225+ DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
3226+
3227+ dependency *sub;
3228+
3229+ while ((sub = read_dependency(buf, separs))) {
3230+ insert_deplist(addto, sub);
3231+ addto = &(*addto)->next;
3232+
3233+ while(isspace(**buf)) (*buf)++;
3234+ if (**buf == sep) {
3235+ (*buf)++;
3236+ continue;
3237+ }
3238+ if (**buf == '\0' || **buf == end) {
3239+ break;
3240+ }
3241+
3242+ die("read_deplist no/bad seperator");
3243+ }
3244+
3245+ DEBUG_ONLY( assert(*buf <= strend); )
3246+
3247+ return result;
3248+}
3249+
3250+static deplistlist *read_dep_andor(char *buf) {
3251+ deplistlist *result = NULL;
3252+ deplistlist **addto = &result;
3253+
3254+ deplist *sub;
3255+
3256+ DEBUG_ONLY( char *strend = buf + strlen(buf); )
3257+
3258+ while ((sub = read_deplist(&buf, '|', ','))) {
3259+ insert_deplistlist(addto, sub);
3260+ addto = &(*addto)->next;
3261+
3262+ if (*buf == ',') buf++;
3263+ }
3264+
3265+ DEBUG_ONLY( assert(buf <= strend); )
3266+
3267+ return result;
3268+}
3269+
3270+static dependency *read_dependency(char **buf, char *end) {
3271+ dependency *dep;
3272+ char *name;
3273+ char newend[10];
3274+ DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
3275+
3276+ assert(strlen(end) <= 8);
3277+ newend[0] = '('; strcpy(newend + 1, end);
3278+
3279+ name = my_strdup(read_until_char(buf, newend));
3280+ if (name == NULL) return NULL;
3281+
3282+ dep = block_malloc(sizeof(dependency));
3283+ if (dep == NULL) die("read_dependency alloc 1:");
3284+
3285+ dep->package = name;
3286+
3287+ while(isspace(**buf)) (*buf)++;
3288+
3289+ if (**buf != '(') {
3290+ dep->op = dr_NOOP;
3291+ dep->version = NULL;
3292+ } else {
3293+ (*buf)++;
3294+ while(isspace(**buf)) (*buf)++;
3295+ /* << , <= , = , >= , >> */
3296+ if (**buf == '<') {
3297+ (*buf)++;
3298+ if (**buf == '<') {
3299+ dep->op = dr_LT;
3300+ (*buf)++;
3301+ } else if (**buf == '=') {
3302+ dep->op = dr_LTEQ;
3303+ (*buf)++;
3304+ } else {
3305+ /* The forms `<' and `>' were used to mean earlier/later or
3306+ * equal, rather than strictly earlier/later, so they should
3307+ * not appear in new packages (though `dpkg' still supports
3308+ * them).
3309+ */
3310+ dep->op = dr_LTEQ;
3311+ }
3312+ } else if (**buf == '>') {
3313+ (*buf)++;
3314+ if (**buf == '>') {
3315+ dep->op = dr_GT;
3316+ (*buf)++;
3317+ } else if (**buf == '=') {
3318+ dep->op = dr_GTEQ;
3319+ (*buf)++;
3320+ } else {
3321+ dep->op = dr_GTEQ;
3322+ }
3323+ } else if (**buf == '=') {
3324+ dep->op = dr_EQ;
3325+ (*buf)++;
3326+ if (**buf == '>') {
3327+ dep->op = dr_GTEQ;
3328+ (*buf)++;
3329+ } else if (**buf == '<') {
3330+ dep->op = dr_LTEQ;
3331+ (*buf)++;
3332+ }
3333+ } else {
3334+ /* treat it as an implicit = :( */
3335+ dep->op = dr_EQ;
3336+ /* would prefer to: die("read_dependency unknown version op"); */
3337+ }
3338+
3339+ while (isspace(**buf)) (*buf)++;
3340+ newend[0] = ')';
3341+ dep->version = my_strdup(read_until_char(buf, newend));
3342+ while (isspace(**buf)) (*buf)++;
3343+
3344+ if (dep->version == NULL) die("read_dependency: no version");
3345+ if (**buf != ')') die("read_dependency: unterminated version");
3346+ (*buf)++;
3347+ }
3348+
3349+ DEBUG_ONLY( assert(*buf <= strend); )
3350+
3351+ return dep;
3352+}
3353+
3354+static void free_dependency(dependency *dep) {
3355+ if (dep == NULL) return;
3356+ /* block_free(dep->package); */
3357+ /* if (dep->version) block_free(dep->version); */
3358+ block_free(dep, sizeof(dependency));
3359+}
3360+
3361+/*************************************************************************
3362+ * Installability Checking
3363+ */
3364+
3365+static collpackagelist **get_matching_low(collpackagelist **addto,
3366+ dpkg_packages *pkgs, dependency *dep, int line)
3367+{
3368+ virtualpkg *vpkg;
3369+ for (vpkg = lookup_virtualpkgtbl(pkgs->virtualpkgs, dep->package);
3370+ vpkg != NULL;
3371+ vpkg = vpkg->next)
3372+ {
3373+ int add;
3374+
3375+ add = 0;
3376+ if (dep->op == dr_NOOP) {
3377+ add = 1;
3378+ } else if (vpkg->value.version != NULL) {
3379+ if (cmpversions(vpkg->value.version, dep->op, dep->version)) {
3380+ add = 1;
3381+ }
3382+ }
3383+
3384+ if (add) {
3385+ insert_l_collpackagelist(addto, vpkg->value.pkg, line);
3386+ addto = &(*addto)->next;
3387+ }
3388+ }
3389+
3390+ return addto;
3391+}
3392+
3393+static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line) {
3394+ collpackagelist *list = NULL;
3395+ collpackagelist **addto = &list;
3396+
3397+ for(; depopts != NULL; depopts = depopts->next) {
3398+ addto = get_matching_low(addto, pkgs, depopts->value, line);
3399+ }
3400+
3401+ return list;
3402+}
3403+
3404+typedef struct instonelist instonelist;
3405+struct instonelist {
3406+ collpackagelist *curX;
3407+ collpackagelist *instoneX;
3408+ int expandedX;
3409+ struct instonelist *nextX, *prevX, *cutoffX;
3410+};
3411+
3412+#define I1CUR(i1) ((i1)->curX)
3413+#define I1INSTONE(i1) ((i1)->instoneX)
3414+#define I1CUTOFF(i1) ((i1)->cutoffX)
3415+#define I1NEXT(i1) ((i1)->nextX) /* can be modified ! */
3416+#define I1PREV(i1) ((i1)->prevX)
3417+#define I1EXPANDED(i1) ((i1)->expandedX)
3418+
3419+static instonelist *insert_instonelist(instonelist *where, collpackagelist *instone);
3420+static void trim_instonelist_after(instonelist *first);
3421+static void free_instonelist(instonelist *l);
3422+
3423+static int max_instone_len = 0;
3424+static int cur_instone_len = 0;
3425+
3426+static instonelist *insert_instonelist(instonelist *old, collpackagelist *instone)
3427+{
3428+ instonelist *n = block_malloc(sizeof(instonelist));
3429+ if (n == NULL)
3430+ die("insert_instonelist alloc:");
3431+
3432+ n->curX = NULL;
3433+ n->instoneX = instone;
3434+ n->cutoffX = NULL;
3435+ n->nextX = (old ? old->nextX : NULL);
3436+ n->prevX = old;
3437+ n->expandedX = 0;
3438+
3439+ if (old) old->nextX = n;
3440+ if (n->nextX) n->nextX->prevX = n;
3441+
3442+ cur_instone_len++;
3443+ if (cur_instone_len > max_instone_len) max_instone_len = cur_instone_len;
3444+
3445+ return n;
3446+}
3447+
3448+static void trim_instonelist_after(instonelist *first) {
3449+ if (!first->nextX) return;
3450+ first->nextX->prevX = NULL;
3451+ free_instonelist(first->nextX);
3452+ first->nextX = NULL;
3453+}
3454+
3455+static void free_instonelist(instonelist *l) {
3456+ instonelist *p, *k;
3457+ if (!l) return;
3458+ for (p = l; p->nextX; p = p->nextX);
3459+ do {
3460+ k = p;
3461+ p = k->prevX;
3462+ free_collpackagelist(k->instoneX);
3463+ block_free(k, sizeof(instonelist));
3464+ cur_instone_len--;
3465+ } while (k != l);
3466+}
3467+
3468+static int caninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
3469+ collpackagelist *conflicts;
3470+ collpackagelist *conf;
3471+ int okay;
3472+
3473+ if (cpkg->installed > 0) return 1;
3474+ if (cpkg->conflicted > 0) return 0;
3475+
3476+ conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
3477+
3478+ okay = 1;
3479+ for (conf = conflicts; conf != NULL; conf = conf->next) {
3480+ if (conf->value->installed > 0) {
3481+ okay = 0;
3482+ break;
3483+ }
3484+ }
3485+ free_collpackagelist(conflicts);
3486+ return okay;
3487+}
3488+
3489+static int cur_install =0;
3490+static int max_install = 0;
3491+static int cur_conflicted = 0;
3492+static int max_conflicted = 0;
3493+
3494+static void install(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
3495+ if (cpkg->installed == 0) {
3496+ collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
3497+ collpackagelist *conf;
3498+ for (conf = conflicts; conf != NULL; conf = conf->next) {
3499+ if (conf->value == cpkg) continue;
3500+ assert(conf->value->installed == 0);
3501+ conf->value->conflicted++;
3502+ if (conf->value->conflicted == 1) {
3503+ cur_conflicted++;
3504+ if (max_conflicted < cur_conflicted)
3505+ max_conflicted = cur_conflicted;
3506+ }
3507+ }
3508+ free_collpackagelist(conflicts);
3509+ cur_install++;
3510+ if (max_install < cur_install) max_install = cur_install;
3511+ }
3512+ assert(cpkg->conflicted == 0);
3513+ cpkg->installed++;
3514+}
3515+
3516+static void uninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
3517+ assert(cpkg->installed > 0);
3518+ assert(cpkg->conflicted == 0);
3519+ cpkg->installed--;
3520+ if (cpkg->installed == 0) {
3521+ collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
3522+ collpackagelist *conf;
3523+ for (conf = conflicts; conf != NULL; conf = conf->next) {
3524+ if (conf->value == cpkg) continue;
3525+ assert(conf->value->installed == 0);
3526+ assert(conf->value->conflicted > 0);
3527+ conf->value->conflicted--;
3528+ if (conf->value->conflicted == 0) cur_conflicted--;
3529+ }
3530+ free_collpackagelist(conflicts);
3531+ cur_install--;
3532+ }
3533+}
3534+
3535+satisfieddep *new_satisfieddep(void) {
3536+ satisfieddep *sd = block_malloc(sizeof(satisfieddep));
3537+ if (!sd) die("new_satisfieddep alloc:");
3538+ return sd;
3539+}
3540+
3541+void free_satisfieddep(satisfieddep *sd) {
3542+ if (!sd) return;
3543+ free_packagelist(sd->pkgs);
3544+ block_free(sd, sizeof(satisfieddep));
3545+}
3546+
3547+LIST_IMPL(satisfieddeplist, satisfieddep *, free_satisfieddep, block_malloc, block_free);
3548+
3549+packagelist *collpkglist2pkglist(collpackagelist *l) {
3550+ packagelist *r = NULL;
3551+ packagelist **addto = &r;
3552+
3553+ for (; l != NULL; l = l->next) {
3554+ insert_packagelist(addto, l->value->pkg);
3555+ addto = &(*addto)->next;
3556+ }
3557+
3558+ return r;
3559+}
3560+
3561+satisfieddeplist *checkunsatisfiabledeps(dpkg_packages *pkgs,
3562+ deplistlist *deps) {
3563+ satisfieddeplist *unsatisfiable = NULL;
3564+ satisfieddeplist **addto = &unsatisfiable;
3565+ satisfieddep *sd;
3566+ collpackagelist *deppkgs;
3567+
3568+ for (; deps != NULL; deps = deps->next) {
3569+ /* deplist *dep; */
3570+ /* for (dep = deps->value; dep != NULL; dep = dep->next) { */
3571+ sd = new_satisfieddep();
3572+ /* sd->dep = dep->value; */
3573+ sd->depl = deps->value;
3574+
3575+ deppkgs = NULL;
3576+ /* get_matching_low(&deppkgs, pkgs, dep->value); */
3577+ deppkgs = get_matching(pkgs, deps->value, __LINE__);
3578+ sd->pkgs = collpkglist2pkglist(deppkgs);
3579+ free_collpackagelist(deppkgs);
3580+
3581+ insert_satisfieddeplist(addto, sd);
3582+ addto = &(*addto)->next;
3583+ /* } */
3584+ }
3585+
3586+ return unsatisfiable;
3587+}
3588+
3589+int checkinstallable2(dpkg_packages *pkgs, char *pkgname) {
3590+ dpkg_collected_package *cpkg = lookup_packagetbl(pkgs->packages, pkgname);
3591+ collpackagelist *cpl = NULL;
3592+
3593+ if (cpkg == NULL) return 0;
3594+
3595+ insert_collpackagelist(&cpl, cpkg);
3596+ /* cpl gets freed in checkinstallable :-/ */
3597+ return checkinstallable(pkgs, cpl);
3598+}
3599+
3600+static void debug_checkinstallable(FILE *out, instonelist *list,
3601+ instonelist *last, instonelist *pointer)
3602+{
3603+ instonelist *l;
3604+ fprintf(out, "Status:");
3605+
3606+ /* codes: | = multiple options here
3607+ * @ = no options can satisfy this dep
3608+ * + = dependencies that can be expanded have been
3609+ * * = nothing selected yet
3610+ * > = where pointer points
3611+ * ^ = the cut point for where we are
3612+ */
3613+
3614+ for (l = list; ; l = I1NEXT(l)) {
3615+ fprintf(out, " ");
3616+ if (l == pointer) fprintf(out, ">");
3617+ if (l == I1CUTOFF(pointer)) fprintf(out, "^");
3618+ if (I1INSTONE(l) == NULL) {
3619+ fprintf(out, "@");
3620+ } else {
3621+ if (I1INSTONE(l)->next != NULL) {
3622+ fprintf(out, "|");
3623+ }
3624+ if (I1EXPANDED(l)) {
3625+ fprintf(out, "+");
3626+ }
3627+ if (I1CUR(l) == NULL) {
3628+ fprintf(out, "*%s", I1INSTONE(l)->value->pkg->package);
3629+ } else {
3630+ fprintf(out, "%s", I1CUR(l)->value->pkg->package);
3631+ }
3632+ }
3633+ if (l == last) break;
3634+ }
3635+ fprintf(out, " ###\n");
3636+ fflush(out);
3637+}
3638+
3639+int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof) {
3640+ /* We use pkg->installed, pkg->conflicted to note how many
3641+ * times we've used this pkg to satisfy a dependency or installed
3642+ * a package that conflicts with it.
3643+ * Thus: pkg->installed == 0, or pkg->conflicted == 0
3644+ *
3645+ * We assume these are okay initially, aren't being played with
3646+ * concurrently elsewhere, and make sure they're still okay when
3647+ * we return.
3648+ */
3649+
3650+ instonelist *list;
3651+ instonelist *last;
3652+
3653+ instonelist *pointer;
3654+
3655+ unsigned long counter = 500000000;
3656+
3657+ int last_max_inst = max_install;
3658+ int last_max_instone = max_instone_len;
3659+ int last_max_conflict = max_conflicted;
3660+
3661+ {
3662+ collpackagelist *cpkg;
3663+ for (cpkg = instoneof; cpkg; cpkg = cpkg->next) {
3664+ if (cpkg->value->installable == YES) {
3665+ free_collpackagelist(instoneof);
3666+ return 1;
3667+ }
3668+ }
3669+ }
3670+
3671+ list = insert_instonelist(NULL, instoneof);
3672+
3673+ last = list;
3674+ pointer = list;
3675+
3676+ while(--counter > 0 && pointer) {
3677+ deplistlist *dep;
3678+ dpkg_collected_package *instpkg; /* convenient alias */
3679+ int i;
3680+
3681+#ifndef NDEBUG
3682+ {
3683+ instonelist *p;
3684+ for (p = list; p != pointer; p = I1NEXT(p)) {
3685+ assert(p != NULL);
3686+ assert(I1CUR(p) != NULL);
3687+ assert(I1CUR(p)->value != NULL);
3688+ assert(I1CUR(p)->value->installed > 0);
3689+ assert(I1CUR(p)->value->conflicted == 0);
3690+ }
3691+ if (I1NEXT(pointer) == NULL) {
3692+ assert(pointer == last);
3693+ } else {
3694+ for (p = I1NEXT(pointer); p; p = I1NEXT(p)) {
3695+ if (I1NEXT(p) == NULL) {
3696+ assert(p == last);
3697+ }
3698+ assert(I1CUR(p) == NULL);
3699+ }
3700+ }
3701+ }
3702+#endif
3703+
3704+#ifdef DIAGNOSE
3705+ debug_checkinstallable(stdout, list, last, pointer);
3706+#endif
3707+
3708+ if (I1CUR(pointer) == NULL) {
3709+ I1CUR(pointer) = I1INSTONE(pointer);
3710+ /* try to choose an already installed package if there is one */
3711+ while (I1CUR(pointer) != NULL) {
3712+ if (I1CUR(pointer)->value->installed != 0) {
3713+ break;
3714+ }
3715+ I1CUR(pointer) = I1CUR(pointer)->next;
3716+ }
3717+ if (I1CUR(pointer) == NULL) {
3718+ I1CUR(pointer) = I1INSTONE(pointer);
3719+ }
3720+ assert(I1CUR(pointer) || !I1INSTONE(pointer));
3721+
3722+ I1CUTOFF(pointer) = last;
3723+ } else {
3724+ uninstall(pkgs, I1CUR(pointer)->value);
3725+ trim_instonelist_after(I1CUTOFF(pointer));
3726+ last = I1CUTOFF(pointer);
3727+
3728+ if (I1CUR(pointer)->value->installed > 0) {
3729+ /* this dependency isn't the issue -- even doing
3730+ * nothing to satisfy it (ie, using an already
3731+ * installed package) doesn't do any good. So give up.
3732+ */
3733+ I1CUR(pointer) = NULL;
3734+ } else {
3735+ I1CUR(pointer) = I1CUR(pointer)->next;
3736+ }
3737+ }
3738+
3739+ while(I1CUR(pointer) && !caninstall(pkgs, I1CUR(pointer)->value)) {
3740+ I1CUR(pointer) = I1CUR(pointer)->next;
3741+ }
3742+
3743+ if (I1CUR(pointer) == NULL) {
3744+ if (I1PREV(pointer) == NULL) break;
3745+ pointer = I1PREV(pointer);
3746+ continue;
3747+ }
3748+
3749+ instpkg = I1CUR(pointer)->value;
3750+
3751+ install(pkgs, instpkg);
3752+
3753+ assert(instpkg->installed > 0);
3754+ if (instpkg->installed == 1) {
3755+ /* if it's been installed exactly once, then this must've been
3756+ * the first time it was touched, so we need to look at the
3757+ * dependencies. If it's the second or later, then we don't care
3758+ * about them.
3759+ */
3760+
3761+ /* if any of the deps can't be satisfied, don't move on */
3762+ int bother = 1;
3763+
3764+ int expanded = I1EXPANDED(pointer);
3765+
3766+ for (i = 0; i < 4; i++) {
3767+ if (!dependency_counts[i]) continue;
3768+ for (dep = instpkg->pkg->depends[i];
3769+ dep != NULL; dep = dep->next)
3770+ {
3771+ collpackagelist *thisdep = get_matching(pkgs, dep->value, __LINE__);
3772+
3773+ if (thisdep == NULL) {
3774+ bother = 0;
3775+
3776+ } else if (thisdep != NULL && thisdep->next == NULL) {
3777+ collpackagelist *x;
3778+
3779+ /* if there's only one way of fulfilling this dep,
3780+ * do it "ASAP"
3781+ */
3782+
3783+ /* optimisation: if thisdep == foo, but the parent
3784+ * was foo|bar, then we already know "foo" is not going
3785+ * to work in this combination, and we can skip it.
3786+ *
3787+ * This deals with cases like X deps: Y|bar, bar deps: Y
3788+ * where bar is a virtual package; cf xlibs
3789+ */
3790+ for (x = I1INSTONE(pointer); x != I1CUR(pointer); x = x->next) {
3791+ if (x->value == thisdep->value) {
3792+ bother = 0;
3793+ break;
3794+ }
3795+ }
3796+
3797+ if (I1INSTONE(pointer)->next == NULL) {
3798+ /* the parent of this entry essentially depends
3799+ * on this too, so we'll get it out of the way
3800+ * ASAP, to reduce the degree of exponentiation
3801+ * in bad cases.
3802+ *
3803+ * _However_ we only want to do this _once_ for
3804+ * any particular node.
3805+ */
3806+ if (expanded) {
3807+ /* thisdep isn't used! */
3808+ free_collpackagelist(thisdep);
3809+ } else {
3810+ insert_instonelist(pointer, thisdep);
3811+ I1EXPANDED(pointer) = 1;
3812+ }
3813+ } else {
3814+ insert_instonelist(I1CUTOFF(pointer), thisdep);
3815+ }
3816+ if (I1NEXT(last)) last = I1NEXT(last);
3817+ assert(!I1NEXT(last));
3818+
3819+ } else {
3820+ /* otherwise it's a multi possibility dep, so do it
3821+ * at the end
3822+ */
3823+
3824+ last = insert_instonelist(last, thisdep);
3825+ }
3826+ }
3827+ }
3828+ if (!bother) {
3829+ /* stay where we are, and try the next possibility */
3830+ continue;
3831+ }
3832+ }
3833+
3834+ pointer = I1NEXT(pointer);
3835+ }
3836+
3837+ if (max_install>last_max_inst || max_instone_len>last_max_instone || max_conflicted >last_max_conflict) {
3838+ printf("MAX: i:%d / c:%d / i1:%d %s\n", max_install,max_conflicted,max_instone_len,instoneof->value->pkg->package);
3839+ }
3840+
3841+ if (counter == 0) {
3842+ fprintf(stderr, "AIEEE: counter overflow:");
3843+ assert(pointer != NULL);
3844+ if (I1CUR(pointer) == NULL || I1CUR(pointer)->value == NULL) {
3845+ /* we're not guaranteed that pointer will make sense here */
3846+ pointer = I1PREV(pointer);
3847+ }
3848+ for (; pointer != NULL; pointer = I1PREV(pointer)) {
3849+ if (I1CUR(pointer) == NULL) {
3850+ /* should only happen at pointer, so not here */
3851+ fprintf(stderr, " >> eep, no packages at pointer <<");
3852+ continue;
3853+ }
3854+ if (I1CUR(pointer)->value == NULL) {
3855+ /* should never happen */
3856+ fprintf(stderr, " >> eep, no package selected <<");
3857+ continue;
3858+ }
3859+ fprintf(stderr, " %s%s",
3860+ (I1INSTONE(pointer)->next == NULL ? "" : "|"),
3861+ I1CUR(pointer)->value->pkg->package);
3862+ uninstall(pkgs, I1CUR(pointer)->value);
3863+ }
3864+ fprintf(stderr, ".\n");
3865+ free_instonelist(list);
3866+ return 0;
3867+ }
3868+
3869+ if (pointer == NULL) {
3870+ dpkg_collected_package *cpkg = I1CUR(list)->value;
3871+ assert(cpkg->installable != YES);
3872+ cpkg->installable = YES;
3873+ for (pointer = last; pointer != NULL; pointer = I1PREV(pointer)) {
3874+ if (I1CUR(pointer)->value->installed == 1) {
3875+ packagenamelist **p = &I1CUR(pointer)->value->mayaffect;
3876+#if 0
3877+ while ( *p && (*p)->value < cpkg->pkg->package ) {
3878+ p = &(*p)->next;
3879+ }
3880+ if (*p == NULL || (*p)->value > cpkg->pkg->package)
3881+#endif
3882+ {
3883+ insert_packagenamelist(p, cpkg->pkg->package);
3884+ }
3885+ }
3886+ uninstall(pkgs, I1CUR(pointer)->value);
3887+ }
3888+ free_instonelist(list);
3889+ return 1;
3890+ } else {
3891+ assert(I1CUR(list) == NULL);
3892+ free_instonelist(list);
3893+ return 0;
3894+ }
3895+}
3896+
3897+/******************/
3898+
3899+HASH_IMPL(sourcetbl, char *, dpkg_source *, SIZEOFHASHMAP, strhash, strcmp,
3900+ KEEP(char*), free_source);
3901+
3902+static dpkg_sources *read_sources_file(char *filename, int n_arches) {
3903+ FILE *f;
3904+ dpkg_sources *result;
3905+ dpkg_source *src;
3906+ int i;
3907+
3908+ f = fopen(filename, "r");
3909+ if (f == NULL && errno != ENOENT) {
3910+ die("read_sources_file: couldn't open file:");
3911+ }
3912+
3913+ result = block_malloc(sizeof(dpkg_sources));
3914+ if (result == NULL) die("read_sources_file alloc 1:");
3915+
3916+ result->n_arches = n_arches;
3917+ result->archname = block_malloc(sizeof(char*) * n_arches);
3918+ if (result->archname == NULL) die("read_sources_file alloc 2:");
3919+ for (i = 0; i < n_arches; i++) result->archname[i] = NULL;
3920+ result->unclaimedpackages = block_malloc(sizeof(ownedpackagelist*)
3921+ * n_arches);
3922+ if (result->unclaimedpackages == NULL) die("read_sources_file alloc 3:");
3923+ for (i = 0; i < n_arches; i++) result->unclaimedpackages[i] = NULL;
3924+
3925+ result->sources = new_sourcetbl();
3926+
3927+ if (f != NULL) {
3928+ while ((src = read_source(f, result))) {
3929+ dpkg_source *old = lookup_sourcetbl(result->sources, src->package);
3930+ if (old == NULL) {
3931+ add_sourcetbl(result->sources, src->package, src);
3932+ } else {
3933+ if (versioncmp(old->version, src->version) || 1) {
3934+ int i;
3935+ old = replace_sourcetbl(result->sources, src->package, src);
3936+ for (i = 0; i < old->owner->n_arches; i++) {
3937+ assert(old->packages[i] == NULL);
3938+ }
3939+ free_source(old);
3940+ } else {
3941+ int i;
3942+ for (i = 0; i < src->owner->n_arches; i++) {
3943+ assert(src->packages[i] == NULL);
3944+ }
3945+ free_source(src);
3946+ }
3947+ }
3948+ }
3949+ fclose(f);
3950+ }
3951+
3952+ return result;
3953+}
3954+
3955+void free_sources(dpkg_sources *s) {
3956+ int i;
3957+ if (s == NULL) return;
3958+ free_sourcetbl(s->sources);
3959+ for (i = 0; i < s->n_arches; i++) {
3960+ /* block_free(s->archname[i]); */
3961+ free_ownedpackagelist(s->unclaimedpackages[i]);
3962+ }
3963+ block_free(s->archname, s->n_arches * sizeof(char*));
3964+ block_free(s->unclaimedpackages, s->n_arches * sizeof(ownedpackagelist*));
3965+ block_free(s, sizeof(dpkg_sources));
3966+}
3967+
3968+static dpkg_source *new_source(dpkg_sources *owner) {
3969+ dpkg_source *result;
3970+ int i;
3971+
3972+ result = block_malloc(sizeof(dpkg_source));
3973+ if (result == NULL) die("new_source alloc 1:");
3974+
3975+ result->package = NULL;
3976+ result->version = NULL;
3977+ result->details = NULL;
3978+ result->fake = 0;
3979+
3980+ result->owner = owner;
3981+ result->packages = block_malloc(sizeof(packagelist*) * owner->n_arches);
3982+ if (result->packages == NULL) die("new_source alloc 2:");
3983+ for (i = 0; i < owner->n_arches; i++) {
3984+ result->packages[i] = NULL;
3985+ }
3986+
3987+ return result;
3988+}
3989+
3990+static dpkg_source *read_source(FILE *f, dpkg_sources *owner) {
3991+ dpkg_source *result;
3992+ dpkg_paragraph *para;
3993+ dpkg_entry *e;
3994+
3995+ para = read_paragraph(f);
3996+ if (para == NULL) return NULL;
3997+
3998+ result = new_source(owner);
3999+ result->details = para;
4000+
4001+ for (e = &para->entry[0]; e < &para->entry[para->n_entries]; e++) {
4002+ if (strcmp("Package", e->name) == 0) {
4003+ result->package = my_strdup(e->value);
4004+ if (result->package == NULL)
4005+ die("read_source strdup:");
4006+ result->package[strlen(result->package)-1] = '\0';
4007+ }
4008+
4009+ if (strcmp("Version", e->name) == 0) {
4010+ result->version = my_strdup(e->value);
4011+ if (result->version == NULL)
4012+ die("read_source strdup:");
4013+ result->version[strlen(result->version)-1] = '\0';
4014+ }
4015+ }
4016+
4017+ return result;
4018+}
4019+
4020+void free_source(dpkg_source *s) {
4021+ int i;
4022+ if (s == NULL) return;
4023+ assert(s->owner != NULL); /* shouldn't have allocated it */
4024+ /* block_free(s->package); */
4025+ /* block_free(s->version); */
4026+ free_paragraph(s->details);
4027+ for (i = 0; i < s->owner->n_arches; i++) {
4028+ free_ownedpackagelist(s->packages[i]);
4029+ }
4030+ block_free(s->packages, s->owner->n_arches * sizeof(ownedpackagelist*));
4031+ block_free(s, sizeof(dpkg_source));
4032+}
4033+
4034+/******************************/
4035+
4036+dpkg_sources *read_directory(char *dir, int n_arches, char *archname[]) {
4037+ char buf[1000];
4038+ dpkg_sources *srcs;
4039+ int i;
4040+
4041+ snprintf(buf, 1000, "%s/Sources", dir);
4042+ srcs = read_sources_file(buf, n_arches);
4043+
4044+ for (i = 0; i < n_arches; i++) {
4045+ FILE *f;
4046+ dpkg_package *pkg;
4047+
4048+ srcs->archname[i] = my_strdup(archname[i]);
4049+
4050+ snprintf(buf, 1000, "%s/Packages_%s", dir, archname[i]);
4051+ f = fopen(buf, "r");
4052+ if (f == NULL && errno != ENOENT) die("load_dirctory fopen:");
4053+ if (f != NULL) {
4054+ while ((pkg = read_package(f))) {
4055+ dpkg_source *src = lookup_sourcetbl(srcs->sources, pkg->source);
4056+ if (src == NULL) {
4057+ src = new_source(srcs);
4058+ src->fake = 1;
4059+ src->package = my_strdup(pkg->source);
4060+ src->version = my_strdup(pkg->source_ver);
4061+ add_sourcetbl(srcs->sources, src->package, src);
4062+ }
4063+ insert_ownedpackagelist(&src->packages[i], pkg);
4064+ }
4065+ fclose(f);
4066+ }
4067+ }
4068+
4069+ return srcs;
4070+}
4071+
4072+void write_directory(char *dir, dpkg_sources *srcs) {
4073+ FILE *src;
4074+ FILE *archfile[100];
4075+ char buf[1000];
4076+ int i;
4077+ sourcetbl_iter srciter;
4078+
4079+ snprintf(buf, 1000, "%s/Sources", dir);
4080+ src = fopen(buf, "w");
4081+ if (!src) die("write_directory: Couldn't open Sources file for output");
4082+
4083+ for (i = 0; i < srcs->n_arches; i++) {
4084+ snprintf(buf, 1000, "%s/Packages_%s", dir, srcs->archname[i]);
4085+ archfile[i] = fopen(buf, "w");
4086+ }
4087+
4088+ for (srciter = first_sourcetbl(srcs->sources);
4089+ !done_sourcetbl(srciter);
4090+ srciter = next_sourcetbl(srciter))
4091+ {
4092+ ownedpackagelist *p;
4093+ int i;
4094+
4095+ if (!srciter.v->fake)
4096+ write_paragraph(src, srciter.v->details);
4097+
4098+ for (i = 0; i < srcs->n_arches; i++) {
4099+ for (p = srciter.v->packages[i]; p != NULL; p = p->next) {
4100+ write_paragraph(archfile[i], p->value->details);
4101+ }
4102+ }
4103+ }
4104+
4105+ fclose(src);
4106+ for (i = 0; i < srcs->n_arches; i++) {
4107+ fclose(archfile[i]);
4108+ }
4109+}
4110+
4111+/*********************/
4112+
4113+HASH_IMPL(sourcenotetbl, char *, dpkg_source_note *, SIZEOFHASHMAP, strhash, strcmp,
4114+ KEEP(char*), free_source_note);
4115+
4116+dpkg_source_note *new_source_note(dpkg_source *src, int n_arches) {
4117+ dpkg_source_note *result = block_malloc(sizeof(dpkg_source_note));
4118+ int i;
4119+
4120+ if (result == NULL) die("new_source_note alloc 1:");
4121+ result->source = src;
4122+ result->n_arches = n_arches;
4123+ result->binaries = block_malloc(n_arches * sizeof(packagelist*));
4124+ if (result->binaries == NULL) die("new_source_note alloc 2:");
4125+ for (i = 0; i < n_arches; i++) {
4126+ result->binaries[i] = NULL;
4127+ }
4128+ return result;
4129+}
4130+
4131+void free_source_note(dpkg_source_note *srcn) {
4132+ int i;
4133+
4134+ if (srcn == NULL) return;
4135+
4136+ if (srcn->binaries != NULL) {
4137+ for (i = 0; i < srcn->n_arches; i++) {
4138+ free_packagelist(srcn->binaries[i]);
4139+ }
4140+ block_free(srcn->binaries, sizeof(packagelist*) * srcn->n_arches);
4141+ }
4142+ block_free(srcn, sizeof(dpkg_source_note));
4143+}
4144+
4145+#ifdef DEBUG
4146+static int is_sources_note(dpkg_sources_note *srcsn) {
4147+ int i;
4148+
4149+ assert(srcsn != NULL);
4150+ assert(srcsn->magic == 0xa1eebabe);
4151+ assert(srcsn->pkgs != NULL);
4152+ for (i = 0; i < srcsn->n_arches; i++) {
4153+ assert(srcsn->pkgs[i] != NULL && srcsn->archname[i] != NULL);
4154+ assert(strcmp(srcsn->archname[i], srcsn->pkgs[i]->arch) == 0);
4155+ }
4156+
4157+ return 1;
4158+}
4159+#endif
4160+
4161+dpkg_sources_note *new_sources_note(int n_arches, char **archname) {
4162+ dpkg_sources_note *result = block_malloc(sizeof(dpkg_sources_note));
4163+ int i;
4164+
4165+ if (result == NULL) die("new_sources_note alloc 1:");
4166+ result->magic = 0xA1EEBABE;
4167+ result->sources = new_sourcenotetbl();
4168+ result->pkgs = block_malloc(n_arches * sizeof(dpkg_packages*));
4169+ if (result->pkgs == NULL) die("new_sources_note alloc 2:");
4170+ result->archname = block_malloc(n_arches * sizeof(char*));
4171+ if (result->archname == NULL) die("new_sources_note alloc 3:");
4172+
4173+ result->n_arches = n_arches;
4174+ for (i = 0; i < n_arches; i++) {
4175+ result->archname[i] = my_strdup(archname[i]);
4176+ result->pkgs[i] = new_packages(result->archname[i]);
4177+ }
4178+ result->undo = NULL;
4179+ return result;
4180+}
4181+
4182+void free_sources_note(dpkg_sources_note *srcsn) {
4183+ int i;
4184+ if (srcsn == NULL) return;
4185+ assert(is_sources_note(srcsn));
4186+ srcsn->magic = 0xBABEA1EE;
4187+ free_sourcenotetbl(srcsn->sources);
4188+ for (i = 0; i < srcsn->n_arches; i++) {
4189+ free_packages(srcsn->pkgs[i]);
4190+ /* block_free(srcsn->archname[i]); */
4191+ }
4192+ block_free(srcsn->pkgs, sizeof(dpkg_packages*) * srcsn->n_arches);
4193+ block_free(srcsn->archname, sizeof(char*) * srcsn->n_arches);
4194+ free_source_note_listlist(srcsn->undo);
4195+ block_free(srcsn, sizeof(dpkg_sources_note));
4196+}
4197+
4198+static void new_op(dpkg_sources_note *srcsn) {
4199+ assert(is_sources_note(srcsn));
4200+ insert_source_note_listlist(&srcsn->undo, NULL);
4201+}
4202+static void save_source_note(dpkg_sources_note *srcsn, dpkg_source_note *srcn) {
4203+ source_note_list **where;
4204+ assert(is_sources_note(srcsn));
4205+ assert(srcsn->undo != NULL);
4206+
4207+ for (where = &srcsn->undo->value;
4208+ *where != NULL;
4209+ where = &(*where)->next)
4210+ {
4211+ if ((*where)->value->source == srcn->source)
4212+ return; /* already saved */
4213+ }
4214+
4215+ insert_source_note_list(where, copy_source_note(srcn));
4216+}
4217+static void save_empty_source_note(dpkg_sources_note *srcsn, dpkg_source *src) {
4218+ dpkg_source_note *srcn;
4219+ source_note_list **where;
4220+
4221+ for (where = &srcsn->undo->value;
4222+ *where != NULL;
4223+ where = &(*where)->next)
4224+ {
4225+ if ((*where)->value->source == src)
4226+ return; /* already saved */
4227+ }
4228+
4229+ srcn = block_malloc(sizeof(dpkg_source_note));
4230+ if (srcn == NULL) die("save_empty_source_note alloc:");
4231+ assert(is_sources_note(srcsn));
4232+
4233+ srcn->source = src;
4234+ srcn->n_arches = 0;
4235+ srcn->binaries = NULL;
4236+
4237+ insert_source_note_list(where, srcn);
4238+}
4239+
4240+typedef enum { DO_ARCHALL = 0, SKIP_ARCHALL = 1 } do_this;
4241+static void remove_binaries_by_arch(dpkg_sources_note *srcsn,
4242+ dpkg_source_note *srcn, int archnum,
4243+ do_this arch_all)
4244+{
4245+ packagelist *p;
4246+ packagelist *leftovers = NULL, **addto = &leftovers;
4247+ assert(is_sources_note(srcsn));
4248+
4249+ assert(arch_all == SKIP_ARCHALL || NULL == lookup_sourcenotetbl(srcsn->sources,srcn->source->package));
4250+ /* if we're removing the entire binary, we should already have
4251+ * removed the source. if we're removing just the binaries on this
4252+ * arch (not arch:all) then we may be keeping the source
4253+ *
4254+ * really a logical XOR, I think. we don't rely on this assertion
4255+ * here
4256+ */
4257+
4258+ for (p = srcn->binaries[archnum]; p != NULL; p = p->next) {
4259+ dpkg_collected_package *cpkg;
4260+ if (arch_all == SKIP_ARCHALL && p->value->arch_all) {
4261+ insert_packagelist(addto, p->value);
4262+ addto = &(*addto)->next;
4263+ continue;
4264+ }
4265+ cpkg = lookup_packagetbl(srcsn->pkgs[archnum]->packages,
4266+ p->value->package);
4267+ remove_package(srcsn->pkgs[archnum], cpkg);
4268+ }
4269+ free_packagelist(srcn->binaries[archnum]);
4270+ srcn->binaries[archnum] = leftovers;
4271+}
4272+
4273+typedef enum { NOTUNDOABLE = 0, UNDOABLE = 1 } undoable;
4274+static void add_binaries_by_arch(dpkg_sources_note *srcsn,
4275+ dpkg_source_note *srcn, dpkg_source *src,
4276+ int archnum, undoable undoop, do_this arch_all)
4277+{
4278+ ownedpackagelist *p;
4279+ const char *archname = srcsn->archname[archnum];
4280+ int origarchnum = -1;
4281+ int i;
4282+
4283+ assert(is_sources_note(srcsn));
4284+ assert(srcn == lookup_sourcenotetbl(srcsn->sources,srcn->source->package));
4285+ for (i = 0; i < src->owner->n_arches; i++) {
4286+ if (strcmp(archname, src->owner->archname[i]) == 0) {
4287+ origarchnum = i;
4288+ break;
4289+ }
4290+ }
4291+ if (origarchnum == -1) return; /* nothing to add, no biggie */
4292+
4293+ for (p = src->packages[origarchnum]; p != NULL; p = p->next) {
4294+ dpkg_collected_package *cpkg;
4295+
4296+ if (arch_all == SKIP_ARCHALL && p->value->arch_all) continue;
4297+
4298+ if ((cpkg = lookup_packagetbl(srcsn->pkgs[archnum]->packages,
4299+ p->value->package)))
4300+ {
4301+ dpkg_source_note *srcnB;
4302+ packagelist **p;
4303+
4304+ if (!undoop) {
4305+ printf("conflict w/o undo: binary %s, owned by %s, replaced by %s\n", cpkg->pkg->package, cpkg->pkg->source, src->package);
4306+ fflush(stdout);
4307+ }
4308+ srcnB = lookup_sourcenotetbl(srcsn->sources, cpkg->pkg->source);
4309+ assert(srcnB != NULL);
4310+
4311+ for (p = &srcnB->binaries[archnum]; *p != NULL; p = &(*p)->next) {
4312+ if ((*p)->value == cpkg->pkg) break;
4313+ }
4314+ assert(*p != NULL); /* binary should be from source */
4315+
4316+ assert(undoop);
4317+ save_source_note(srcsn, srcnB);
4318+ remove_package(srcsn->pkgs[archnum], cpkg);
4319+ remove_packagelist(p);
4320+ }
4321+
4322+ add_package(srcsn->pkgs[archnum], p->value);
4323+ insert_packagelist(&srcn->binaries[archnum], p->value);
4324+ }
4325+}
4326+
4327+void upgrade_source(dpkg_sources_note *srcsn, dpkg_source *src) {
4328+ dpkg_source_note *srcn;
4329+ int i;
4330+
4331+ new_op(srcsn);
4332+
4333+ assert(is_sources_note(srcsn));
4334+ /* first, find the old source, if it exists */
4335+ srcn = remove_sourcenotetbl(srcsn->sources, src->package);
4336+ if (srcn != NULL) {
4337+ save_source_note(srcsn, srcn);
4338+ for (i = 0; i < srcn->n_arches; i++) {
4339+ remove_binaries_by_arch(srcsn, srcn, i, DO_ARCHALL);
4340+ }
4341+ free_source_note(srcn);
4342+ } else {
4343+ save_empty_source_note(srcsn, src);
4344+ }
4345+
4346+ /* then add the new one */
4347+ srcn = new_source_note(src, srcsn->n_arches);
4348+ add_sourcenotetbl(srcsn->sources, src->package, srcn);
4349+ for (i = 0; i < srcsn->n_arches; i++) {
4350+ add_binaries_by_arch(srcsn, srcn, src, i, UNDOABLE, DO_ARCHALL);
4351+ }
4352+ assert(is_sources_note(srcsn));
4353+}
4354+
4355+void upgrade_arch(dpkg_sources_note *srcsn, dpkg_source *src, char *arch) {
4356+ dpkg_source_note *srcn;
4357+ int archnum = -1;
4358+ int i;
4359+
4360+ assert(is_sources_note(srcsn));
4361+ /* first, find the old source */
4362+ srcn = lookup_sourcenotetbl(srcsn->sources, src->package);
4363+
4364+ assert(srcn != NULL);
4365+ new_op(srcsn);
4366+ save_source_note(srcsn, srcn);
4367+
4368+ /* then lookup the archnum */
4369+ for (i = 0; i < srcsn->n_arches; i++) {
4370+ if (strcmp(arch, srcsn->archname[i]) == 0) {
4371+ archnum = i;
4372+ break;
4373+ }
4374+ }
4375+ if (archnum == -1) die("upgrade_arch: unknown arch");
4376+
4377+ /* then remove the old stuff and add the new */
4378+ remove_binaries_by_arch(srcsn, srcn, archnum, SKIP_ARCHALL);
4379+ add_binaries_by_arch(srcsn, srcn, src, archnum, UNDOABLE, SKIP_ARCHALL);
4380+ assert(is_sources_note(srcsn));
4381+}
4382+
4383+void remove_source(dpkg_sources_note *srcsn, char *name) {
4384+ dpkg_source_note *srcn;
4385+ int i;
4386+
4387+ assert(is_sources_note(srcsn));
4388+ srcn = remove_sourcenotetbl(srcsn->sources, name);
4389+ assert(srcn != NULL);
4390+
4391+ new_op(srcsn);
4392+ save_source_note(srcsn, srcn);
4393+ for (i = 0; i < srcn->n_arches; i++) {
4394+ remove_binaries_by_arch(srcsn, srcn, i, DO_ARCHALL);
4395+ }
4396+ free_source_note(srcn);
4397+ assert(is_sources_note(srcsn));
4398+}
4399+
4400+int can_undo(dpkg_sources_note *srcsn) {
4401+ assert(is_sources_note(srcsn));
4402+ return srcsn->undo != NULL;
4403+}
4404+
4405+void undo_change(dpkg_sources_note *srcsn) {
4406+ dpkg_source_note *srcnO, *srcnC; /* old, current */
4407+ source_note_list *srcnl;
4408+ int i;
4409+
4410+ assert(is_sources_note(srcsn));
4411+ assert(can_undo(srcsn));
4412+
4413+ srcnl = remove_source_note_listlist(&srcsn->undo);
4414+
4415+ while(srcnl) {
4416+ srcnO = remove_source_note_list(&srcnl);
4417+ assert(srcnO != NULL); /* can_undo() implies this is true... */
4418+
4419+ srcnC = remove_sourcenotetbl(srcsn->sources, srcnO->source->package);
4420+ if (srcnC != NULL) {
4421+ for (i = 0; i < srcnC->n_arches; i++) {
4422+ remove_binaries_by_arch(srcsn, srcnC, i, DO_ARCHALL);
4423+ }
4424+ free_source_note(srcnC);
4425+ assert(!lookup_sourcenotetbl(srcsn->sources,
4426+ srcnO->source->package));
4427+ }
4428+
4429+ if (srcnO->binaries == NULL) {
4430+ /* no original source */
4431+ assert(srcnC != NULL); /* some sort of no-op? freaky. */
4432+ free_source_note(srcnO);
4433+ } else {
4434+ packagelist *p;
4435+ /* original source */
4436+ add_sourcenotetbl(srcsn->sources, srcnO->source->package, srcnO);
4437+ for (i = 0; i < srcsn->n_arches; i++) {
4438+ for (p = srcnO->binaries[i]; p != NULL; p = p->next) {
4439+ add_package(srcsn->pkgs[i], p->value);
4440+ }
4441+ }
4442+ }
4443+ }
4444+}
4445+
4446+LIST_IMPL(source_note_list, dpkg_source_note *, free_source_note,
4447+ block_malloc, block_free);
4448+LIST_IMPL(source_note_listlist, source_note_list *, free_source_note_list,
4449+ block_malloc, block_free);
4450+
4451+void commit_changes(dpkg_sources_note *srcsn) {
4452+ assert(is_sources_note(srcsn));
4453+ free_source_note_listlist(srcsn->undo);
4454+ srcsn->undo = NULL;
4455+}
4456+
4457+dpkg_source_note *copy_source_note(dpkg_source_note *srcn) {
4458+ dpkg_source_note *srcn2;
4459+ packagelist *src, **dest;
4460+ int i;
4461+
4462+ assert(srcn->binaries != NULL);
4463+
4464+ srcn2 = block_malloc(sizeof(dpkg_source_note));
4465+ if (srcn2 == NULL) die("copy_source_note alloc:");
4466+
4467+ srcn2->source = srcn->source;
4468+ srcn2->n_arches = srcn->n_arches;
4469+ srcn2->binaries = block_malloc(sizeof(packagenamelist*) * srcn2->n_arches);
4470+ if (srcn2->binaries == NULL) die("copy_source_note alloc:");
4471+
4472+ for (i = 0; i < srcn2->n_arches; i++) {
4473+ dest = &(srcn2->binaries[i]);
4474+ *dest = NULL;
4475+ for (src = srcn->binaries[i]; src; src = src->next) {
4476+ insert_packagelist(dest, src->value);
4477+ dest = &((*dest)->next);
4478+ }
4479+ }
4480+
4481+ return srcn2;
4482+}
4483+
4484+void write_notes(char *dir, dpkg_sources_note *srcsn) {
4485+ FILE *src;
4486+ FILE *archfile[100];
4487+ char buf[1000];
4488+ int i;
4489+ sourcenotetbl_iter srciter;
4490+
4491+ assert(is_sources_note(srcsn));
4492+ snprintf(buf, 1000, "%s/Sources", dir);
4493+ src = fopen(buf, "w");
4494+ for (i = 0; i < srcsn->n_arches; i++) {
4495+ snprintf(buf, 1000, "%s/Packages_%s", dir, srcsn->archname[i]);
4496+ archfile[i] = fopen(buf, "w");
4497+ }
4498+
4499+ for (srciter = first_sourcenotetbl(srcsn->sources);
4500+ !done_sourcenotetbl(srciter);
4501+ srciter = next_sourcenotetbl(srciter))
4502+ {
4503+ packagelist *p;
4504+ int i;
4505+
4506+ if (!srciter.v->source->fake)
4507+ write_paragraph(src, srciter.v->source->details);
4508+
4509+ for (i = 0; i < srcsn->n_arches; i++) {
4510+ for (p = srciter.v->binaries[i]; p != NULL; p = p->next) {
4511+ write_paragraph(archfile[i], p->value->details);
4512+ }
4513+ }
4514+ }
4515+
4516+ fclose(src);
4517+ for (i = 0; i < srcsn->n_arches; i++) {
4518+ fclose(archfile[i]);
4519+ }
4520+}
4521+
4522
4523=== added file 'update_out/dpkg.h'
4524--- update_out/dpkg.h 1970-01-01 00:00:00 +0000
4525+++ update_out/dpkg.h 2020-03-12 14:58:23 +0000
4526@@ -0,0 +1,207 @@
4527+#ifndef DPKG_H
4528+#define DPKG_H
4529+
4530+#include "templates.h"
4531+#include "memory.h"
4532+
4533+#include <stdio.h>
4534+
4535+/**************************************************************************
4536+ * Coping with an rfc822-esque field
4537+ */
4538+
4539+typedef struct dpkg_entry dpkg_entry;
4540+struct dpkg_entry {
4541+ char *name;
4542+ char *value;
4543+};
4544+
4545+typedef struct dpkg_paragraph dpkg_paragraph;
4546+struct dpkg_paragraph {
4547+ int n_entries;
4548+ int n_allocated;
4549+ dpkg_entry *entry;
4550+};
4551+
4552+/**************************************************************************
4553+ * Coping with a package (or many pkgs) as an abstract entity
4554+ */
4555+
4556+typedef enum {dr_NOOP,dr_LT,dr_LTEQ,dr_EQ,dr_GTEQ,dr_GT} dependency_relation;
4557+extern char *dependency_relation_sym[];
4558+
4559+typedef struct dependency dependency;
4560+struct dependency {
4561+ char *package;
4562+ dependency_relation op;
4563+ char *version;
4564+};
4565+
4566+LIST(deplist, dependency*);
4567+LIST(deplistlist, deplist*);
4568+
4569+LIST(packagenamelist, char*);
4570+LIST(ownedpackagenamelist, char*);
4571+
4572+typedef struct dpkg_package dpkg_package;
4573+
4574+struct dpkg_package {
4575+ char *package;
4576+ char *version;
4577+
4578+ char *source;
4579+ char *source_ver;
4580+
4581+ int priority;
4582+
4583+ int arch_all;
4584+
4585+ deplistlist *depends[4];
4586+ deplist *conflicts;
4587+ ownedpackagenamelist *provides;
4588+
4589+ dpkg_paragraph *details;
4590+};
4591+
4592+LIST(packagelist, dpkg_package *);
4593+LIST(ownedpackagelist, dpkg_package *);
4594+
4595+typedef struct satisfieddep satisfieddep;
4596+
4597+struct satisfieddep {
4598+ /* dependency *dep; */
4599+ deplist *depl;
4600+ packagelist *pkgs;
4601+};
4602+
4603+LIST(satisfieddeplist, satisfieddep *);
4604+
4605+/**************************************************************************
4606+ * Coping with a source package (and collections thereof) as an abstract
4607+ * entity, owning a bunch of binary packages
4608+ */
4609+
4610+typedef struct dpkg_source dpkg_source;
4611+struct dpkg_source {
4612+ char *package;
4613+ char *version;
4614+
4615+ int fake;
4616+
4617+ struct dpkg_sources *owner;
4618+ ownedpackagelist **packages; /* one for each architecture */
4619+
4620+ dpkg_paragraph *details;
4621+};
4622+
4623+HASH(sourcetbl,char *,dpkg_source *);
4624+
4625+typedef struct dpkg_sources dpkg_sources;
4626+struct dpkg_sources {
4627+ int n_arches;
4628+ char **archname;
4629+ sourcetbl *sources;
4630+ ownedpackagelist **unclaimedpackages; /* one for each arch */
4631+};
4632+
4633+/**************************************************************************
4634+ */
4635+
4636+typedef struct dpkg_collected_package dpkg_collected_package;
4637+struct dpkg_collected_package {
4638+ dpkg_package *pkg;
4639+
4640+ int installed, conflicted;
4641+
4642+ enum { UNKNOWN, YES } installable;
4643+ packagenamelist *mayaffect;
4644+
4645+ /* on update, the installability_checked of each /mayaffect/ed package
4646+ * is cleared, and the mayaffect list is cleared.
4647+ *
4648+ * note that installable = NO couldn't be maintained over adding a package
4649+ * to testing. installable = YES can be, thanks to the mayaffect list
4650+ * (once a package is removed, everything it mayaffect must be set back
4651+ * to unknown, but everything else is okay)
4652+ */
4653+};
4654+
4655+LIST(collpackagelist, dpkg_collected_package *);
4656+
4657+/**************************************************************************
4658+ */
4659+
4660+typedef struct dpkg_provision dpkg_provision;
4661+struct dpkg_provision {
4662+ char *version;
4663+ dpkg_collected_package *pkg;
4664+};
4665+
4666+LIST(virtualpkg, dpkg_provision);
4667+
4668+HASH(virtualpkgtbl,char *,virtualpkg *);
4669+HASH(packagetbl,char *,dpkg_collected_package *);
4670+
4671+typedef struct dpkg_packages dpkg_packages;
4672+struct dpkg_packages {
4673+ char *arch;
4674+ packagetbl *packages;
4675+ virtualpkgtbl *virtualpkgs;
4676+};
4677+
4678+typedef struct dpkg_source_note dpkg_source_note;
4679+struct dpkg_source_note {
4680+ dpkg_source *source; /* unowned */
4681+ int n_arches;
4682+ packagelist **binaries; /* one for each arch */
4683+};
4684+HASH(sourcenotetbl, char *, dpkg_source_note *);
4685+
4686+LIST(source_note_list, dpkg_source_note *);
4687+ /* contains a copy of the previous source_note */
4688+LIST(source_note_listlist, source_note_list *);
4689+ /* contains a copy of all the source_notes modified by the last op */
4690+
4691+typedef struct dpkg_sources_note dpkg_sources_note;
4692+struct dpkg_sources_note {
4693+ unsigned long magic;
4694+ sourcenotetbl *sources;
4695+ int n_arches;
4696+ dpkg_packages **pkgs;
4697+ char **archname;
4698+
4699+ source_note_listlist *undo;
4700+};
4701+
4702+void free_packages(dpkg_packages *pkgs);
4703+void free_sources(dpkg_sources *s);
4704+
4705+dpkg_packages *get_architecture(dpkg_sources *srcs, char *arch);
4706+
4707+/* parsing things */
4708+int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof);
4709+int checkinstallable2(dpkg_packages *pkgs, char *pkgname);
4710+satisfieddeplist *checkunsatisfiabledeps(dpkg_packages *pkgs,
4711+ deplistlist *deps);
4712+
4713+dpkg_sources *read_directory(char *dir, int n_arches, char *archname[]);
4714+void write_directory(char *dir, dpkg_sources *srcs);
4715+
4716+void free_source(dpkg_source *s);
4717+
4718+/* adding and deleting and stuff */
4719+dpkg_sources_note *new_sources_note(int n_arches, char **archname);
4720+void remove_source(dpkg_sources_note *srcsn, char *name);
4721+void upgrade_source(dpkg_sources_note *srcsn, dpkg_source *src);
4722+void upgrade_arch(dpkg_sources_note *srcsn, dpkg_source *src, char *arch);
4723+void write_notes(char *dir, dpkg_sources_note *srcsn);
4724+void free_sources_note(dpkg_sources_note *srcsn);
4725+void free_source_note(dpkg_source_note *srcn);
4726+void undo_change(dpkg_sources_note *srcsn);
4727+int can_undo(dpkg_sources_note *srcsn);
4728+void commit_changes(dpkg_sources_note *srcsn);
4729+
4730+int versioncmp(char *left, char *right);
4731+int cmpversions(char *left, int op, char *right);
4732+
4733+#endif
4734
4735=== added file 'update_out/freelist.c'
4736--- update_out/freelist.c 1970-01-01 00:00:00 +0000
4737+++ update_out/freelist.c 2020-03-12 14:58:23 +0000
4738@@ -0,0 +1,188 @@
4739+#include <stdio.h>
4740+#include <stdlib.h>
4741+#include "templates.h"
4742+
4743+typedef unsigned long ul;
4744+
4745+#define SIZE (sizeof(ul) * 8)
4746+#define ROUND_DOWN(x) ((x) & ~(SIZE-1))
4747+#define ROUND_UP(x) ROUND_DOWN((x) + (SIZE-1))
4748+#define NEXT_UP(x) ROUND_DOWN((x) + SIZE)
4749+#define NEXT_DOWN(x) ROUND_DOWN((x) - 1)
4750+
4751+#define SETBIT(s,p) \
4752+ assert( (bits[(s)/SIZE] & (p)) == (setp ? 0 : (p)) ); \
4753+ if (setp) bits[(s)/SIZE] |= (p); \
4754+ else bits[(s)/SIZE] &= ~(p)
4755+
4756+#define GETBIT(s) (bits[ROUND_DOWN(s)/SIZE] & (1ul << (NEXT_UP(s) - s - 1)))
4757+
4758+size_t count_free_bits_back(ul *bits, size_t s) {
4759+ size_t cnt = 0;
4760+ ul w = ROUND_DOWN(s) / SIZE;
4761+ size_t add = s % SIZE;
4762+ ul off = (~0ul) << (SIZE - add);
4763+ ul H, d;
4764+
4765+ while ((bits[w] & off) == 0) {
4766+ cnt += add;
4767+ add = SIZE;
4768+ off = ~0ul;
4769+ if (w == 0)
4770+ return cnt;
4771+ w--;
4772+ }
4773+
4774+ H = add;
4775+ add = 0;
4776+ while ((d = (H - add) / 2) > 0) {
4777+ ul offM = (off >> d) & off;
4778+ if (bits[w] & offM) {
4779+ off = offM;
4780+ H = H - d;
4781+ } else {
4782+ add = H - d;
4783+ }
4784+ }
4785+ cnt += add;
4786+ return cnt;
4787+}
4788+
4789+size_t count_free_bits_after(ul *bits, size_t s, size_t end) {
4790+ size_t cnt = 0;
4791+ ul w = ROUND_DOWN(s) / SIZE;
4792+ size_t add = SIZE - s % SIZE;
4793+ ul off = (~0ul) >> (SIZE - add);
4794+ ul H, d;
4795+
4796+ end /= SIZE;
4797+
4798+ while ((bits[w] & off) == 0) {
4799+ cnt += add;
4800+ add = SIZE;
4801+ off = ~0ul;
4802+ w++;
4803+ if (w == end)
4804+ return cnt;
4805+ }
4806+
4807+ H = add;
4808+ add = 0;
4809+ while ((d = (H - add) / 2) > 0) {
4810+ ul offM = off << d;
4811+ if (bits[w] & offM) {
4812+ off = offM;
4813+ H = H - d;
4814+ } else {
4815+ add = H - d;
4816+ }
4817+ }
4818+ cnt += add;
4819+ return cnt;
4820+}
4821+
4822+void find_long_freebits(ul *bits, size_t s, ul *start, size_t *size) {
4823+ ul clen = 0;
4824+ ul bstart = 0, blen = 0;
4825+ ul i, k;
4826+
4827+ for (i = 0; i < s; i++) {
4828+ if (bits[i] == 0) {
4829+ clen++;
4830+ } else {
4831+ if (clen > blen) {
4832+ bstart = i - clen;
4833+ blen = clen;
4834+ }
4835+ clen = 0;
4836+ }
4837+ }
4838+
4839+ if (blen == 0) return;
4840+
4841+ bstart *= SIZE; blen *= SIZE;
4842+ k = count_free_bits_back(bits, bstart);
4843+ bstart -= k; blen += k;
4844+
4845+ blen += count_free_bits_after(bits, bstart + blen, s*SIZE);
4846+
4847+ *start = bstart; *size = blen;
4848+}
4849+
4850+void mark_bits(ul *bits, ul s, size_t size, int setp) {
4851+ ul e = s+size;
4852+
4853+ ul rds = ROUND_DOWN(s);
4854+ ul nus = rds + SIZE;
4855+ ul rue = ROUND_UP(e);
4856+
4857+ ul patl = (~0UL) >> (s % SIZE);
4858+ ul patr = (~0UL) << (rue - e);
4859+
4860+ assert(size > 0);
4861+
4862+ /* bits[s1..e1] get touched, but bits[s1], bits[e1] only partially
4863+ *
4864+ * if s1 == e1, then bits[s1] get touched from [s%SIZE, e%SIZE)
4865+ * else
4866+ * bits[s1] gets touched from [s%SIZE, SIZE)
4867+ * bits[s2..e1) get reset completely
4868+ * bits[e1] gets touched from [0, e%SIZE)
4869+ */
4870+
4871+ if (nus >= e) {
4872+ /* ROUND_DOWN(s) <= s < e <= NEXT_UP(s) */
4873+ SETBIT(rds, patl & patr);
4874+ } else {
4875+ /* ROUND_DOWN(s) <= s < NEXT_UP(s) <= NEXT_DOWN(e) < e */
4876+ ul rde = ROUND_DOWN(e);
4877+
4878+ SETBIT(rds, patl);
4879+ SETBIT(rde, patr);
4880+ while (nus < rde) {
4881+ SETBIT(nus, ~0UL);
4882+ nus += SIZE;
4883+ }
4884+ }
4885+}
4886+
4887+void print_bits(ul *bits, ul s) {
4888+ ul i;
4889+ putchar(' ');
4890+ for (i = 0; i < s * SIZE; i++) {
4891+ putchar( GETBIT(i) ? '1' : '0' );
4892+ }
4893+}
4894+
4895+#ifdef TESTBIN
4896+
4897+#define X 2
4898+int main(void) {
4899+ ul memory[X];
4900+ ul l, r;
4901+ ul k = 5;
4902+
4903+ memset(memory, 0, sizeof(memory));
4904+ for (l = 0; l < X*SIZE; l += k) {
4905+ for (r = 1; l+(r*r) < X*SIZE; r++) {
4906+
4907+ printf("%lu %lu (%lu %lu", l, r*r,
4908+ (unsigned long) count_free_bits_back(memory, X*SIZE), (unsigned long) X*SIZE);
4909+ mark_bits(memory, l, r*r, 1);
4910+ printf("; %lu %lu %lu; %lu %lu %lu;): ",
4911+ (unsigned long) count_free_bits_back(memory, X*SIZE) + l + r*r,
4912+ (unsigned long) count_free_bits_after(memory, l + r*r, X*SIZE) + l + r*r,
4913+ (unsigned long) X*SIZE,
4914+ (unsigned long) count_free_bits_back(memory, l),
4915+ (unsigned long) count_free_bits_after(memory, 0, X*SIZE),
4916+ l);
4917+ print_bits(memory, X);
4918+ printf("\n");
4919+
4920+ mark_bits(memory, l, r*r, 0);
4921+ }
4922+ }
4923+
4924+ return 0;
4925+}
4926+#endif
4927
4928=== added file 'update_out/freelist.h'
4929--- update_out/freelist.h 1970-01-01 00:00:00 +0000
4930+++ update_out/freelist.h 2020-03-12 14:58:23 +0000
4931@@ -0,0 +1,14 @@
4932+
4933+#ifndef FREELIST_H
4934+#define FREELIST_H
4935+
4936+#include <stdlib.h>
4937+
4938+typedef unsigned long flb_t;
4939+
4940+void mark_bits(flb_t *bits, flb_t s, size_t size, int setp);
4941+size_t count_free_bits_back(flb_t *bits, size_t s);
4942+size_t count_free_bits_after(flb_t *bits, size_t s, size_t end);
4943+void find_long_freebits(flb_t *bits, flb_t s, flb_t *start, size_t *size);
4944+
4945+#endif
4946
4947=== added file 'update_out/index.html'
4948--- update_out/index.html 1970-01-01 00:00:00 +0000
4949+++ update_out/index.html 2020-03-12 14:58:23 +0000
4950@@ -0,0 +1,18 @@
4951+<a href="README">README</a><br>
4952+<a href="Makefile">Makefile</a><br>
4953+<a href="assert.c">assert.c</a><br>
4954+<a href="britney-py.c">britney-py.c</a><br>
4955+<a href="checklib.c">checklib.c</a><br>
4956+<a href="dpkg.c">dpkg.c</a><br>
4957+<a href="freelist.c">freelist.c</a><br>
4958+<a href="memory.c">memory.c</a><br>
4959+<a href="memory2.c">memory2.c</a><br>
4960+<a href="memory3.c">memory3.c</a><br>
4961+<a href="dpkg-lib.cpp">dpkg-lib.cpp</a><br>
4962+<a href="dpkg.h">dpkg.h</a><br>
4963+<a href="freelist.h">freelist.h</a><br>
4964+<a href="memory.h">memory.h</a><br>
4965+<a href="templates.h">templates.h</a><br>
4966+<a href="check_out.py">check_out.py</a><br>
4967+<a href="check_uptodate.py">check_uptodate.py</a><br>
4968+<a href="update_out.py">update_out.py</a><br>
4969
4970=== added file 'update_out/memory.c'
4971--- update_out/memory.c 1970-01-01 00:00:00 +0000
4972+++ update_out/memory.c 2020-03-12 14:58:23 +0000
4973@@ -0,0 +1,389 @@
4974+#include <stdio.h>
4975+#include <stdlib.h>
4976+
4977+#include "memory.h"
4978+#include "templates.h"
4979+#include "freelist.h"
4980+
4981+/**** THEORY
4982+ *
4983+
4984+So, we have blocks with a freelist
4985+
4986+ XXX............XXXXXXX..XXXXX.....XXXXXX......
4987+
4988+Within a block, we work with segments. A segment is...
4989+
4990+ ^..........|
4991+
4992+Every now and then we make sure we've got a decent sized segment.
4993+
4994+We have multiple blocks. They're kept ordered by the size of their
4995+current segment.
4996+
4997+ **********************************************/
4998+
4999+#define ALIGN 4
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: