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]