static void pkg_disappear(struct pkginfo *pkg, struct pkginfo *infavour) { printf(_("(Noting disappearance of %s, which has been completely replaced.)\n"), pkg_name(pkg, pnaw_nonambig)); log_action("disappear", pkg, &pkg->installed); debug(dbg_general, "pkg_disappear disappearing %s", pkg_name(pkg, pnaw_nonambig)); trig_activate_packageprocessing(pkg); maintainer_script_installed(pkg, POSTRMFILE, "post-removal script (for disappearance)", "disappear", infavour->set->name, versiondescribe(&infavour->available.version, vdew_nonambig), NULL); /* OK, now we delete all the stuff in the ‘info’ directory .. */ debug(dbg_general, "pkg_disappear cleaning info directory"); pkg_infodb_foreach(pkg, &pkg->installed, pkg_infodb_remove_file); dir_sync_path(pkgadmindir()); pkg_set_status(pkg, stat_notinstalled); pkg_set_want(pkg, want_unknown); pkg_reset_eflags(pkg); blankversion(&pkg->configversion); pkgbin_blank(&pkg->installed); pkg->clientdata->fileslistvalid = false; modstatdb_note(pkg); }
/* * Returns true if the file is used by packages other than pkg, * false otherwise. */ bool dir_is_used_by_others(struct filenamenode *file, struct pkginfo *pkg) { struct filepackages_iterator *iter; struct pkginfo *other_pkg; debug(dbg_veryverbose, "dir_is_used_by_others '%s' (except %s)", file->name, pkg ? pkg_name(pkg, pnaw_always) : "<none>"); iter = filepackages_iter_new(file); while ((other_pkg = filepackages_iter_next(iter))) { debug(dbg_veryverbose, "dir_is_used_by_others considering %s ...", pkg_name(other_pkg, pnaw_always)); if (other_pkg == pkg) continue; filepackages_iter_free(iter); debug(dbg_veryverbose, "dir_is_used_by_others yes"); return true; } filepackages_iter_free(iter); debug(dbg_veryverbose, "dir_is_used_by_others no"); return false; }
/* * 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) { static struct varbuf namesarg; 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) { assert(pkg->status == stat_triggerspending || pkg->status == stat_triggersawaited); 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, stat_halfconfigured); modstatdb_note(pkg); if (!f_noact) { sincenothing = 0; maintscript_postinst(pkg, "triggered", namesarg.buf + 1, NULL); } post_postinst_tasks(pkg, stat_installed); } else { /* In other branch is done by modstatdb_note(), from inside * post_postinst_tasks(). */ trig_clear_awaiters(pkg); } }
bool skip_due_to_hold(struct pkginfo *pkg) { if (pkg->want != PKG_WANT_HOLD) return false; if (fc_hold) { notice(_("package %s was on hold, processing it anyway as you requested"), pkg_name(pkg, pnaw_nonambig)); return false; } printf(_("Package %s is on hold, not touching it. Use --force-hold to override.\n"), pkg_name(pkg, pnaw_nonambig)); return true; }
static void breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok, struct deppossi *breaks, struct pkginfo *broken, struct pkginfo *breaker, struct deppossi *virtbroken) { struct varbuf depmsg = VARBUF_INIT; debug(dbg_depcondetail, " checking breaker %s virtbroken %s", pkg_name(breaker, pnaw_always), virtbroken ? virtbroken->ed->name : "<none>"); if (breaker->status == PKG_STAT_NOTINSTALLED || breaker->status == PKG_STAT_CONFIGFILES) return; if (broken == breaker) return; if (!versionsatisfied(&broken->installed, breaks)) return; /* The test below can only trigger if dep_breaks start having * arch qualifiers different from “any”. */ if (!archsatisfied(&broken->installed, breaks)) return; if (ignore_depends(breaker)) return; if (virtbroken && ignore_depends(&virtbroken->ed->pkg)) return; if (virtbroken && !pkg_virtual_deppossi_satisfied(breaks, virtbroken)) return; varbufdependency(&depmsg, breaks->up); varbuf_end_str(&depmsg); varbuf_printf(aemsgs, _(" %s (%s) breaks %s and is %s.\n"), pkg_name(breaker, pnaw_nonambig), versiondescribe(&breaker->installed.version, vdew_nonambig), depmsg.buf, gettext(statusstrings[breaker->status])); varbuf_destroy(&depmsg); if (virtbroken) { varbuf_printf(aemsgs, _(" %s (%s) provides %s.\n"), pkg_name(broken, pnaw_nonambig), versiondescribe(&broken->installed.version, vdew_nonambig), virtbroken->ed->name); } else if (breaks->verrel != DPKG_RELATION_NONE) { varbuf_printf(aemsgs, _(" Version of %s to be configured is %s.\n"), pkg_name(broken, pnaw_nonambig), versiondescribe(&broken->installed.version, vdew_nonambig)); if (in_force(FORCE_DEPENDS_VERSION)) return; } if (force_breaks(breaks)) return; *ok = DEP_CHECK_HALT; }
void trig_clear_awaiters(struct pkginfo *notpend) { struct trigaw *ta; struct pkginfo *aw; if (notpend->trigpend_head) internerr("package %s has pending triggers", pkg_name(notpend, pnaw_always)); ta = notpend->othertrigaw_head; notpend->othertrigaw_head = NULL; for (; ta; ta = ta->samepend_next) { aw = ta->aw; if (!aw) continue; LIST_UNLINK_PART(aw->trigaw, ta, sameaw); if (!aw->trigaw.head && aw->status == PKG_STAT_TRIGGERSAWAITED) { if (aw->trigpend_head) pkg_set_status(aw, PKG_STAT_TRIGGERSPENDING); else pkg_set_status(aw, PKG_STAT_INSTALLED); modstatdb_note(aw); } } }
/* * conflictor may be NULL. */ void cu_prermdeconfigure(int argc, void **argv) { struct pkginfo *deconf= (struct pkginfo*)argv[0]; struct pkginfo *conflictor = (struct pkginfo *)argv[1]; struct pkginfo *infavour= (struct pkginfo*)argv[2]; if (conflictor) { maintainer_script_postinst(deconf, "abort-deconfigure", "in-favour", pkgbin_name(infavour, &infavour->available, pnaw_nonambig), versiondescribe(&infavour->available.version, vdew_nonambig), "removing", pkg_name(conflictor, pnaw_nonambig), versiondescribe(&conflictor->installed.version, vdew_nonambig), NULL); } else { maintainer_script_postinst(deconf, "abort-deconfigure", "in-favour", pkgbin_name(infavour, &infavour->available, pnaw_nonambig), versiondescribe(&infavour->available.version, vdew_nonambig), NULL); } post_postinst_tasks(deconf, stat_installed); }
/* * Returns true if the file is used by pkg, false otherwise. */ bool dir_is_used_by_pkg(struct filenamenode *file, struct pkginfo *pkg, struct fileinlist *list) { struct fileinlist *node; size_t namelen; debug(dbg_veryverbose, "dir_is_used_by_pkg '%s' (by %s)", file->name, pkg ? pkg_name(pkg, pnaw_always) : "<none>"); namelen = strlen(file->name); for (node = list; node; node = node->next) { debug(dbg_veryverbose, "dir_is_used_by_pkg considering %s ...", node->namenode->name); if (strncmp(file->name, node->namenode->name, namelen) == 0 && strlen(node->namenode->name) > namelen && node->namenode->name[namelen] == '/') { debug(dbg_veryverbose, "dir_is_used_by_pkg yes"); return true; } } debug(dbg_veryverbose, "dir_is_used_by_pkg no"); return false; }
void trigproc_run_deferred(void) { jmp_buf ejbuf; debug(dbg_triggers, "trigproc_run_deferred"); while (!pkg_queue_is_empty(&deferred)) { struct pkginfo *pkg; pkg = pkg_queue_pop(&deferred); if (!pkg) continue; if (setjmp(ejbuf)) { pop_error_context(ehflag_bombout); continue; } push_error_context_jump(&ejbuf, print_error_perpackage, pkg_name(pkg, pnaw_nonambig)); pkg->clientdata->trigprocdeferred = NULL; trigproc(pkg, TRIGPROC_TRY); pop_error_context(ehflag_normaltidy); } }
static const char * parse_awaiter_package(void) { struct dpkg_error err = DPKG_ERROR_INIT; struct pkginfo *pkg; if (!f_await) bypackage = "-"; if (bypackage == NULL) { const char *pkgname, *archname; pkgname = getenv("DPKG_MAINTSCRIPT_PACKAGE"); archname = getenv("DPKG_MAINTSCRIPT_ARCH"); if (pkgname == NULL || archname == NULL) ohshit(_("must be called from a maintainer script" " (or with a --by-package option)")); pkg = pkg_spec_find_pkg(pkgname, archname, &err); } else if (strcmp(bypackage, "-") == 0) { pkg = NULL; } else { pkg = pkg_spec_parse_pkg(bypackage, &err); } /* Normalize the bypackage name if there was no error. */ if (pkg) bypackage = pkg_name(pkg, pnaw_nonambig); return err.str; }
static void breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok, struct deppossi *breaks, struct pkginfo *broken, struct pkginfo *breaker, struct pkgset *virtbroken) { struct varbuf depmsg = VARBUF_INIT; debug(dbg_depcondetail, " checking breaker %s virtbroken %s", pkg_name(breaker, pnaw_always), virtbroken ? virtbroken->name : "<none>"); if (breaker->status == stat_notinstalled || breaker->status == stat_configfiles) return; if (broken == breaker) return; if (!versionsatisfied(&broken->installed, breaks)) return; /* The test below can only trigger if dep_breaks start having * arch qualifiers different from “any”. */ if (!archsatisfied(&broken->installed, breaks)) return; if (ignore_depends(breaker)) return; if (virtbroken && ignore_depends(&virtbroken->pkg)) return; varbufdependency(&depmsg, breaks->up); varbuf_end_str(&depmsg); varbuf_printf(aemsgs, _(" %s (%s) breaks %s and is %s.\n"), pkg_name(breaker, pnaw_nonambig), versiondescribe(&breaker->installed.version, vdew_nonambig), depmsg.buf, gettext(statusstrings[breaker->status])); varbuf_destroy(&depmsg); if (virtbroken) { varbuf_printf(aemsgs, _(" %s (%s) provides %s.\n"), pkg_name(broken, pnaw_nonambig), versiondescribe(&broken->installed.version, vdew_nonambig), virtbroken->name); } else if (breaks->verrel != dpkg_relation_none) { varbuf_printf(aemsgs, _(" Version of %s to be configured is %s.\n"), pkg_name(broken, pnaw_nonambig), versiondescribe(&broken->installed.version, vdew_nonambig)); if (fc_dependsversion) return; } if (force_breaks(breaks)) return; *ok = dep_check_halt; }
/* * Called by modstatdb_note. */ void trig_activate_packageprocessing(struct pkginfo *pkg) { debug(dbg_triggersdetail, "trigproc_activate_packageprocessing pkg=%s", pkg_name(pkg, pnaw_always)); trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed, TRIGGERSCIFILE), NULL, trig_cicb_statuschange_activate, pkg, &pkg->installed); }
static struct pkginfo * pkg_array_mapper(const char *name) { struct pkginfo *pkg; pkg = dpkg_options_parse_pkgname(cipaction, name); if (pkg->status == PKG_STAT_NOTINSTALLED) notice(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig)); return pkg; }
static bool tortoise_not_in_hare(struct pkginfo *processing_now, struct trigcycleperpkg *tortoise_pkg) { const char *processing_now_name, *tortoise_name; struct trigpend *hare_trig, *tortoise_trig; processing_now_name = pkg_name(processing_now, pnaw_nonambig); tortoise_name = pkg_name(tortoise_pkg->pkg, pnaw_nonambig); debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s", __func__, processing_now_name, tortoise_name); for (tortoise_trig = tortoise_pkg->then_trigs; tortoise_trig; tortoise_trig = tortoise_trig->next) { debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s tortoisetrig=%s", __func__, processing_now_name, tortoise_name, tortoise_trig->name); /* hare is now so we can just look up in the actual data. */ for (hare_trig = tortoise_pkg->pkg->trigpend_head; hare_trig; hare_trig = hare_trig->next) { debug(dbg_triggersstupid, "%s pnow=%s tortoise=%s" " tortoisetrig=%s haretrig=%s", __func__, processing_now_name, tortoise_name, tortoise_trig->name, hare_trig->name); if (strcmp(hare_trig->name, tortoise_trig->name) == 0) break; } if (hare_trig == NULL) { /* Not found in hare, yay! */ debug(dbg_triggersdetail, "%s pnow=%s tortoise=%s OK", __func__, processing_now_name, tortoise_name); return true; } } return false; }
static void trigproc_enqueue_deferred(struct pkginfo *pend) { if (f_triggers < 0) return; ensure_package_clientdata(pend); if (pend->clientdata->trigprocdeferred) return; pend->clientdata->trigprocdeferred = pkg_queue_push(&deferred, pend); debug(dbg_triggers, "trigproc_enqueue_deferred pend=%s", pkg_name(pend, pnaw_always)); }
static void describebriefly(struct pkginfo *pkg) { int maxl, l; const char *pdesc; maxl= 57; l= strlen(pkg->set->name); if (l>20) maxl -= (l-20); pdesc = pkgbin_summary(pkg, &pkg->installed, &l); l = min(l, maxl); printf(" %-20s %.*s\n", pkg_name(pkg, pnaw_nonambig), l, pdesc); }
static void getsel1package(struct pkginfo *pkg) { const char *pkgname; int l; if (pkg->want == want_unknown) return; pkgname = pkg_name(pkg, pnaw_nonambig); l = strlen(pkgname); l >>= 3; l = 6 - l; if (l < 1) l = 1; printf("%s%.*s%s\n", pkgname, l, "\t\t\t\t\t\t", wantinfos[pkg->want].name); }
/* * Returns true if the directory contains conffiles belonging to pkg, * false otherwise. */ bool dir_has_conffiles(struct filenamenode *file, struct pkginfo *pkg) { struct conffile *conff; size_t namelen; debug(dbg_veryverbose, "dir_has_conffiles '%s' (from %s)", file->name, pkg_name(pkg, pnaw_always)); namelen = strlen(file->name); for (conff= pkg->installed.conffiles; conff; conff= conff->next) { if (conff->obsolete) continue; if (strncmp(file->name, conff->name, namelen) == 0 && strlen(conff->name) > namelen && conff->name[namelen] == '/') { debug(dbg_veryverbose, "directory %s has conffile %s from %s", file->name, conff->name, pkg_name(pkg, pnaw_always)); return true; } } debug(dbg_veryverbose, "dir_has_conffiles no"); return false; }
/* * Note: If anyone wants to set some triggers-pending, they must also * set status appropriately, or we will undo it. That is, it is legal * to call this when pkg->status and pkg->trigpend_head disagree and * in that case pkg->status takes precedence and pkg->trigpend_head * will be adjusted. */ void modstatdb_note(struct pkginfo *pkg) { struct trigaw *ta; onerr_abort++; /* Clear pending triggers here so that only code that sets the status * to interesting (for triggers) values has to care about triggers. */ if (pkg->status != stat_triggerspending && pkg->status != stat_triggersawaited) pkg->trigpend_head = NULL; if (pkg->status <= stat_configfiles) { for (ta = pkg->trigaw.head; ta; ta = ta->sameaw.next) ta->aw = NULL; pkg->trigaw.head = pkg->trigaw.tail = NULL; } log_message("status %s %s %s", statusinfos[pkg->status].name, pkg_name(pkg, pnaw_always), versiondescribe(&pkg->installed.version, vdew_nonambig)); statusfd_send("status: %s: %s", pkg_name(pkg, pnaw_nonambig), statusinfos[pkg->status].name); if (cstatus >= msdbrw_write) modstatdb_note_core(pkg); if (!pkg->trigpend_head && pkg->othertrigaw_head) { /* Automatically remove us from other packages' Triggers-Awaited. * We do this last because we want to maximize our chances of * successfully recording the status of the package we were * pointed at by our caller, although there is some risk of * leaving us in a slightly odd situation which is cleared up * by the trigger handling logic in deppossi_ok_found. */ trig_clear_awaiters(pkg); } onerr_abort--; }
static void getsel1package(struct pkginfo *pkg) { const char *pkgname; int l; if (pkg->want == PKG_WANT_UNKNOWN) return; pkgname = pkg_name(pkg, pnaw_nonambig); l = strlen(pkgname); l >>= 3; l = 6 - l; if (l < 1) l = 1; printf("%s%.*s%s\n", pkgname, l, "\t\t\t\t\t\t", pkg_want_name(pkg)); }
/** * Mark a conffile as obsolete. * * @param pkg The package owning the conffile. * @param namenode The namenode for the obsolete conffile. */ void conffile_mark_obsolete(struct pkginfo *pkg, struct filenamenode *namenode) { struct conffile *conff; for (conff = pkg->installed.conffiles; conff; conff = conff->next) { if (strcmp(conff->name, namenode->name) == 0) { debug(dbg_conff, "marking %s conffile %s as obsolete", pkg_name(pkg, pnaw_always), conff->name); conff->obsolete = true; return; } } }
static bool foundcyclebroken(struct cyclesofarlink *thislink, struct cyclesofarlink *sofar, struct pkginfo *dependedon, struct deppossi *possi) { struct cyclesofarlink *sol; if(!possi) return false; /* We're investigating the dependency ‘possi’ to see if it * is part of a loop. To this end we look to see whether the * depended-on package is already one of the packages whose * dependencies we're searching. */ for (sol = sofar; sol && sol->pkg != dependedon; sol = sol->prev); /* If not, we do a recursive search on it to see what we find. */ if (!sol) return findbreakcyclerecursive(dependedon, thislink); debug(dbg_depcon,"found cycle"); /* Right, we now break one of the links. We prefer to break * a dependency of a package without a postinst script, as * this is a null operation. If this is not possible we break * the other link in the recursive calling tree which mentions * this package (this being the first package involved in the * cycle). It doesn't particularly matter which we pick, but if * we break the earliest dependency we came across we may be * able to do something straight away when findbreakcycle returns. */ sofar= thislink; for (sol = sofar; !(sol != sofar && sol->pkg == dependedon); sol = sol->prev) { if (!pkg_infodb_has_file(sol->pkg, &sol->pkg->installed, POSTINSTFILE)) break; } /* Now we have either a package with no postinst, or the other * occurrence of the current package in the list. */ sol->possi->cyclebreak = true; debug(dbg_depcon, "cycle broken at %s -> %s", pkg_name(sol->possi->up->up, pnaw_always), sol->possi->ed->name); return true; }
/* * cstatus might be msdbrw_readonly if we're in --no-act mode, in which * case we don't write out all of the interest files etc. but we do * invent all of the activations for our own benefit. */ static void trig_transitional_activate(enum modstatdb_rw cstatus) { struct pkgiterator *iter; struct pkginfo *pkg; iter = pkg_db_iter_new(); while ((pkg = pkg_db_iter_next_pkg(iter))) { if (pkg->status <= PKG_STAT_HALFINSTALLED) continue; debug(dbg_triggersdetail, "trig_transitional_activate %s %s", pkg_name(pkg, pnaw_always), pkg_status_name(pkg)); pkg->trigpend_head = NULL; trig_parse_ci(pkg_infodb_get_file(pkg, &pkg->installed, TRIGGERSCIFILE), cstatus >= msdbrw_write ? transitional_interest_callback : transitional_interest_callback_ro, NULL, pkg, &pkg->installed); /* Ensure we're not creating incoherent data that can't * be written down. This should never happen in theory but * can happen if you restore an old status file that is * not in sync with the infodb files. */ if (pkg->status < PKG_STAT_TRIGGERSAWAITED) continue; if (pkg->trigaw.head) pkg_set_status(pkg, PKG_STAT_TRIGGERSAWAITED); else if (pkg->trigpend_head) pkg_set_status(pkg, PKG_STAT_TRIGGERSPENDING); else pkg_set_status(pkg, PKG_STAT_INSTALLED); } pkg_db_iter_free(iter); if (cstatus >= msdbrw_write) { modstatdb_checkpoint(); trig_file_interests_save(); } }
/* ARGSUSED */ static int add_shlibs_to_pkg(__unused void *actdata, struct pkg *pkg, const char *fpath, const char *name, bool is_shlib) { switch(filter_system_shlibs(name, NULL, 0)) { case EPKG_OK: /* A non-system library */ pkg_addshlib_required(pkg, name); return (EPKG_OK); case EPKG_END: /* A system library */ return (EPKG_OK); default: /* Ignore link resolution errors if we're analysing a shared library. */ if (is_shlib) return (EPKG_OK); warnx("(%s-%s) %s - shared library %s not found", pkg_name(pkg), pkg_version(pkg), fpath, name); return (EPKG_FATAL); } }
int verify(const char *const *argv) { struct pkginfo *pkg; int rc = 0; modstatdb_open(msdbrw_readonly); ensure_diversions(); if (!*argv) { struct pkgiterator *it; it = pkg_db_iter_new(); while ((pkg = pkg_db_iter_next_pkg(it))) verify_package(pkg); pkg_db_iter_free(it); } else { const char *thisarg; while ((thisarg = *argv++)) { pkg = dpkg_options_parse_pkgname(cipaction, thisarg); if (pkg->status == PKG_STAT_NOTINSTALLED) { notice(_("package '%s' is not installed"), pkg_name(pkg, pnaw_nonambig)); rc = 1; continue; } verify_package(pkg); } } modstatdb_shutdown(); m_output(stdout, _("<standard output>")); return rc; }
void describedepcon(struct varbuf *addto, struct dependency *dep) { const char *fmt; struct varbuf depstr = VARBUF_INIT; switch (dep->type) { case dep_depends: fmt = _("%s depends on %s"); break; case dep_predepends: fmt = _("%s pre-depends on %s"); break; case dep_recommends: fmt = _("%s recommends %s"); break; case dep_suggests: fmt = _("%s suggests %s"); break; case dep_breaks: fmt = _("%s breaks %s"); break; case dep_conflicts: fmt = _("%s conflicts with %s"); break; case dep_enhances: fmt = _("%s enhances %s"); break; default: internerr("unknown deptype '%d'", dep->type); } varbufdependency(&depstr, dep); varbuf_end_str(&depstr); varbuf_printf(addto, fmt, pkg_name(dep->up, pnaw_nonambig), depstr.buf); varbuf_destroy(&depstr); }
static void modstatdb_note_core(struct pkginfo *pkg) { assert(cstatus >= msdbrw_write); varbuf_reset(&uvb); varbufrecord(&uvb, pkg, &pkg->installed); if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used) ohshite(_("unable to write updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fflush(importanttmp)) ohshite(_("unable to flush updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (ftruncate(fileno(importanttmp), uvb.used)) ohshite(_("unable to truncate for updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fsync(fileno(importanttmp))) ohshite(_("unable to fsync updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); if (fclose(importanttmp)) ohshite(_("unable to close updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); sprintf(updatefnrest, IMPORTANTFMT, nextupdate); if (rename(importanttmpfile, updatefnbuf)) ohshite(_("unable to install updated status of `%.250s'"), pkg_name(pkg, pnaw_nonambig)); dir_sync_path(updatesdir); /* Have we made a real mess? */ assert(strlen(updatefnrest) <= IMPORTANTMAXLEN); nextupdate++; if (nextupdate > MAXUPDATES) { modstatdb_checkpoint(); nextupdate = 0; } createimptmp(); }
/* * 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); } }
/* * *whynot must already have been initialized; it need not be * empty though - it will be reset before use. * * If depisok returns false for ‘not OK’ it will contain a description, * newline-terminated BUT NOT NUL-TERMINATED, of the reason. * * If depisok returns true it will contain garbage. * allowunconfigd should be non-zero during the ‘Pre-Depends’ checking * before a package is unpacked, when it is sufficient for the package * to be unpacked provided that both the unpacked and previously-configured * versions are acceptable. * * On false return (‘not OK’), *canfixbyremove refers to a package which * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix * the problem. Caller may pass NULL for canfixbyremove and need not * initialize *canfixbyremove. * * On false return (‘not OK’), *canfixbytrigaw refers to a package which * can fix the problem if all the packages listed in Triggers-Awaited have * their triggers processed. Caller may pass NULL for canfixbytrigaw and * need not initialize *canfixbytrigaw. */ bool depisok(struct dependency *dep, struct varbuf *whynot, struct pkginfo **canfixbyremove, struct pkginfo **canfixbytrigaw, bool allowunconfigd) { struct deppossi *possi; struct deppossi *provider; struct pkginfo *pkg_pos; int nconflicts; /* Use this buffer so that when internationalisation comes along we * don't have to rewrite the code completely, only redo the sprintf strings * (assuming we have the fancy argument-number-specifiers). * Allow 250x3 for package names, versions, &c, + 250 for ourselves. */ char linebuf[1024]; assert(dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_breaks || dep->type == dep_conflicts || dep->type == dep_recommends || dep->type == dep_suggests || dep->type == dep_enhances); if (canfixbyremove) *canfixbyremove = NULL; if (canfixbytrigaw) *canfixbytrigaw = NULL; /* The dependency is always OK if we're trying to remove the depend*ing* * package. */ switch (dep->up->clientdata->istobe) { case PKG_ISTOBE_REMOVE: case PKG_ISTOBE_DECONFIGURE: return true; case PKG_ISTOBE_NORMAL: /* Only installed packages can be make dependency problems. */ switch (dep->up->status) { case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: break; case PKG_STAT_HALFCONFIGURED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFINSTALLED: if (dep->type == dep_predepends || dep->type == dep_conflicts || dep->type == dep_breaks) break; /* Fall through. */ case PKG_STAT_CONFIGFILES: case PKG_STAT_NOTINSTALLED: return true; default: internerr("unknown status depending '%d'", dep->up->status); } break; case PKG_ISTOBE_INSTALLNEW: case PKG_ISTOBE_PREINSTALL: break; default: internerr("unknown istobe depending '%d'", dep->up->clientdata->istobe); } /* Describe the dependency, in case we have to moan about it. */ varbuf_reset(whynot); varbuf_add_char(whynot, ' '); describedepcon(whynot, dep); varbuf_add_char(whynot, '\n'); /* TODO: Check dep_enhances as well. */ if (dep->type == dep_depends || dep->type == dep_predepends || dep->type == dep_recommends || dep->type == dep_suggests ) { /* Go through the alternatives. As soon as we find one that * we like, we return ‘true’ straight away. Otherwise, when we get to * the end we'll have accumulated all the reasons in whynot and * can return ‘false’. */ for (possi= dep->list; possi; possi= possi->next) { struct deppossi_pkg_iterator *possi_iter; possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { switch (pkg_pos->clientdata->istobe) { case PKG_ISTOBE_REMOVE: sprintf(linebuf, _(" %.250s is to be removed.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; case PKG_ISTOBE_DECONFIGURE: sprintf(linebuf, _(" %.250s is to be deconfigured.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; case PKG_ISTOBE_INSTALLNEW: if (versionsatisfied(&pkg_pos->available, possi)) { deppossi_pkg_iter_free(possi_iter); return true; } sprintf(linebuf, _(" %.250s is to be installed, but is version " "%.250s.\n"), pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig), versiondescribe(&pkg_pos->available.version, vdew_nonambig)); break; case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (pkg_pos->status) { case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: if (versionsatisfied(&pkg_pos->installed, possi)) { deppossi_pkg_iter_free(possi_iter); return true; } sprintf(linebuf, _(" %.250s is installed, but is version " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig)); break; case PKG_STAT_NOTINSTALLED: /* Don't say anything about this yet - it might be a virtual package. * Later on, if nothing has put anything in linebuf, we know that it * isn't and issue a diagnostic then. */ *linebuf = '\0'; break; case PKG_STAT_TRIGGERSAWAITED: if (canfixbytrigaw && versionsatisfied(&pkg_pos->installed, possi)) *canfixbytrigaw = pkg_pos; /* Fall through to have a chance to return OK due to * allowunconfigd and to fill the explanation */ case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (allowunconfigd) { if (!dpkg_version_is_informative(&pkg_pos->configversion)) { sprintf(linebuf, _(" %.250s is unpacked, but has never been " "configured.\n"), pkg_name(pkg_pos, pnaw_nonambig)); break; } else if (!versionsatisfied(&pkg_pos->installed, possi)) { sprintf(linebuf, _(" %.250s is unpacked, but is version " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig)); break; } else if (!dpkg_version_relate(&pkg_pos->configversion, possi->verrel, &possi->version)) { sprintf(linebuf, _(" %.250s latest configured version is " "%.250s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->configversion, vdew_nonambig)); break; } else { deppossi_pkg_iter_free(possi_iter); return true; } } /* Fall through. */ default: sprintf(linebuf, _(" %.250s is %s.\n"), pkg_name(pkg_pos, pnaw_nonambig), gettext(statusstrings[pkg_pos->status])); break; } break; default: internerr("unknown istobe depended '%d'", pkg_pos->clientdata->istobe); } varbuf_add_str(whynot, linebuf); } deppossi_pkg_iter_free(possi_iter); /* See if the package we're about to install Provides it. */ for (provider = possi->ed->depended.available; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; if (provider->up->up->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) return true; } /* Now look at the packages already on the system. */ for (provider = possi->ed->depended.installed; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; switch (provider->up->up->clientdata->istobe) { case PKG_ISTOBE_INSTALLNEW: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that by using the available * information above. */ continue; case PKG_ISTOBE_REMOVE: sprintf(linebuf, _(" %.250s provides %.250s but is to be removed.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name); break; case PKG_ISTOBE_DECONFIGURE: sprintf(linebuf, _(" %.250s provides %.250s but is to be deconfigured.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name); break; case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: if (provider->up->up->status == PKG_STAT_INSTALLED || provider->up->up->status == PKG_STAT_TRIGGERSPENDING) return true; if (provider->up->up->status == PKG_STAT_TRIGGERSAWAITED) *canfixbytrigaw = provider->up->up; sprintf(linebuf, _(" %.250s provides %.250s but is %s.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name, gettext(statusstrings[provider->up->up->status])); break; default: internerr("unknown istobe provider '%d'", provider->up->up->clientdata->istobe); } varbuf_add_str(whynot, linebuf); } if (!*linebuf) { /* If the package wasn't installed at all, and we haven't said * yet why this isn't satisfied, we should say so now. */ sprintf(linebuf, _(" %.250s is not installed.\n"), possi->ed->name); varbuf_add_str(whynot, linebuf); } } return false; } else { /* It's conflicts or breaks. There's only one main alternative, * but we also have to consider Providers. We return ‘false’ as soon * as we find something that matches the conflict, and only describe * it then. If we get to the end without finding anything we return * ‘true’. */ possi= dep->list; nconflicts= 0; if (possi->ed != possi->up->up->set) { struct deppossi_pkg_iterator *possi_iter; /* If the package conflicts with or breaks itself it must mean * other packages which provide the same virtual name. We * therefore don't look at the real package and go on to the * virtual ones. */ possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { switch (pkg_pos->clientdata->istobe) { case PKG_ISTOBE_REMOVE: break; case PKG_ISTOBE_INSTALLNEW: if (!versionsatisfied(&pkg_pos->available, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is to be installed.\n"), pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig), versiondescribe(&pkg_pos->available.version, vdew_nonambig)); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) { deppossi_pkg_iter_free(possi_iter); return false; } nconflicts++; *canfixbyremove = pkg_pos; break; case PKG_ISTOBE_DECONFIGURE: if (dep->type == dep_breaks) break; /* Already deconfiguring this. */ /* Fall through. */ case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (pkg_pos->status) { case PKG_STAT_NOTINSTALLED: case PKG_STAT_CONFIGFILES: break; case PKG_STAT_HALFINSTALLED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (dep->type == dep_breaks) break; /* No problem. */ case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: if (!versionsatisfied(&pkg_pos->installed, possi)) break; sprintf(linebuf, _(" %.250s (version %.250s) is present and %s.\n"), pkg_name(pkg_pos, pnaw_nonambig), versiondescribe(&pkg_pos->installed.version, vdew_nonambig), gettext(statusstrings[pkg_pos->status])); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) { deppossi_pkg_iter_free(possi_iter); return false; } nconflicts++; *canfixbyremove = pkg_pos; } break; default: internerr("unknown istobe conflict '%d'", pkg_pos->clientdata->istobe); } } deppossi_pkg_iter_free(possi_iter); } /* See if the package we're about to install Provides it. */ for (provider = possi->ed->depended.available; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->clientdata->istobe != PKG_ISTOBE_INSTALLNEW) continue; if (provider->up->up->set == dep->up->set) continue; /* Conflicts and provides the same. */ if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; sprintf(linebuf, _(" %.250s provides %.250s and is to be installed.\n"), pkgbin_name(provider->up->up, &provider->up->up->available, pnaw_nonambig), possi->ed->name); varbuf_add_str(whynot, linebuf); /* We can't remove the one we're about to install: */ if (canfixbyremove) *canfixbyremove = NULL; return false; } /* Now look at the packages already on the system. */ for (provider = possi->ed->depended.installed; provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; if (provider->up->up->set == dep->up->set) continue; /* Conflicts and provides the same. */ if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; switch (provider->up->up->clientdata->istobe) { case PKG_ISTOBE_INSTALLNEW: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying * to install. We dealt with that package by using the * available information above. */ continue; case PKG_ISTOBE_REMOVE: continue; case PKG_ISTOBE_DECONFIGURE: if (dep->type == dep_breaks) continue; /* Already deconfiguring. */ case PKG_ISTOBE_NORMAL: case PKG_ISTOBE_PREINSTALL: switch (provider->up->up->status) { case PKG_STAT_NOTINSTALLED: case PKG_STAT_CONFIGFILES: continue; case PKG_STAT_HALFINSTALLED: case PKG_STAT_UNPACKED: case PKG_STAT_HALFCONFIGURED: if (dep->type == dep_breaks) break; /* No problem. */ case PKG_STAT_INSTALLED: case PKG_STAT_TRIGGERSPENDING: case PKG_STAT_TRIGGERSAWAITED: sprintf(linebuf, _(" %.250s provides %.250s and is present and %s.\n"), pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name, gettext(statusstrings[provider->up->up->status])); varbuf_add_str(whynot, linebuf); if (!canfixbyremove) return false; nconflicts++; *canfixbyremove= provider->up->up; break; } break; default: internerr("unknown istobe conflict provider '%d'", provider->up->up->clientdata->istobe); } } if (!nconflicts) return true; if (nconflicts > 1) *canfixbyremove = NULL; return false; } /* if (dependency) {...} else {...} */ }
/** * Cycle breaking works recursively down the package dependency tree. * * ‘sofar’ is the list of packages we've descended down already - if we * encounter any of its packages again in a dependency we have found a cycle. */ static bool findbreakcyclerecursive(struct pkginfo *pkg, struct cyclesofarlink *sofar) { struct cyclesofarlink thislink, *sol; struct dependency *dep; struct deppossi *possi, *providelink; struct pkginfo *provider, *pkg_pos; if (pkg->clientdata->color == PKG_CYCLE_BLACK) return false; pkg->clientdata->color = PKG_CYCLE_GRAY; if (debug_has_flag(dbg_depcondetail)) { struct varbuf str_pkgs = VARBUF_INIT; for (sol = sofar; sol; sol = sol->prev) { varbuf_add_str(&str_pkgs, " <- "); varbuf_add_pkgbin_name(&str_pkgs, sol->pkg, &sol->pkg->installed, pnaw_nonambig); } varbuf_end_str(&str_pkgs); debug(dbg_depcondetail, "findbreakcyclerecursive %s %s", pkg_name(pkg, pnaw_always), str_pkgs.buf); varbuf_destroy(&str_pkgs); } thislink.pkg= pkg; thislink.prev = sofar; thislink.possi = NULL; for (dep= pkg->installed.depends; dep; dep= dep->next) { if (dep->type != dep_depends && dep->type != dep_predepends) continue; for (possi= dep->list; possi; possi= possi->next) { struct deppossi_pkg_iterator *possi_iter; /* Don't find the same cycles again. */ if (possi->cyclebreak) continue; thislink.possi= possi; possi_iter = deppossi_pkg_iter_new(possi, wpb_installed); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) if (foundcyclebroken(&thislink, sofar, pkg_pos, possi)) { deppossi_pkg_iter_free(possi_iter); return true; } deppossi_pkg_iter_free(possi_iter); /* Right, now we try all the providers ... */ for (providelink = possi->ed->depended.installed; providelink; providelink = providelink->rev_next) { if (providelink->up->type != dep_provides) continue; provider= providelink->up->up; if (provider->clientdata->istobe == PKG_ISTOBE_NORMAL) continue; /* We don't break things at ‘provides’ links, so ‘possi’ is * still the one we use. */ if (foundcyclebroken(&thislink, sofar, provider, possi)) return true; } } } /* Nope, we didn't find a cycle to break. */ pkg->clientdata->color = PKG_CYCLE_BLACK; return false; }