static void enqueue_specified(const char *const *argv) { const char *thisarg; while ((thisarg = *argv++) != NULL) { struct dpkg_error err; struct pkginfo *pkg; pkg = pkg_spec_parse_pkg(thisarg, &err); if (pkg == NULL) badusage(_("--%s needs a valid package name but '%.250s' is not: %s"), cipaction->olong, thisarg, err.str); if (pkg->status == stat_notinstalled) { size_t l = strlen(pkg->set->name); const char *extension = pkg->set->name + l - sizeof(DEBEXT) + 1; if (l >= sizeof(DEBEXT) && strcmp(extension, DEBEXT) == 0) badusage(_("you must specify packages by their own names," " not by quoting the names of the files they come in")); } enqueue_package(pkg); } }
static void enqueue_pending(void) { struct pkg_hash_iter *iter; struct pkginfo *pkg; iter = pkg_hash_iter_new(); while ((pkg = pkg_hash_iter_next_pkg(iter)) != NULL) { switch (cipaction->arg_int) { case act_configure: if (!(pkg->status == PKG_STAT_UNPACKED || pkg->status == PKG_STAT_HALFCONFIGURED || pkg->trigpend_head)) continue; if (pkg->want != PKG_WANT_INSTALL) continue; break; case act_triggers: if (!pkg->trigpend_head) continue; if (pkg->want != PKG_WANT_INSTALL) continue; break; case act_remove: case act_purge: if (pkg->want != PKG_WANT_PURGE) { if (pkg->want != PKG_WANT_DEINSTALL) continue; if (pkg->status == PKG_STAT_CONFIGFILES) continue; } if (pkg->status == PKG_STAT_NOTINSTALLED) continue; break; default: internerr("unknown action '%d'", cipaction->arg_int); } enqueue_package(pkg); } pkg_hash_iter_free(iter); }
static void enqueue_pending(void) { struct pkgiterator *it; struct pkginfo *pkg; it = pkg_db_iter_new(); while ((pkg = pkg_db_iter_next_pkg(it)) != NULL) { switch (cipaction->arg_int) { case act_configure: if (!(pkg->status == stat_unpacked || pkg->status == stat_halfconfigured || pkg->trigpend_head)) continue; if (pkg->want != want_install) continue; break; case act_triggers: if (!pkg->trigpend_head) continue; if (pkg->want != want_install) continue; break; case act_remove: case act_purge: if (pkg->want != want_purge) { if (pkg->want != want_deinstall) continue; if (pkg->status == stat_configfiles) continue; } if (pkg->status == stat_notinstalled) continue; break; default: internerr("unknown action '%d'", cipaction->arg_int); } enqueue_package(pkg); } pkg_db_iter_free(it); }
/* * Does cycle checking. Doesn't mind if pkg has no triggers pending - in * that case does nothing but fix up any stale awaiters. */ void trigproc(struct pkginfo *pkg, enum trigproc_type type) { static struct varbuf namesarg; struct varbuf depwhynot = VARBUF_INIT; struct trigpend *tp; struct pkginfo *gaveup; debug(dbg_triggers, "trigproc %s", pkg_name(pkg, pnaw_always)); if (pkg->clientdata->trigprocdeferred) pkg->clientdata->trigprocdeferred->pkg = NULL; pkg->clientdata->trigprocdeferred = NULL; if (pkg->trigpend_head) { enum dep_check ok; assert(pkg->status == PKG_STAT_TRIGGERSPENDING || pkg->status == PKG_STAT_TRIGGERSAWAITED); if (dependtry > 1) { gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; if (findbreakcycle(pkg)) sincenothing = 0; } ok = dependencies_ok(pkg, NULL, &depwhynot); if (ok == DEP_CHECK_DEFER) { 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) { varbuf_destroy(&depwhynot); return; } sincenothing = 0; varbuf_end_str(&depwhynot); notice(_("dependency problems prevent processing " "triggers for %s:\n%s"), pkg_name(pkg, pnaw_nonambig), depwhynot.buf); varbuf_destroy(&depwhynot); ohshit(_("dependency problems - leaving triggers unprocessed")); } else if (depwhynot.used) { varbuf_end_str(&depwhynot); notice(_("%s: dependency problems, but processing " "triggers anyway as you requested:\n%s"), pkg_name(pkg, pnaw_nonambig), depwhynot.buf); varbuf_destroy(&depwhynot); } if (dependtry <= 1) { gaveup = check_trigger_cycle(pkg); if (gaveup == pkg) return; } printf(_("Processing triggers for %s (%s) ...\n"), pkg_name(pkg, pnaw_nonambig), versiondescribe(&pkg->installed.version, vdew_nonambig)); log_action("trigproc", pkg, &pkg->installed); varbuf_reset(&namesarg); for (tp = pkg->trigpend_head; tp; tp = tp->next) { varbuf_add_char(&namesarg, ' '); varbuf_add_str(&namesarg, tp->name); } varbuf_end_str(&namesarg); /* Setting the status to half-configured * causes modstatdb_note to clear pending triggers. */ pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED); modstatdb_note(pkg); if (!f_noact) { sincenothing = 0; maintscript_postinst(pkg, "triggered", namesarg.buf + 1, NULL); } post_postinst_tasks(pkg, PKG_STAT_INSTALLED); } else { /* In other branch is done by modstatdb_note(), from inside * post_postinst_tasks(). */ trig_clear_awaiters(pkg); } }
void enqueue_package_mark_seen(struct pkginfo *pkg) { enqueue_package(pkg); pkg->clientdata->cmdline_seen++; }
/* * Return values: * 0: cannot be satisfied. * 1: defer: may be satisfied later, when other packages are better or * at higher dependtry due to --force * will set *fixbytrig to package whose trigger processing would help * if applicable (and leave it alone otherwise). * 2: not satisfied but forcing * (*interestingwarnings >= 0 on exit? caller is to print oemsgs). * 3: satisfied now. */ static enum found_status deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, struct pkginfo *removing, struct deppossi *provider, struct pkginfo **fixbytrig, bool *matched, struct deppossi *checkversion, int *interestingwarnings, struct varbuf *oemsgs) { enum found_status thisf; if (ignore_depends(possdependee)) { debug(dbg_depcondetail," ignoring depended package so ok and found"); return FOUND_OK; } thisf = FOUND_NONE; if (possdependee == removing) { if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is to be removed.\n"), pkg_name(possdependee, pnaw_nonambig), provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is to be removed.\n"), pkg_name(possdependee, pnaw_nonambig)); } *matched = true; debug(dbg_depcondetail," removing possdependee, returning %d",thisf); return thisf; } switch (possdependee->status) { case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: case PKG_STAT_TRIGGERSAWAITED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_INSTALLED: if (checkversion) { if (provider) { debug(dbg_depcondetail, " checking package %s provided by pkg %s", checkversion->ed->name, pkg_name(possdependee, pnaw_always)); if (!pkg_virtual_deppossi_satisfied(checkversion, provider)) { varbuf_printf(oemsgs, _(" Version of %s on system, provided by %s, is %s.\n"), checkversion->ed->name, pkg_name(possdependee, pnaw_always), versiondescribe(&provider->version, vdew_nonambig)); if (in_force(FORCE_DEPENDS_VERSION)) thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION); debug(dbg_depcondetail, " bad version"); goto unsuitable; } } else { debug(dbg_depcondetail, " checking non-provided pkg %s", pkg_name(possdependee, pnaw_always)); if (!versionsatisfied(&possdependee->installed, checkversion)) { varbuf_printf(oemsgs, _(" Version of %s on system is %s.\n"), pkg_name(possdependee, pnaw_nonambig), versiondescribe(&possdependee->installed.version, vdew_nonambig)); if (in_force(FORCE_DEPENDS_VERSION)) thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION); debug(dbg_depcondetail, " bad version"); goto unsuitable; } } } if (possdependee->status == PKG_STAT_INSTALLED || possdependee->status == PKG_STAT_TRIGGERSPENDING) { debug(dbg_depcondetail," is installed, ok and found"); return FOUND_OK; } if (possdependee->status == PKG_STAT_TRIGGERSAWAITED) { if (possdependee->trigaw.head == NULL) internerr("package %s in state %s, has no awaited triggers", pkg_name(possdependee, pnaw_always), pkg_status_name(possdependee)); if (removing || !(f_triggers || (possdependee->clientdata && possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW))) { if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s awaits trigger processing.\n"), pkg_name(possdependee, pnaw_nonambig), provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s awaits trigger processing.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " triggers-awaited, no fixbytrig"); goto unsuitable; } /* We don't check the status of trigaw.head->pend here, just in case * we get into the pathological situation where Triggers-Awaited but * the named package doesn't actually have any pending triggers. In * that case we queue the non-pending package for trigger processing * anyway, and that trigger processing will be a noop except for * sorting out all of the packages which name it in Triggers-Awaited. * * (This situation can only arise if modstatdb_note success in * clearing the triggers-pending status of the pending package * but then fails to go on to update the awaiters.) */ *fixbytrig = possdependee->trigaw.head->pend; debug(dbg_depcondetail, " triggers-awaited, fixbytrig '%s', defer", pkg_name(*fixbytrig, pnaw_always)); return FOUND_DEFER; } if (possdependee->clientdata && possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) { debug(dbg_depcondetail," unpacked/halfconfigured, defer"); return FOUND_DEFER; } else if (!removing && in_force(FORCE_CONFIGURE_ANY) && !skip_due_to_hold(possdependee) && !(possdependee->status == PKG_STAT_HALFCONFIGURED)) { notice(_("also configuring '%s' (required by '%s')"), pkg_name(possdependee, pnaw_nonambig), pkg_name(requiredby, pnaw_nonambig)); enqueue_package(possdependee); sincenothing = 0; return FOUND_DEFER; } else { if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not configured yet.\n"), pkg_name(possdependee, pnaw_nonambig), provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is not configured yet.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " not configured/able"); goto unsuitable; } default: if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not installed.\n"), pkg_name(possdependee, pnaw_nonambig), provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is not installed.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " not installed"); goto unsuitable; } unsuitable: debug(dbg_depcondetail, " returning %d", thisf); (*interestingwarnings)++; return thisf; }
void process_queue(void) { struct pkg_list *rundown; struct pkginfo *volatile pkg; volatile enum action action_todo; jmp_buf ejbuf; enum pkg_istobe istobe = PKG_ISTOBE_NORMAL; if (abort_processing) return; clear_istobes(); switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_install: istobe = PKG_ISTOBE_INSTALLNEW; break; case act_remove: case act_purge: istobe = PKG_ISTOBE_REMOVE; break; default: internerr("unknown action '%d'", cipaction->arg_int); } for (rundown = queue.head; rundown; rundown = rundown->next) { ensure_package_clientdata(rundown->pkg); /* We have processed this package more than once. There are no duplicates * as we make sure of that when enqueuing them. */ if (rundown->pkg->clientdata->cmdline_seen > 1) { switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_remove: case act_purge: printf(_("Package %s listed more than once, only processing once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; case act_install: printf(_("More than one copy of package %s has been unpacked\n" " in this run ! Only configuring it once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; default: internerr("unknown action '%d'", cipaction->arg_int); } } rundown->pkg->clientdata->istobe = istobe; } while (!pkg_queue_is_empty(&queue)) { pkg = pkg_queue_pop(&queue); if (!pkg) continue; /* Duplicate, which we removed earlier. */ ensure_package_clientdata(pkg); pkg->clientdata->enqueued = false; action_todo = cipaction->arg_int; if (sincenothing++ > queue.length * 3 + 2) { /* Make sure that even if we have exceeded the queue since not having * made any progress, we are not getting stuck trying to progress by * trigger processing, w/o jumping into the next dependtry. */ dependtry++; sincenothing = 0; 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) { 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; if (dependtry >= DEPEND_TRY_LAST) internerr("exceeded dependtry %d (sincenothing=%d, queue.length=%d)", dependtry, sincenothing, queue.length); } } debug(dbg_general, "process queue pkg %s queue.len %d progress %d, try %d", pkg_name(pkg, pnaw_always), queue.length, sincenothing, dependtry); if (pkg->status > PKG_STAT_INSTALLED) internerr("package %s status %d is out-of-bounds", pkg_name(pkg, pnaw_always), pkg->status); if (setjmp(ejbuf)) { /* Give up on it from the point of view of other packages, i.e. reset * istobe. */ pkg->clientdata->istobe = PKG_ISTOBE_NORMAL; pop_error_context(ehflag_bombout); if (abort_processing) return; continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); switch (action_todo) { case act_triggers: if (!pkg->trigpend_head) ohshit(_("package %.250s is not ready for trigger processing\n" " (current status '%.250s' with no pending triggers)"), pkg_name(pkg, pnaw_nonambig), pkg_status_name(pkg)); /* Fall through. */ case act_install: /* Don't try to configure pkgs that we've just disappeared. */ if (pkg->status == PKG_STAT_NOTINSTALLED) break; /* Fall through. */ case act_configure: /* Do whatever is most needed. */ if (pkg->trigpend_head) trigproc(pkg, TRIGPROC_TRY_QUEUED); else deferred_configure(pkg); break; case act_remove: case act_purge: deferred_remove(pkg); break; default: internerr("unknown action '%d'", cipaction->arg_int); } m_output(stdout, _("<standard output>")); m_output(stderr, _("<standard error>")); pop_error_context(ehflag_normaltidy); } if (queue.length) internerr("finished package processing with non-empty queue length %d", queue.length); }
/* * Also has conflictor in argv[1] and infavour in argv[2]. * conflictor may be NULL if deconfigure was due to Breaks. */ void ok_prermdeconfigure(int argc, void **argv) { struct pkginfo *deconf= (struct pkginfo*)argv[0]; if (cipaction->arg_int == act_install) enqueue_package(deconf); }
/* * Return values: * 0: cannot be satisfied. * 1: defer: may be satisfied later, when other packages are better or * at higher dependtry due to --force * will set *fixbytrig to package whose trigger processing would help * if applicable (and leave it alone otherwise). * 2: not satisfied but forcing * (*interestingwarnings >= 0 on exit? caller is to print oemsgs). * 3: satisfied now. */ static enum found_status deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, struct pkginfo *removing, struct pkgset *providing, struct pkginfo **fixbytrig, bool *matched, struct deppossi *checkversion, int *interestingwarnings, struct varbuf *oemsgs) { enum found_status thisf; if (ignore_depends(possdependee)) { debug(dbg_depcondetail," ignoring depended package so ok and found"); return found_ok; } thisf = found_none; if (possdependee == removing) { if (providing) { varbuf_printf(oemsgs, _(" Package %s which provides %s is to be removed.\n"), pkg_name(possdependee, pnaw_nonambig), providing->name); } else { varbuf_printf(oemsgs, _(" Package %s is to be removed.\n"), pkg_name(possdependee, pnaw_nonambig)); } *matched = true; debug(dbg_depcondetail," removing possdependee, returning %d",thisf); return thisf; } switch (possdependee->status) { case stat_unpacked: case stat_halfconfigured: case stat_triggersawaited: case stat_triggerspending: case stat_installed: if (checkversion && !versionsatisfied(&possdependee->installed,checkversion)) { varbuf_printf(oemsgs, _(" Version of %s on system is %s.\n"), pkg_name(possdependee, pnaw_nonambig), versiondescribe(&possdependee->installed.version, vdew_nonambig)); assert(checkversion->verrel != dpkg_relation_none); if (fc_dependsversion) thisf = (dependtry >= 3) ? found_forced : found_defer; debug(dbg_depcondetail," bad version, returning %d",thisf); (*interestingwarnings)++; return thisf; } if (possdependee->status == stat_installed || possdependee->status == stat_triggerspending) { debug(dbg_depcondetail," is installed, ok and found"); return found_ok; } if (possdependee->status == stat_triggersawaited) { assert(possdependee->trigaw.head); if (removing || !(f_triggers || possdependee->clientdata->istobe == itb_installnew)) { if (providing) { varbuf_printf(oemsgs, _(" Package %s which provides %s awaits trigger processing.\n"), pkg_name(possdependee, pnaw_nonambig), providing->name); } else { varbuf_printf(oemsgs, _(" Package %s awaits trigger processing.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " triggers-awaited, no fixbytrig"); goto unsuitable; } /* We don't check the status of trigaw.head->pend here, just in case * we get into the pathological situation where Triggers-Awaited but * the named package doesn't actually have any pending triggers. In * that case we queue the non-pending package for trigger processing * anyway, and that trigger processing will be a noop except for * sorting out all of the packages which name it in Triggers-Awaited. * * (This situation can only arise if modstatdb_note success in * clearing the triggers-pending status of the pending package * but then fails to go on to update the awaiters.) */ *fixbytrig = possdependee->trigaw.head->pend; debug(dbg_depcondetail, " triggers-awaited, fixbytrig '%s', defer", pkg_name(*fixbytrig, pnaw_always)); return found_defer; } if (possdependee->clientdata && possdependee->clientdata->istobe == itb_installnew) { debug(dbg_depcondetail," unpacked/halfconfigured, defer"); return found_defer; } else if (!removing && fc_configureany && !skip_due_to_hold(possdependee) && !(possdependee->status == stat_halfconfigured)) { notice(_("also configuring '%s' (required by '%s')"), pkg_name(possdependee, pnaw_nonambig), pkg_name(requiredby, pnaw_nonambig)); enqueue_package(possdependee); sincenothing = 0; return found_defer; } else { if (providing) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not configured yet.\n"), pkg_name(possdependee, pnaw_nonambig), providing->name); } else { varbuf_printf(oemsgs, _(" Package %s is not configured yet.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " not configured/able"); goto unsuitable; } default: if (providing) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not installed.\n"), pkg_name(possdependee, pnaw_nonambig), providing->name); } else { varbuf_printf(oemsgs, _(" Package %s is not installed.\n"), pkg_name(possdependee, pnaw_nonambig)); } debug(dbg_depcondetail, " not installed"); goto unsuitable; } unsuitable: debug(dbg_depcondetail, " returning %d", thisf); (*interestingwarnings)++; return thisf; }
void process_queue(void) { struct pkg_list *rundown; struct pkginfo *volatile pkg; volatile enum action action_todo; jmp_buf ejbuf; enum istobes istobe= itb_normal; if (abort_processing) return; clear_istobes(); switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_install: istobe= itb_installnew; break; case act_remove: case act_purge: istobe= itb_remove; break; default: internerr("unknown action '%d'", cipaction->arg_int); } for (rundown = queue.head; rundown; rundown = rundown->next) { ensure_package_clientdata(rundown->pkg); if (rundown->pkg->clientdata->istobe == istobe) { /* Erase the queue entry - this is a second copy! */ switch (cipaction->arg_int) { case act_triggers: case act_configure: case act_remove: case act_purge: printf(_("Package %s listed more than once, only processing once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; case act_install: printf(_("More than one copy of package %s has been unpacked\n" " in this run ! Only configuring it once.\n"), pkg_name(rundown->pkg, pnaw_nonambig)); break; default: internerr("unknown action '%d'", cipaction->arg_int); } rundown->pkg = NULL; } else { rundown->pkg->clientdata->istobe= istobe; } } while (!pkg_queue_is_empty(&queue)) { pkg = pkg_queue_pop(&queue); if (!pkg) continue; /* Duplicate, which we removed earlier. */ action_todo = cipaction->arg_int; if (sincenothing++ > queue.length * 2 + 2) { if (progress_bytrigproc && progress_bytrigproc->trigpend_head) { enqueue_package(pkg); pkg = progress_bytrigproc; action_todo = act_configure; } else { dependtry++; sincenothing = 0; assert(dependtry <= 4); } } assert(pkg->status <= stat_installed); if (setjmp(ejbuf)) { /* Give up on it from the point of view of other packages, i.e. reset * istobe. */ pkg->clientdata->istobe= itb_normal; pop_error_context(ehflag_bombout); if (abort_processing) return; continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); switch (action_todo) { case act_triggers: if (!pkg->trigpend_head) ohshit(_("package %.250s is not ready for trigger processing\n" " (current status `%.250s' with no pending triggers)"), pkg_name(pkg, pnaw_nonambig), statusinfos[pkg->status].name); /* Fall through. */ case act_install: /* Don't try to configure pkgs that we've just disappeared. */ if (pkg->status == stat_notinstalled) break; /* Fall through. */ case act_configure: /* Do whatever is most needed. */ if (pkg->trigpend_head) trigproc(pkg); else deferred_configure(pkg); break; case act_remove: case act_purge: deferred_remove(pkg); break; default: internerr("unknown action '%d'", cipaction->arg_int); } m_output(stdout, _("<standard output>")); m_output(stderr, _("<standard error>")); pop_error_context(ehflag_normaltidy); } assert(!queue.length); }