diff -Nru dpkg-1.18.4ubuntu1/debian/changelog dpkg-1.18.4ubuntu1.7/debian/changelog --- dpkg-1.18.4ubuntu1/debian/changelog 2016-01-12 21:33:35.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/debian/changelog 2019-12-05 17:03:22.000000000 +0000 @@ -1,3 +1,65 @@ +dpkg (1.18.4ubuntu1.7) xenial; urgency=medium + + * Cherry-pick an Ubuntu-specific patch applied to 1.18.23ubuntu1 to + mask ABI bits in flags for ARM (Closes: #853793) + + -- Olivier Tilloy Thu, 05 Dec 2019 18:03:22 +0100 + +dpkg (1.18.4ubuntu1.6) xenial; urgency=medium + + * Cherry-pick upstream fixes for trigger loops (LP: #1828639) + - dpkg: Negate tortoise_not_in_hare() function name and return value + - dpkg: Initialize trigcyclenode's next member once + - dpkg: Factor trigproc_new_cyclenode() out from check_trigger_cycle() + - dpkg: Mark the package we are giving up on a trigger cycle as istobe normal + - dpkg: Switch dependtry from an int to an enum + - dpkg: Reset progress_bytrigproc once we have injected into the current iteration + - dpkg: Split trigger processing types into required, try-queued and try-deferred + - dpkg: Convert one trigger processing required type into the new try-queued + - dpkg: Move trigproc cycle reset inside try-deferred conditional + - dpkg: Introduce a new dependency try level for trigger processing + - dpkg: Introduce a new dependency try level for trigger cycle checks + + -- Julian Andres Klode Tue, 16 Jul 2019 14:57:11 +0200 + +dpkg (1.18.4ubuntu1.5) xenial; urgency=medium + + * Apply patch from upstream to add frontend locking (LP: #1796081): + - Add support for frontend locking. This makes it possible for frontends + using this new protocol, to safely lock the dpkg database w/o risk of + race conditions with other dpkg instances or frontends supporting the + same protocol. + + -- Julian Andres Klode Thu, 04 Oct 2018 14:21:49 +0200 + +dpkg (1.18.4ubuntu1.4) xenial; urgency=medium + + * Cherry-pick d01212f2d7e59fc713c66b5d60421ac2296c1463 from 1.18.5: + - Allow detached upstream orig tarball signatures when extracting + version 1.0 non-native source packages (LP: #1751114) + + -- Adam Conrad Wed, 14 Mar 2018 13:17:08 -0600 + +dpkg (1.18.4ubuntu1.3) xenial; urgency=medium + + * Use ohshit() instead of internerr() for unhandled dpkg-split exit + codes. (i.e. do not abort). Closes: #812679, LP: #1601998 + + -- Brian Murray Fri, 20 Oct 2017 16:14:06 -0700 + +dpkg (1.18.4ubuntu1.2) xenial; urgency=medium + + * Cherry-pick patch from git to limit preallocation to files over + 16KiB, fixing installation performance regression (LP: #1663749) + + -- Adam Conrad Mon, 10 Apr 2017 04:08:19 -0600 + +dpkg (1.18.4ubuntu1.1) xenial; urgency=medium + + * Add Breaks on ufw (<< 0.35-0ubuntu2~) for trigger loops (LP: #1571174) + + -- Adam Conrad Thu, 12 May 2016 04:35:55 -0600 + dpkg (1.18.4ubuntu1) xenial; urgency=medium * Merge from Debian testing; remaining changes in the Ubuntu delta: diff -Nru dpkg-1.18.4ubuntu1/debian/control dpkg-1.18.4ubuntu1.7/debian/control --- dpkg-1.18.4ubuntu1/debian/control 2016-01-12 21:24:14.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/debian/control 2019-07-16 12:57:11.000000000 +0000 @@ -66,6 +66,7 @@ pypy (<< 2.4.0+dfsg-3~), readahead-fedora (<< 2:1.5.6-5.2~), software-center (<< 13.10-0ubuntu9~), + ufw (<< 0.35-0ubuntu2~), ureadahead (<< 0.100.0-17~), wordpress (<< 4.1+dfsg-1~), xfonts-traditional (<< 1.7~), diff -Nru dpkg-1.18.4ubuntu1/doc/frontend.txt dpkg-1.18.4ubuntu1.7/doc/frontend.txt --- dpkg-1.18.4ubuntu1/doc/frontend.txt 2015-11-25 21:45:14.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/doc/frontend.txt 2019-07-16 12:57:11.000000000 +0000 @@ -10,15 +10,15 @@ ---------------- Any frontend needing to make sure no write operation is currently happening, -should lock the dpkg database by locking the file «/lock» using -file record locks (i.e. fcntl(2) advisory locking). The whole file should -be locked, as that's the most portable way to perform this operation; this -can be achieved by using start=0, len=0 and whence=SEEK_SET. +and no other frontend is running should first acquire the frontend lock at +«/lock-frontend», and then acquire the dpkg database lock at +«/lock». When the frontend invokes dpkg, it should set the +environment variable DPKG_FRONTEND_LOCKED (to prevent dpkg from acquiring +the frontend lock), and then release the dpkg database lock, which will be +acquired by dpkg itself. This way no other frontend following this protocol +can race to perform operations while another one has one in progress. -Take into account there will be a race condition between the frontend -unlocking the database and the invoked dpkg locking it again, in which -another process could lock it. - -In the future this functionality will be available through a shared libdpkg -library, and all frontends will be expected to switch to that instead, -because this will fix the aforementioned race condition. +These locks must be file record locks (i.e. fcntl(2) advisory locking), and +the whole file should be locked, as that's the most portable way to perform +this operation; this can be achieved by using start=0, len=0 and +whence=SEEK_SET. diff -Nru dpkg-1.18.4ubuntu1/lib/dpkg/dbmodify.c dpkg-1.18.4ubuntu1.7/lib/dpkg/dbmodify.c --- dpkg-1.18.4ubuntu1/lib/dpkg/dbmodify.c 2015-11-26 23:53:36.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/lib/dpkg/dbmodify.c 2019-07-16 12:57:11.000000000 +0000 @@ -51,6 +51,7 @@ static enum modstatdb_rw cstatus=-1, cflags=0; static char *lockfile; +static char *frontendlockfile; static char *statusfile, *availablefile; static char *importanttmpfile=NULL; static FILE *importanttmp; @@ -140,6 +141,7 @@ char **store; } fnis[] = { { LOCKFILE, &lockfile }, + { FRONTENDLOCKFILE, &frontendlockfile }, { STATUSFILE, &statusfile }, { AVAILFILE, &availablefile }, { UPDATESDIR, &updatesdir }, @@ -185,6 +187,7 @@ } static int dblockfd = -1; +static int frontendlockfd = -1; bool modstatdb_is_locked(void) @@ -216,6 +219,18 @@ if (dblockfd >= 0) return true; + if (getenv("DPKG_FRONTEND_LOCKED") == NULL) { + frontendlockfd = open(frontendlockfile, O_RDWR | O_CREAT | O_TRUNC, 0660); + if (frontendlockfd == -1) { + if (errno == EACCES || errno == EPERM) + return false; + else + ohshite(_("unable to open/create frontend lockfile")); + } + } else { + frontendlockfd = -1; + } + dblockfd = open(lockfile, O_RDWR | O_CREAT | O_TRUNC, 0660); if (dblockfd == -1) { if (errno == EACCES || errno == EPERM) @@ -233,6 +248,9 @@ if (!modstatdb_can_lock()) ohshit(_("you do not have permission to lock the dpkg status database")); + if (frontendlockfd != -1) + file_lock(&frontendlockfd, FILE_LOCK_NOWAIT, frontendlockfile, + _("dpkg frontend")); file_lock(&dblockfd, FILE_LOCK_NOWAIT, lockfile, _("dpkg status database")); } @@ -241,8 +259,11 @@ { /* Unlock. */ pop_cleanup(ehflag_normaltidy); + if (frontendlockfd != -1) + pop_cleanup(ehflag_normaltidy); dblockfd = -1; + frontendlockfd = -1; } enum modstatdb_rw diff -Nru dpkg-1.18.4ubuntu1/lib/dpkg/dpkg.h dpkg-1.18.4ubuntu1.7/lib/dpkg/dpkg.h --- dpkg-1.18.4ubuntu1/lib/dpkg/dpkg.h 2015-12-12 20:49:24.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/lib/dpkg/dpkg.h 2019-07-16 12:57:11.000000000 +0000 @@ -76,6 +76,7 @@ #define STATUSFILE "status" #define AVAILFILE "available" #define LOCKFILE "lock" +#define FRONTENDLOCKFILE "lock-frontend" #define DIVERSIONSFILE "diversions" #define STATOVERRIDEFILE "statoverride" #define UPDATESDIR "updates/" diff -Nru dpkg-1.18.4ubuntu1/lib/dpkg/fdio.c dpkg-1.18.4ubuntu1.7/lib/dpkg/fdio.c --- dpkg-1.18.4ubuntu1/lib/dpkg/fdio.c 2015-11-26 23:51:59.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/lib/dpkg/fdio.c 2019-07-16 12:57:11.000000000 +0000 @@ -102,7 +102,9 @@ { int rc; - if (len == 0) + /* Do not preallocate on very small files as that degrades performance + * on some filesystems. */ + if (len < (4 * 4096) - 1) return 0; #if defined(HAVE_F_PREALLOCATE) diff -Nru dpkg-1.18.4ubuntu1/man/dpkg.1 dpkg-1.18.4ubuntu1.7/man/dpkg.1 --- dpkg-1.18.4ubuntu1/man/dpkg.1 2015-12-25 03:53:50.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/man/dpkg.1 2019-07-16 12:57:11.000000000 +0000 @@ -817,6 +817,10 @@ .B COLUMNS Sets the number of columns \fBdpkg\fP should use when displaying formatted text. Currently only used by \-l. +.TP +.B DPKG_FRONTEND_LOCKED +Set by a package manager frontend to notify dpkg that it should not acquire +the frontend lock (since dpkg 1.19.1). .SS Internal environment .TP .B DPKG_SHELL_REASON diff -Nru dpkg-1.18.4ubuntu1/scripts/Dpkg/Shlibs/Objdump.pm dpkg-1.18.4ubuntu1.7/scripts/Dpkg/Shlibs/Objdump.pm --- dpkg-1.18.4ubuntu1/scripts/Dpkg/Shlibs/Objdump.pm 2016-01-12 21:24:14.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/scripts/Dpkg/Shlibs/Objdump.pm 2019-12-05 17:02:44.000000000 +0000 @@ -93,11 +93,11 @@ to_pipe => \$output, %opts); while (<$output>) { chomp; - if (/0x5000402/) { + if (/0x500040./) { $hf = 1; last; } - if (/0x5000202/) { + if (/0x500020./) { $sf = 1; last; } diff -Nru dpkg-1.18.4ubuntu1/scripts/Dpkg/Source/Package/V1.pm dpkg-1.18.4ubuntu1.7/scripts/Dpkg/Source/Package/V1.pm --- dpkg-1.18.4ubuntu1/scripts/Dpkg/Source/Package/V1.pm 2015-11-26 23:53:39.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/scripts/Dpkg/Source/Package/V1.pm 2019-07-16 12:57:11.000000000 +0000 @@ -104,10 +104,13 @@ # V1.0 only supports gzip compression my ($tarfile, $difffile); + my $tarsign; foreach my $file ($self->get_files()) { if ($file =~ /^(?:\Q$basename\E\.orig|\Q$basenamerev\E)\.tar\.gz$/) { error(g_('multiple tarfiles in v1.0 source package')) if $tarfile; $tarfile = $file; + } elsif ($file =~ /^\Q$basename\E\.orig\.tar\.gz\.asc$/) { + $tarsign = $file; } elsif ($file =~ /^\Q$basenamerev\E\.diff\.gz$/) { $difffile = $file; } else { diff -Nru dpkg-1.18.4ubuntu1/src/configure.c dpkg-1.18.4ubuntu1.7/src/configure.c --- dpkg-1.18.4ubuntu1/src/configure.c 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/configure.c 2019-07-16 12:57:11.000000000 +0000 @@ -598,7 +598,7 @@ vdew_nonambig)); } - if (dependtry > 1) + if (dependtry >= DEPEND_TRY_CYCLES) if (findbreakcycle(pkg)) sincenothing = 0; diff -Nru dpkg-1.18.4ubuntu1/src/main.h dpkg-1.18.4ubuntu1.7/src/main.h --- dpkg-1.18.4ubuntu1/src/main.h 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/main.h 2019-07-16 12:57:11.000000000 +0000 @@ -218,7 +218,53 @@ void deferred_remove(struct pkginfo *pkg); void deferred_configure(struct pkginfo *pkg); -extern int sincenothing, dependtry; +/* + * During the packages queue processing, the algorithm for deciding what to + * configure first is as follows: + * + * Loop through all packages doing a ‘try 1’ until we've been round and + * nothing has been done, then do ‘try 2’, and subsequent ones likewise. + * The incrementing of ‘dependtry’ is done by process_queue(). + * + * Try 1: + * Are all dependencies of this package done? If so, do it. + * Are any of the dependencies missing or the wrong version? + * If so, abort (unless --force-depends, in which case defer). + * Will we need to configure a package we weren't given as an + * argument? If so, abort ─ except if --force-configure-any, + * in which case we add the package to the argument list. + * If none of the above, defer the package. + * + * Try 2: + * Find a cycle and break it (see above). + * Do as for try 1. + * + * Try 3: + * Start processing triggers if necessary. + * Do as for try 2. + * + * Try 4: + * Same as for try 3, but check trigger cycles even when deferring + * processing due to unsatisfiable dependencies. + * + * Try 5 (only if --force-depends-version): + * Same as for try 2, but don't mind version number in dependencies. + * + * Try 6 (only if --force-depends): + * Do anyway. + */ +enum dependtry { + DEPEND_TRY_NORMAL = 1, + DEPEND_TRY_CYCLES = 2, + DEPEND_TRY_TRIGGERS = 3, + DEPEND_TRY_TRIGGERS_CYCLES = 4, + DEPEND_TRY_FORCE_DEPENDS_VERSION = 5, + DEPEND_TRY_FORCE_DEPENDS = 6, + DEPEND_TRY_LAST, +}; + +extern enum dependtry dependtry; +extern int sincenothing; /* from cleanup.c (most of these are declared in archives.h) */ @@ -281,8 +327,10 @@ /* from trigproc.c */ enum trigproc_type { - /** Opportunistic trigger processing. */ - TRIGPROC_TRY, + /** Opportunistic deferred trigger processing. */ + TRIGPROC_TRY_DEFERRED, + /** Opportunistic queued trigger processing. */ + TRIGPROC_TRY_QUEUED, /** Required trigger processing. */ TRIGPROC_REQUIRED, }; diff -Nru dpkg-1.18.4ubuntu1/src/packages.c dpkg-1.18.4ubuntu1.7/src/packages.c --- dpkg-1.18.4ubuntu1/src/packages.c 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/packages.c 2019-07-16 12:57:11.000000000 +0000 @@ -50,7 +50,8 @@ static struct pkginfo *progress_bytrigproc; static struct pkg_queue queue = PKG_QUEUE_INIT; -int sincenothing = 0, dependtry = 1; +enum dependtry dependtry = DEPEND_TRY_NORMAL; +int sincenothing = 0; void enqueue_package(struct pkginfo *pkg) @@ -232,17 +233,22 @@ * trigger processing, w/o jumping into the next dependtry. */ dependtry++; sincenothing = 0; - assert(dependtry <= 4); + if (dependtry >= DEPEND_TRY_LAST) + internerr("exceeded dependtry %d (sincenothing=%d; queue.length=%d)", + dependtry, sincenothing, queue.length); } else if (sincenothing > queue.length * 2 + 2) { - /* XXX: This probably needs moving into a new dependtry instead. */ - if (progress_bytrigproc && progress_bytrigproc->trigpend_head) { + if (dependtry >= DEPEND_TRY_TRIGGERS && + progress_bytrigproc && progress_bytrigproc->trigpend_head) { enqueue_package(pkg); pkg = progress_bytrigproc; + progress_bytrigproc = NULL; action_todo = act_configure; } else { dependtry++; sincenothing = 0; - assert(dependtry <= 4); + if (dependtry >= DEPEND_TRY_LAST) + internerr("exceeded dependtry %d (sincenothing=%d, queue.length=%d)", + dependtry, sincenothing, queue.length); } } @@ -280,7 +286,7 @@ case act_configure: /* Do whatever is most needed. */ if (pkg->trigpend_head) - trigproc(pkg, TRIGPROC_REQUIRED); + trigproc(pkg, TRIGPROC_TRY_QUEUED); else deferred_configure(pkg); break; @@ -342,6 +348,15 @@ FOUND_OK = 3, }; +static enum found_status +found_forced_on(enum dependtry dependtry_forced) +{ + if (dependtry >= dependtry_forced) + return FOUND_FORCED; + else + return FOUND_DEFER; +} + /* * Return values: * 0: cannot be satisfied. @@ -399,7 +414,7 @@ pkg_name(possdependee, pnaw_always), versiondescribe(&provider->version, vdew_nonambig)); if (fc_dependsversion) - thisf = (dependtry >= 3) ? FOUND_FORCED : FOUND_DEFER; + thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION); debug(dbg_depcondetail, " bad version"); goto unsuitable; } @@ -412,7 +427,7 @@ versiondescribe(&possdependee->installed.version, vdew_nonambig)); if (fc_dependsversion) - thisf = (dependtry >= 3) ? FOUND_FORCED : FOUND_DEFER; + thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION); debug(dbg_depcondetail, " bad version"); goto unsuitable; } @@ -676,7 +691,7 @@ if (thisf > found) found= thisf; } if (fc_depends) { - thisf = (dependtry >= 4) ? FOUND_FORCED : FOUND_DEFER; + thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS); if (thisf > found) { found = thisf; debug(dbg_depcondetail, " rescued by force-depends, found %d", found); diff -Nru dpkg-1.18.4ubuntu1/src/remove.c dpkg-1.18.4ubuntu1.7/src/remove.c --- dpkg-1.18.4ubuntu1/src/remove.c 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/remove.c 2019-07-16 12:57:11.000000000 +0000 @@ -71,7 +71,10 @@ pkg_name(depender, pnaw_always)); continue; } - if (dependtry > 1) { if (findbreakcycle(pkgtoremove)) sincenothing= 0; } + if (dependtry >= DEPEND_TRY_CYCLES) { + if (findbreakcycle(pkgtoremove)) + sincenothing = 0; + } varbuf_snapshot(raemsgs, &raemsgs_state); ok= dependencies_ok(depender,pkgtoremove,raemsgs); if (ok == DEP_CHECK_HALT && diff -Nru dpkg-1.18.4ubuntu1/src/trigproc.c dpkg-1.18.4ubuntu1.7/src/trigproc.c --- dpkg-1.18.4ubuntu1/src/trigproc.c 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/trigproc.c 2019-07-16 12:57:11.000000000 +0000 @@ -49,10 +49,11 @@ * we add it to that queue (unless --no-triggers). * * - * We want to prefer configuring packages where possible to doing - * trigger processing, but we want to prefer trigger processing to - * cycle-breaking and dependency forcing. This is achieved as - * follows: + * We want to prefer configuring packages where possible to doing trigger + * processing, although it would be better to prefer trigger processing + * to cycle-breaking we need to do the latter first or we might generate + * artificial trigger cycles, but we always want to prefer trigger + * processing to dependency forcing. This is achieved as follows: * * Each time during configure processing where a package D is blocked by * only (ie Depends unsatisfied but would be satisfied by) a t-awaiter W @@ -60,10 +61,11 @@ * (If --no-triggers and nonempty argument list and package isn't in * argument list then we don't do this.) * - * Each time in packages.c where we increment dependtry, we instead see - * if we have encountered such a t-pending T. If we do, we trigproc T - * instead of incrementing dependtry and this counts as having done - * something so we reset sincenothing. + * Each time in process_queue() where we increment dependtry, we instead + * see if we have encountered such a t-pending T. If we do and are in + * a trigger processing try, we trigproc T instead of incrementing + * dependtry and this counts as having done something so we reset + * sincenothing. * * * For --triggers-only and --configure, we go through each thing in the @@ -162,7 +164,7 @@ pkg_name(pkg, pnaw_nonambig)); pkg->clientdata->trigprocdeferred = NULL; - trigproc(pkg, TRIGPROC_TRY); + trigproc(pkg, TRIGPROC_TRY_DEFERRED); pop_error_context(ehflag_normaltidy); } @@ -207,8 +209,8 @@ } static bool -tortoise_not_in_hare(struct pkginfo *processing_now, - struct trigcycleperpkg *tortoise_pkg) +tortoise_in_hare(struct pkginfo *processing_now, + struct trigcycleperpkg *tortoise_pkg) { const char *processing_now_name, *tortoise_name; struct trigpend *hare_trig, *tortoise_trig; @@ -241,31 +243,24 @@ /* Not found in hare, yay! */ debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s OK", __func__, processing_now_name, tortoise_name); - return true; + return false; } } - return false; + return true; } -/* - * Returns package we're to give up on. - */ -static struct pkginfo * -check_trigger_cycle(struct pkginfo *processing_now) +static struct trigcyclenode * +trigproc_new_cyclenode(struct pkginfo *processing_now) { struct trigcyclenode *tcn; - struct trigcycleperpkg *tcpp, *tortoise_pkg; - struct trigpend *tortoise_trig; + struct trigcycleperpkg *tcpp; + struct pkginfo *pkg; struct pkgiterator *it; - struct pkginfo *pkg, *giveup; - const char *sep; - - debug(dbg_triggers, "check_triggers_cycle pnow=%s", - pkg_name(processing_now, pnaw_always)); tcn = nfmalloc(sizeof(*tcn)); tcn->pkgs = NULL; + tcn->next = NULL; tcn->then_processed = processing_now; it = pkg_db_iter_new(); @@ -279,15 +274,34 @@ tcn->pkgs = tcpp; } pkg_db_iter_free(it); + + return tcn; +} + +/* + * Returns package we are to give up on. + */ +static struct pkginfo * +check_trigger_cycle(struct pkginfo *processing_now) +{ + struct trigcyclenode *tcn; + struct trigcycleperpkg *tortoise_pkg; + struct trigpend *tortoise_trig; + struct pkginfo *giveup; + const char *sep; + + debug(dbg_triggers, "check_triggers_cycle pnow=%s", + pkg_name(processing_now, pnaw_always)); + + tcn = trigproc_new_cyclenode(processing_now); + if (!hare) { debug(dbg_triggersdetail, "check_triggers_cycle pnow=%s first", pkg_name(processing_now, pnaw_always)); - tcn->next = NULL; hare = tortoise = tcn; return NULL; } - tcn->next = NULL; hare->next = tcn; hare = tcn; if (tortoise_advance) @@ -301,7 +315,7 @@ for (tortoise_pkg = tortoise->pkgs; tortoise_pkg; tortoise_pkg = tortoise_pkg->next) { - if (tortoise_not_in_hare(processing_now, tortoise_pkg)) + if (!tortoise_in_hare(processing_now, tortoise_pkg)) return NULL; } /* Oh dear. hare is a superset of tortoise. We are making no @@ -335,8 +349,12 @@ debug(dbg_triggers, "check_triggers_cycle pnow=%s giveup=%s", pkg_name(processing_now, pnaw_always), pkg_name(giveup, pnaw_always)); - assert(giveup->status == PKG_STAT_TRIGGERSAWAITED || - giveup->status == PKG_STAT_TRIGGERSPENDING); + if (giveup->status != PKG_STAT_TRIGGERSAWAITED && + giveup->status != PKG_STAT_TRIGGERSPENDING) + internerr("package %s in non-trigger state %s", + pkg_name(giveup, pnaw_always), + pkg_status_name(giveup)); + giveup->clientdata->istobe = PKG_ISTOBE_NORMAL; pkg_set_status(giveup, PKG_STAT_HALFCONFIGURED); modstatdb_note(giveup); print_error_perpackage(_("triggers looping, abandoned"), @@ -370,33 +388,42 @@ assert(pkg->status == PKG_STAT_TRIGGERSPENDING || pkg->status == PKG_STAT_TRIGGERSAWAITED); - if (dependtry > 1) { - gaveup = check_trigger_cycle(pkg); - if (gaveup == pkg) - return; + if (dependtry < DEPEND_TRY_TRIGGERS && + type == TRIGPROC_TRY_QUEUED) { + /* We are not yet in a triggers run, so postpone this + * package completely. */ + enqueue_package(pkg); + return; + } + if (dependtry >= DEPEND_TRY_CYCLES) { if (findbreakcycle(pkg)) sincenothing = 0; } ok = dependencies_ok(pkg, NULL, &depwhynot); if (ok == DEP_CHECK_DEFER) { + if (dependtry >= DEPEND_TRY_TRIGGERS_CYCLES) { + gaveup = check_trigger_cycle(pkg); + if (gaveup == pkg) + return; + } + varbuf_destroy(&depwhynot); enqueue_package(pkg); return; } else if (ok == DEP_CHECK_HALT) { - /* We cannot process this package on this dpkg run, - * and we can get here repeatedly if this package is - * required to make progress for other packages. So - * reset the trigger cycles tracking to avoid bogus - * cycle detections. */ - trigproc_reset_cycle(); - - /* When doing opportunistic trigger processig, nothing - * requires us to be able to make progress; skip the - * package and silently ignore the error due to - * unsatisfiable dependencies. */ - if (type == TRIGPROC_TRY) { + /* When doing opportunistic deferred trigger processing, + * nothing requires us to be able to make progress; + * skip the package and silently ignore the error due + * to unsatisfiable dependencies. And because we can + * end up here repeatedly, if this package is required + * to make progress for other packages, we need to + * reset the trigger cycle tracking to avoid detecting + * bogus cycles*/ + if (type == TRIGPROC_TRY_DEFERRED) { + trigproc_reset_cycle(); + varbuf_destroy(&depwhynot); return; } @@ -416,11 +443,9 @@ varbuf_destroy(&depwhynot); } - if (dependtry <= 1) { - gaveup = check_trigger_cycle(pkg); - if (gaveup == pkg) - return; - } + gaveup = check_trigger_cycle(pkg); + if (gaveup == pkg) + return; printf(_("Processing triggers for %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig), diff -Nru dpkg-1.18.4ubuntu1/src/unpack.c dpkg-1.18.4ubuntu1.7/src/unpack.c --- dpkg-1.18.4ubuntu1/src/unpack.c 2015-11-26 23:53:41.000000000 +0000 +++ dpkg-1.18.4ubuntu1.7/src/unpack.c 2019-07-16 12:57:11.000000000 +0000 @@ -120,7 +120,7 @@ /* No, it wasn't a part. */ break; default: - internerr("unexpected exit status %d from %s", status, SPLITTER); + ohshit(_("subprocess %s returned error exit status %d"), SPLITTER, status); } return true;