tags 143307 + patch thanks I've reproduced the problem from #143307 and attached is a fix.
The core of the problem was that if dpkg is interrupted, you can have the following situation: Package: a Triggers-Awaited: b Package: b Status: ... installed This is as expected but I obviously hadn't properly tested the recovery, which is to do a no-op trigger processing step for b. The machinery in packages.c would be unimpressed by b's appearance in progress_bytrigproc. In the patch below I also fix --no-act for trigger processing, which was previously broken. This was somewhat more complex than ideal because the triggers arrangements leak somewhat more into dbmodify than previously existing functionality. I decided to create a new msdbrw_... value `simulate' and change the various places to use it and treat it appropriately. After calling modstatdb_init with msdbrw_simulate it is permitted to call modstatdb_note. Ian. diff --exclude='*~' -bru orig/dpkg-1.14.20/lib/dbmodify.c dpkg-1.14.20/lib/dbmodify.c --- orig/dpkg-1.14.20/lib/dbmodify.c 2008-06-18 08:33:27.000000000 +0100 +++ dpkg-1.14.20/lib/dbmodify.c 2008-06-28 15:41:17.000000000 +0100 @@ -170,8 +170,8 @@ msdbrw_write); } break; - case msdbrw_readonly: - cstatus= msdbrw_readonly; break; + case msdbrw_readonly: case msdbrw_simulate: + cstatus= readwritereq; break; default: internerr("unknown readwritereq"); } @@ -204,6 +204,7 @@ void modstatdb_checkpoint(void) { int i; + if (cstatus == msdbrw_simulate) return; assert(cstatus >= msdbrw_write); writedb(statusfile,0,1); @@ -249,7 +250,7 @@ void modstatdb_note(struct pkginfo *pkg) { struct trigaw *ta; - assert(cstatus >= msdbrw_write); + assert(cstatus >= msdbrw_simulate); onerr_abort++; @@ -267,6 +268,8 @@ versiondescribe(&pkg->installed.version, vdew_nonambig)); statusfd_send("status: %s: %s", pkg->name, statusinfos[pkg->status].name); + if (cstatus >= msdbrw_write) { + varbufreset(&uvb); varbufrecord(&uvb, pkg, &pkg->installed); if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used) @@ -274,7 +277,8 @@ if (fflush(importanttmp)) ohshite(_("unable to flush updated status of `%.250s'"), pkg->name); if (ftruncate(fileno(importanttmp), uvb.used)) - ohshite(_("unable to truncate for updated status of `%.250s'"), pkg->name); + ohshite(_("unable to truncate for updated status of `%.250s'"), + pkg->name); if (fsync(fileno(importanttmp))) ohshite(_("unable to fsync updated status of `%.250s'"), pkg->name); if (fclose(importanttmp)) @@ -282,7 +286,8 @@ sprintf(updatefnrest, IMPORTANTFMT, nextupdate); if (rename(importanttmpfile, updatefnbuf)) ohshite(_("unable to install updated status of `%.250s'"), pkg->name); - assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); /* or we've made a real mess */ + assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); + /* ... or we've made a real mess */ nextupdate++; @@ -293,6 +298,8 @@ createimptmp(); + } + if (!pkg->trigpend_head && pkg->othertrigaw_head) { /* Automatically remove us from other packages' Triggers-Awaited. * We do this last because we want to maximise our chances of diff --exclude='*~' -bru orig/dpkg-1.14.20/lib/dpkg-db.h dpkg-1.14.20/lib/dpkg-db.h --- orig/dpkg-1.14.20/lib/dpkg-db.h 2008-06-18 08:33:27.000000000 +0100 +++ dpkg-1.14.20/lib/dpkg-db.h 2008-06-28 15:41:17.000000000 +0100 @@ -189,6 +189,7 @@ /* Those marked with \*s*\ are possible returns from modstatdb_init. */ msdbrw_readonly/*s*/, msdbrw_needsuperuserlockonly/*s*/, msdbrw_writeifposs, + msdbrw_simulate/*s*/, /* read only, but writes ignored not asserted */ msdbrw_write/*s*/, msdbrw_needsuperuser, /* Now some optional flags: */ msdbrw_flagsmask= ~077, diff --exclude='*~' -bru orig/dpkg-1.14.20/lib/triglib.c dpkg-1.14.20/lib/triglib.c --- orig/dpkg-1.14.20/lib/triglib.c 2008-06-18 08:33:27.000000000 +0100 +++ dpkg-1.14.20/lib/triglib.c 2008-06-28 15:45:23.000000000 +0100 @@ -664,9 +664,17 @@ void trig_incorporate(enum modstatdb_rw cstatus, const char *admindir) { + static int simulation_done; + int ur; enum trigdef_updateflags tduf; + if (cstatus == msdbrw_simulate) { + /* only incorporate once, as we're supposed to fold it into status */ + if (simulation_done) return; + simulation_done= 1; + } + trigdef = &tdm_incorp; trig_file_interests_ensure(); diff --exclude='*~' -bru orig/dpkg-1.14.20/src/archives.c dpkg-1.14.20/src/archives.c --- orig/dpkg-1.14.20/src/archives.c 2008-06-18 08:33:31.000000000 +0100 +++ dpkg-1.14.20/src/archives.c 2008-06-28 15:41:17.000000000 +0100 @@ -1087,7 +1087,7 @@ trigproc_install_hooks(); modstatdb_init(admindir, - f_noact ? msdbrw_readonly + f_noact ? msdbrw_simulate : cipaction->arg == act_avail ? msdbrw_write : fc_nonroot ? msdbrw_write : msdbrw_needsuperuser); diff --exclude='*~' -bru orig/dpkg-1.14.20/src/packages.c dpkg-1.14.20/src/packages.c --- orig/dpkg-1.14.20/src/packages.c 2008-06-18 08:33:31.000000000 +0100 +++ dpkg-1.14.20/src/packages.c 2008-06-28 15:54:24.000000000 +0100 @@ -93,7 +93,7 @@ trigproc_install_hooks(); modstatdb_init(admindir, - f_noact ? msdbrw_readonly + f_noact ? msdbrw_simulate : fc_nonroot ? msdbrw_write : msdbrw_needsuperuser); checkpath(); @@ -211,7 +211,12 @@ action_todo = cipaction->arg; if (sincenothing++ > queue.length * 2 + 2) { - if (progress_bytrigproc && progress_bytrigproc->trigpend_head) { + if (progress_bytrigproc && + (progress_bytrigproc->trigpend_head || + (progress_bytrigproc->status >= stat_triggersawaited && + progress_bytrigproc->othertrigaw_head))) { + debug(dbg_depcon, "using progress_bytrigproc %s instead of %s", + progress_bytrigproc->name, pkg->name); add_to_queue(pkg); pkg = progress_bytrigproc; action_todo = act_configure; @@ -246,7 +251,8 @@ /* Fall through. */ case act_configure: /* Do whatever is most needed. */ - if (pkg->trigpend_head) + if (pkg->trigpend_head || + (pkg->status >= stat_triggersawaited && pkg->othertrigaw_head)) trigproc(pkg); else deferred_configure(pkg); @@ -389,7 +395,7 @@ * anyway, and that trigger processing will be a noop except for * sorting out all of the packages which name it in T-Awaited. * - * (This situation can only arise if modstatdb_note success in + * (This situation can only arise if modstatdb_note succeeds in * clearing the triggers-pending status of the pending package * but then fails to go on to update the awaiters.) */ @@ -609,8 +615,13 @@ } if (ok == 0 && (pkg->clientdata && pkg->clientdata->istobe == itb_remove)) ok= 1; - if (!anycannotfixbytrig && canfixbytrig) + + if (!anycannotfixbytrig && canfixbytrig) { + debug(dbg_depcon, "progress_bytrigproc %s (was %s)", + canfixbytrig->name, + progress_bytrigproc ? progress_bytrigproc->name : "<none>"); progress_bytrigproc = canfixbytrig; + } varbuffree(&oemsgs); debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, (int)aemsgs->used, aemsgs->buf); diff --exclude='*~' -bru orig/dpkg-1.14.20/src/trigproc.c dpkg-1.14.20/src/trigproc.c --- orig/dpkg-1.14.20/src/trigproc.c 2008-05-05 18:07:01.000000000 +0100 +++ dpkg-1.14.20/src/trigproc.c 2008-06-28 15:47:05.000000000 +0100 @@ -288,6 +288,7 @@ printf(_("Processing triggers for %s ...\n"), pkg->name); log_action("trigproc", pkg); + if (!f_noact) { varbufreset(&namesarg); for (tp = pkg->trigpend_head; tp; tp = tp->next) { varbufaddc(&namesarg, ' '); @@ -301,6 +302,7 @@ sincenothing = 0; maintainer_script_postinst(pkg, "triggered", namesarg.buf + 1, NULL); + } /* This is to cope if the package triggers itself: */ pkg->status = pkg->trigaw.head ? stat_triggersawaited : diff --exclude='*~' -bru orig/dpkg-1.14.20/src/update.c dpkg-1.14.20/src/update.c --- orig/dpkg-1.14.20/src/update.c 2008-05-05 18:07:01.000000000 +0100 +++ dpkg-1.14.20/src/update.c 2008-06-28 15:41:17.000000000 +0100 @@ -101,7 +101,7 @@ if (*argv) badusage(_("--forget-old-unavail takes no arguments")); - modstatdb_init(admindir, f_noact ? msdbrw_readonly : msdbrw_write); + modstatdb_init(admindir, f_noact ? msdbrw_simulate : msdbrw_write); it= iterpkgstart(); while ((pkg= iterpkgnext(it))) { Only in dpkg-1.14.20: x.gdb -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]