static bool ignore_depends_possi(struct deppossi *possi) { struct deppossi_pkg_iterator *possi_iter; struct pkginfo *pkg; possi_iter = deppossi_pkg_iter_new(possi, wpb_installed); while ((pkg = deppossi_pkg_iter_next(possi_iter))) { if (ignore_depends(pkg)) { deppossi_pkg_iter_free(possi_iter); return true; } } deppossi_pkg_iter_free(possi_iter); return false; }
/* * *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; }
/** * Print a single package which: * (a) is the target of one or more relevant predependencies. * (b) has itself no unsatisfied pre-dependencies. * * If such a package is present output is the Packages file entry, * which can be massaged as appropriate. * * Exit status: * 0 = a package printed, OK * 1 = no suitable package available * 2 = error */ int predeppackage(const char *const *argv) { static struct varbuf vb; struct pkgiterator *it; struct pkginfo *pkg = NULL, *startpkg, *trypkg; struct dependency *dep; struct deppossi *possi, *provider; if (*argv) badusage(_("--%s takes no arguments"), cipaction->olong); modstatdb_open(msdbrw_readonly | msdbrw_available_readonly); /* We use clientdata->istobe to detect loops. */ clear_istobes(); dep = NULL; it = pkg_db_iter_new(); while (!dep && (pkg = pkg_db_iter_next_pkg(it))) { /* Ignore packages user doesn't want. */ if (pkg->want != PKG_WANT_INSTALL) continue; /* Ignore packages not available. */ if (!pkg->files) continue; pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; for (dep= pkg->available.depends; dep; dep= dep->next) { if (dep->type != dep_predepends) continue; if (depisok(dep, &vb, NULL, NULL, true)) continue; /* This will leave dep non-NULL, and so exit the loop. */ break; } pkg->clientdata->istobe = PKG_ISTOBE_NORMAL; /* If dep is NULL we go and get the next package. */ } pkg_db_iter_free(it); if (!dep) return 1; /* Not found. */ assert(pkg); startpkg= pkg; pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; /* OK, we have found an unsatisfied predependency. * Now go and find the first thing we need to install, as a first step * towards satisfying it. */ do { /* We search for a package which would satisfy dep, and put it in pkg. */ for (possi = dep->list, pkg = NULL; !pkg && possi; possi=possi->next) { struct deppossi_pkg_iterator *possi_iter; possi_iter = deppossi_pkg_iter_new(possi, wpb_available); while (!pkg && (trypkg = deppossi_pkg_iter_next(possi_iter))) { if (trypkg->files && trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL && versionsatisfied(&trypkg->available, possi)) { pkg = trypkg; break; } for (provider = possi->ed->depended.available; !pkg && provider; provider = provider->next) { if (provider->up->type != dep_provides) continue; if (!pkg_virtual_deppossi_satisfied(possi, provider)) continue; trypkg = provider->up->up; if (!trypkg->files) continue; if (trypkg->clientdata->istobe == PKG_ISTOBE_NORMAL) { pkg = trypkg; break; } } } deppossi_pkg_iter_free(possi_iter); } if (!pkg) { varbuf_reset(&vb); describedepcon(&vb,dep); varbuf_end_str(&vb); notice(_("cannot see how to satisfy pre-dependency:\n %s"), vb.buf); ohshit(_("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)"), pkgbin_name(dep->up, &dep->up->available, pnaw_nonambig), pkgbin_name(startpkg, &startpkg->available, pnaw_nonambig)); } pkg->clientdata->istobe = PKG_ISTOBE_PREINSTALL; for (dep= pkg->available.depends; dep; dep= dep->next) { if (dep->type != dep_predepends) continue; if (depisok(dep, &vb, NULL, NULL, true)) continue; /* This will leave dep non-NULL, and so exit the loop. */ break; } } while (dep); /* OK, we've found it - pkg has no unsatisfied pre-dependencies! */ writerecord(stdout, _("<standard output>"), pkg, &pkg->available); m_output(stdout, _("<standard output>")); return 0; }
/* * Checks [Pre]-Depends only. */ enum dep_check dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing, struct varbuf *aemsgs) { /* Valid values: 2 = ok, 1 = defer, 0 = halt. */ enum dep_check ok; /* Valid values: 0 = none, 1 = defer, 2 = withwarning, 3 = ok. */ enum found_status found, thisf; int interestingwarnings; bool matched, anycannotfixbytrig; struct varbuf oemsgs = VARBUF_INIT; struct dependency *dep; struct deppossi *possi, *provider; struct pkginfo *possfixbytrig, *canfixbytrig; interestingwarnings= 0; ok = DEP_CHECK_OK; debug(dbg_depcon,"checking dependencies of %s (- %s)", pkg_name(pkg, pnaw_always), removing ? pkg_name(removing, pnaw_always) : "<none>"); anycannotfixbytrig = false; canfixbytrig = NULL; for (dep= pkg->installed.depends; dep; dep= dep->next) { if (dep->type != dep_depends && dep->type != dep_predepends) continue; debug(dbg_depcondetail," checking group ..."); matched = false; varbuf_reset(&oemsgs); found = FOUND_NONE; possfixbytrig = NULL; for (possi = dep->list; found != FOUND_OK && possi; possi = possi->next) { struct deppossi_pkg_iterator *possi_iter; struct pkginfo *pkg_pos; debug(dbg_depcondetail," checking possibility -> %s",possi->ed->name); if (possi->cyclebreak) { debug(dbg_depcondetail," break cycle so ok and found"); found = FOUND_OK; break; } thisf = FOUND_NONE; possi_iter = deppossi_pkg_iter_new(possi, wpb_installed); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { thisf = deppossi_ok_found(pkg_pos, pkg, removing, NULL, &possfixbytrig, &matched, possi, &interestingwarnings, &oemsgs); if (thisf > found) found = thisf; if (found == FOUND_OK) break; } deppossi_pkg_iter_free(possi_iter); if (found != FOUND_OK) { for (provider = possi->ed->depended.installed; found != FOUND_OK && provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; debug(dbg_depcondetail, " checking provider %s", pkg_name(provider->up->up, pnaw_always)); if (!deparchsatisfied(&provider->up->up->installed, provider->arch, possi)) { debug(dbg_depcondetail, " provider does not satisfy arch"); continue; } thisf = deppossi_ok_found(provider->up->up, pkg, removing, provider, &possfixbytrig, &matched, possi, &interestingwarnings, &oemsgs); if (thisf == FOUND_DEFER && provider->up->up == pkg && !removing) { /* IOW, if the pkg satisfies its own dep (via a provide), then * we let it pass, even if it isn't configured yet (as we're * installing it). */ thisf = FOUND_OK; } if (thisf > found) found = thisf; } } debug(dbg_depcondetail," found %d",found); if (thisf > found) found= thisf; } if (in_force(FORCE_DEPENDS)) { thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS); if (thisf > found) { found = thisf; debug(dbg_depcondetail, " rescued by force-depends, found %d", found); } } debug(dbg_depcondetail, " found %d matched %d possfixbytrig %s", found, matched, possfixbytrig ? pkg_name(possfixbytrig, pnaw_always) : "-"); if (removing && !matched) continue; switch (found) { case FOUND_NONE: anycannotfixbytrig = true; ok = DEP_CHECK_HALT; /* Fall through. */ case FOUND_FORCED: varbuf_add_str(aemsgs, " "); varbuf_add_pkgbin_name(aemsgs, pkg, &pkg->installed, pnaw_nonambig); varbuf_add_str(aemsgs, _(" depends on ")); varbufdependency(aemsgs, dep); if (interestingwarnings) { /* Don't print the line about the package to be removed if * that's the only line. */ varbuf_end_str(&oemsgs); varbuf_add_str(aemsgs, _("; however:\n")); varbuf_add_str(aemsgs, oemsgs.buf); } else { varbuf_add_str(aemsgs, ".\n"); } break; case FOUND_DEFER: if (possfixbytrig) canfixbytrig = possfixbytrig; else anycannotfixbytrig = true; if (ok > DEP_CHECK_DEFER) ok = DEP_CHECK_DEFER; break; case FOUND_OK: break; default: internerr("unknown value for found '%d'", found); } } if (ok == DEP_CHECK_HALT && (pkg->clientdata && pkg->clientdata->istobe == PKG_ISTOBE_REMOVE)) ok = DEP_CHECK_DEFER; if (!anycannotfixbytrig && canfixbytrig) progress_bytrigproc = canfixbytrig; varbuf_destroy(&oemsgs); debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, (int)aemsgs->used, aemsgs->buf); return ok; }
/* * Checks [Pre]-Depends only. */ enum dep_check dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing, struct varbuf *aemsgs) { /* Valid values: 2 = ok, 1 = defer, 0 = halt. */ enum dep_check ok; /* Valid values: 0 = none, 1 = defer, 2 = withwarning, 3 = ok. */ enum found_status found, thisf; int interestingwarnings; bool matched, anycannotfixbytrig; struct varbuf oemsgs = VARBUF_INIT; struct dependency *dep; struct deppossi *possi, *provider; struct pkginfo *possfixbytrig, *canfixbytrig; interestingwarnings= 0; ok = dep_check_ok; debug(dbg_depcon,"checking dependencies of %s (- %s)", pkg_name(pkg, pnaw_always), removing ? pkg_name(removing, pnaw_always) : "<none>"); anycannotfixbytrig = false; canfixbytrig = NULL; for (dep= pkg->installed.depends; dep; dep= dep->next) { if (dep->type != dep_depends && dep->type != dep_predepends) continue; debug(dbg_depcondetail," checking group ..."); matched = false; varbuf_reset(&oemsgs); found = found_none; possfixbytrig = NULL; for (possi = dep->list; found != found_ok && possi; possi = possi->next) { struct deppossi_pkg_iterator *possi_iter; struct pkginfo *pkg_pos; debug(dbg_depcondetail," checking possibility -> %s",possi->ed->name); if (possi->cyclebreak) { debug(dbg_depcondetail," break cycle so ok and found"); found = found_ok; break; } thisf = found_none; possi_iter = deppossi_pkg_iter_new(possi, wpb_installed); while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) { thisf = deppossi_ok_found(pkg_pos, pkg, removing, NULL, &possfixbytrig, &matched, possi, &interestingwarnings, &oemsgs); if (thisf > found) found = thisf; if (found == found_ok) break; } deppossi_pkg_iter_free(possi_iter); if (found != found_ok && possi->verrel == dpkg_relation_none) { for (provider = possi->ed->depended.installed; found != found_ok && provider; provider = provider->rev_next) { if (provider->up->type != dep_provides) continue; debug(dbg_depcondetail, " checking provider %s", pkg_name(provider->up->up, pnaw_always)); if (!deparchsatisfied(&provider->up->up->installed, provider->arch, possi)) { debug(dbg_depcondetail, " provider does not satisfy arch"); continue; } thisf = deppossi_ok_found(provider->up->up, pkg, removing, possi->ed, &possfixbytrig, &matched, NULL, &interestingwarnings, &oemsgs); if (thisf > found) found = thisf; } } debug(dbg_depcondetail," found %d",found); if (thisf > found) found= thisf; } if (fc_depends) { thisf = (dependtry >= 4) ? found_forced : found_defer; if (thisf > found) { found = thisf; debug(dbg_depcondetail, " rescued by force-depends, found %d", found); } } debug(dbg_depcondetail, " found %d matched %d possfixbytrig %s", found, matched, possfixbytrig ? pkg_name(possfixbytrig, pnaw_always) : "-"); if (removing && !matched) continue; switch (found) { case found_none: anycannotfixbytrig = true; ok = dep_check_halt; case found_forced: varbuf_add_str(aemsgs, " "); varbuf_add_pkgbin_name(aemsgs, pkg, &pkg->installed, pnaw_nonambig); varbuf_add_str(aemsgs, _(" depends on ")); varbufdependency(aemsgs, dep); if (interestingwarnings) { /* Don't print the line about the package to be removed if * that's the only line. */ varbuf_end_str(&oemsgs); varbuf_add_str(aemsgs, _("; however:\n")); varbuf_add_str(aemsgs, oemsgs.buf); } else { varbuf_add_str(aemsgs, ".\n"); } break; case found_defer: if (possfixbytrig) canfixbytrig = possfixbytrig; else anycannotfixbytrig = true; if (ok > dep_check_defer) ok = dep_check_defer; break; case found_ok: break; default: internerr("unknown value for found '%d'", found); } } if (ok == dep_check_halt && (pkg->clientdata && pkg->clientdata->istobe == itb_remove)) ok = dep_check_defer; if (!anycannotfixbytrig && canfixbytrig) progress_bytrigproc = canfixbytrig; varbuf_destroy(&oemsgs); debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, (int)aemsgs->used, aemsgs->buf); return ok; }