Merge lp:~cjwatson/britney/fix-sru-branching into lp:britney

Proposed by Colin Watson
Status: Superseded
Proposed branch: lp:~cjwatson/britney/fix-sru-branching
Merge into: lp:britney
Diff against target: 7295 lines (+7146/-0) (has conflicts)
28 files modified
README (+107/-0)
britney (+516/-0)
fauxpkg/FauxPackages (+59/-0)
fauxpkg/README (+50/-0)
fauxpkg/fauxpkg.py (+181/-0)
fauxpkg/noremove.d/README (+3/-0)
scripts/backlog-report (+86/-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)
Text conflict in README
To merge this branch: bzr merge lp:~cjwatson/britney/fix-sru-branching
Reviewer Review Type Date Requested Status
Ubuntu Package Archive Administrators Pending
Review via email: mp+261537@code.launchpad.net

This proposal has been superseded by a proposal from 2015-06-09.

Commit message

Make sure the hints branch always points to the right place, even if it's changed due to e.g. a series being released.

Description of the change

Make sure the hints branch always points to the right place, even if it's changed due to e.g. a series being released.

To post a comment you must log in.

Unmerged revisions

281. By Colin Watson

Make sure the hints branch always points to the right place, even if it's changed due to e.g. a series being released.

280. By Adam Conrad

vivid -> wily

279. By Iain Lane

merge lp:~cjwatson/britney/dynamic-arches

278. By Steve Langasek

Merge lp:~cjwatson/britney/sru-lock

277. By Steve Langasek

Merge lp:~cjwatson/britney/honour-updates

276. By Steve Langasek

Merge lp:~cjwatson/britney/fix-blocks-function

275. By Steve Langasek

Merge lp:~cjwatson/britney/more-output-prefix

274. By Steve Langasek

Merge lp:~cjwatson/britney/output-prefix

273. By Steve Langasek

Merge lp:~cjwatson/britney/sru-config

272. By Colin Watson

Publish update_excuses.yaml and archive copies of it.

Preview Diff

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

Subscribers

People subscribed via source and target branches

to all changes: