diff options
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | dselect/pkgdepcon.cc | 9 | ||||
-rw-r--r-- | dselect/pkgsublist.cc | 6 | ||||
-rw-r--r-- | lib/dpkg/depcon.c | 40 | ||||
-rw-r--r-- | lib/dpkg/dpkg-db.h | 4 | ||||
-rw-r--r-- | src/depcon.c | 15 | ||||
-rw-r--r-- | src/enquiry.c | 12 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/packages.c | 97 |
10 files changed, 145 insertions, 51 deletions
diff --git a/debian/changelog b/debian/changelog index 9a64ddae3..155b10edd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -24,6 +24,14 @@ dpkg (1.17.11) UNRELEASED; urgency=low * Do not write to the available file when unpacking binary packages. This information is not useful as dpkg has never recorded the archive path, so it has never been truly available for re-installation anyway. + * Add versioned Provides support: + - Add a new dpkg --assert-versioned-provides command. + - Packages can provide a specific version, “virtual (= 1.0)” which will + be honored, previously it would just be accepted when parsing. + - Non-versioned virtual packages will not satisfy versioned dependencies. + - Versioned virtual packages will satisfy non-versioned dependencies. + Based on skeletal code by Ben Collins <bcollins@debian.org>. + Closes: #7330, #24934, #112131, #134582, #180316 [ Updated programs translations ] * Danish (Joe Dalton). Closes: #754127 diff --git a/dselect/pkgdepcon.cc b/dselect/pkgdepcon.cc index 712c683f8..95f96e5cc 100644 --- a/dselect/pkgdepcon.cc +++ b/dselect/pkgdepcon.cc @@ -414,8 +414,7 @@ packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade) return false; } } - if (possi->verrel != DPKG_RELATION_NONE) - return false; + deppossi *provider; for (provider = possi->ed->depended.installed; @@ -427,7 +426,8 @@ packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade) provider->up->up->clientdata && !useavailable(provider->up->up) && would_like_to_install(provider->up->up->clientdata->selected, - provider->up->up)) + provider->up->up) && + pkg_virtual_deppossi_satisfied(possi, provider)) return true; } for (provider = possi->ed->depended.available; @@ -438,7 +438,8 @@ packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade) provider->up->up->set == possi->up->up->set) || !provider->up->up->clientdata || !would_like_to_install(provider->up->up->clientdata->selected, - provider->up->up)) + provider->up->up) || + !pkg_virtual_deppossi_satisfied(possi, provider)) continue; if (useavailable(provider->up->up)) return true; diff --git a/dselect/pkgsublist.cc b/dselect/pkgsublist.cc index c775dbb66..09e7da1bd 100644 --- a/dselect/pkgsublist.cc +++ b/dselect/pkgsublist.cc @@ -159,9 +159,9 @@ packagelist::add(dependency *depends, showpriority displayimportance) add(depends->up,info.string(),displayimportance); for (possi=depends->list; possi; possi=possi->next) { add(&possi->ed->pkg, info.string(), displayimportance); - if (possi->verrel == DPKG_RELATION_NONE && depends->type != dep_provides) { - // providers aren't relevant if a version was specified, or - // if we're looking at a provider relationship already + if (depends->type != dep_provides) { + /* Providers are not relevant if we are looking at a provider + * relationship already. */ deppossi *provider; for (provider = possi->ed->depended.available; provider; diff --git a/lib/dpkg/depcon.c b/lib/dpkg/depcon.c index cd8d8a0bd..52515ed65 100644 --- a/lib/dpkg/depcon.c +++ b/lib/dpkg/depcon.c @@ -83,3 +83,43 @@ archsatisfied(struct pkgbin *it, struct deppossi *against) { return deparchsatisfied(it, it->arch, against); } + +/** + * Check if the dependency is satisfied by a virtual package. + * + * For versioned depends, we only check providers with #DPKG_RELATION_EQ. It + * does not make sense to check ones without a version since we have nothing + * to verify against. Also, it is way too complex to allow anything but an + * equal in a provided version. A few examples below to deter you from trying: + * + * - pkg1 depends on virt (>= 0.6), pkg2 provides virt (<= 1.0). + * Should pass (easy enough). + * + * - pkg1 depends on virt (>= 0.7) and (<= 1.1), pkg2 provides virt (>= 1.2). + * Should fail (little harder). + * + * - pkg1 depends on virt (>= 0.4), pkg2 provides virt (<= 1.0) and (>= 0.5), + * IOW, inclusive of only those versions. This would require backchecking + * the other provided versions in the possi, which would make things sickly + * complex and overly time consuming. Should fail (very hard to implement). + * + * This could be handled by switching to a SAT solver, but that would imply + * lots of work for very little gain. Packages can easily get around most of + * these by providing multiple #DPKG_RELATION_EQ versions. + */ +bool +pkg_virtual_deppossi_satisfied(struct deppossi *dependee, + struct deppossi *provider) +{ + if (provider->verrel != DPKG_RELATION_NONE && + provider->verrel != DPKG_RELATION_EQ) + return false; + + if (provider->verrel == DPKG_RELATION_NONE && + dependee->verrel != DPKG_RELATION_NONE) + return false; + + return dpkg_version_relate(&provider->version, + dependee->verrel, + &dependee->version); +} diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h index 521f63481..9c46fa912 100644 --- a/lib/dpkg/dpkg-db.h +++ b/lib/dpkg/dpkg-db.h @@ -406,6 +406,10 @@ bool deparchsatisfied(struct pkgbin *it, const struct dpkg_arch *arch, struct deppossi *against); bool archsatisfied(struct pkgbin *it, struct deppossi *against); +bool +pkg_virtual_deppossi_satisfied(struct deppossi *dependee, + struct deppossi *provider); + /*** from nfmalloc.c ***/ void *nfmalloc(size_t); char *nfstrsave(const char*); diff --git a/src/depcon.c b/src/depcon.c index deedd5cbf..1f17c84d0 100644 --- a/src/depcon.c +++ b/src/depcon.c @@ -460,13 +460,13 @@ depisok(struct dependency *dep, struct varbuf *whynot, } deppossi_pkg_iter_free(possi_iter); - /* If there was no version specified we try looking for Providers. */ - if (possi->verrel == DPKG_RELATION_NONE) { /* 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; } @@ -476,6 +476,8 @@ depisok(struct dependency *dep, struct varbuf *whynot, 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: @@ -519,7 +521,6 @@ depisok(struct dependency *dep, struct varbuf *whynot, sprintf(linebuf, _(" %.250s is not installed.\n"), possi->ed->name); varbuf_add_str(whynot, linebuf); } - } } return false; @@ -600,8 +601,6 @@ depisok(struct dependency *dep, struct varbuf *whynot, deppossi_pkg_iter_free(possi_iter); } - /* If there was no version specified we try looking for Providers. */ - if (possi->verrel == DPKG_RELATION_NONE) { /* See if the package we're about to install Provides it. */ for (provider = possi->ed->depended.available; provider; @@ -611,6 +610,8 @@ depisok(struct dependency *dep, struct varbuf *whynot, 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); @@ -630,6 +631,9 @@ depisok(struct dependency *dep, struct varbuf *whynot, 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 @@ -673,7 +677,6 @@ depisok(struct dependency *dep, struct varbuf *whynot, provider->up->up->clientdata->istobe); } } - } if (!nconflicts) return true; diff --git a/src/enquiry.c b/src/enquiry.c index f1597b002..e3f49cfbb 100644 --- a/src/enquiry.c +++ b/src/enquiry.c @@ -432,6 +432,14 @@ assertmultiarch(const char *const *argv) return assert_version_support(argv, &version, _("multi-arch")); } +int +assertverprovides(const char *const *argv) +{ + struct dpkg_version version = { 0, "1.17.11", NULL }; + + return assert_version_support(argv, &version, _("versioned Provides")); +} + /** * Print a single package which: * (a) is the target of one or more relevant predependencies. @@ -508,13 +516,13 @@ predeppackage(const char *const *argv) pkg = trypkg; break; } - if (possi->verrel != DPKG_RELATION_NONE) - continue; 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; diff --git a/src/main.c b/src/main.c index 73e746003..6e15f3fd3 100644 --- a/src/main.c +++ b/src/main.c @@ -126,7 +126,7 @@ usage(const struct cmdinfo *ci, const char *value) printf(_( "For internal use: dpkg --assert-support-predepends | --predep-package |\n" " --assert-working-epoch | --assert-long-filenames | --assert-multi-conrep |\n" -" --assert-multi-arch.\n" +" --assert-multi-arch | --assert-versioned-provides.\n" "\n")); printf(_( @@ -672,6 +672,7 @@ static const struct cmdinfo cmdinfos[]= { ACTION( "assert-long-filenames", 0, act_assertlongfilenames, assertlongfilenames ), ACTION( "assert-multi-conrep", 0, act_assertmulticonrep, assertmulticonrep ), ACTION( "assert-multi-arch", 0, act_assertmultiarch, assertmultiarch ), + ACTION( "assert-versioned-provides", 0, act_assertverprovides, assertverprovides ), ACTION( "add-architecture", 0, act_arch_add, arch_add ), ACTION( "remove-architecture", 0, act_arch_remove, arch_remove ), ACTION( "print-architecture", 0, act_printarch, printarch ), diff --git a/src/main.h b/src/main.h index 10014ef0e..5a35808ab 100644 --- a/src/main.h +++ b/src/main.h @@ -101,6 +101,7 @@ enum action { act_assertlongfilenames, act_assertmulticonrep, act_assertmultiarch, + act_assertverprovides, act_audit, act_unpackchk, @@ -165,6 +166,7 @@ int assertpredep(const char *const *argv); int assertlongfilenames(const char *const *argv); int assertmulticonrep(const char *const *argv); int assertmultiarch(const char *const *argv); +int assertverprovides(const char *const *argv); int predeppackage(const char *const *argv); int printarch(const char *const *argv); int printinstarch(const char *const *argv); diff --git a/src/packages.c b/src/packages.c index fed0a4893..597c0c572 100644 --- a/src/packages.c +++ b/src/packages.c @@ -328,7 +328,7 @@ enum found_status { */ static enum found_status deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, - struct pkginfo *removing, struct pkgset *providing, + struct pkginfo *removing, struct deppossi *provider, struct pkginfo **fixbytrig, bool *matched, struct deppossi *checkversion, int *interestingwarnings, struct varbuf *oemsgs) @@ -341,10 +341,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, } thisf = FOUND_NONE; if (possdependee == removing) { - if (providing) { + if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is to be removed.\n"), - pkg_name(possdependee, pnaw_nonambig), providing->name); + pkg_name(possdependee, pnaw_nonambig), + provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is to be removed.\n"), pkg_name(possdependee, pnaw_nonambig)); @@ -360,17 +361,35 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, case PKG_STAT_TRIGGERSAWAITED: case PKG_STAT_TRIGGERSPENDING: case PKG_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 (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 (fc_dependsversion) + thisf = (dependtry >= 3) ? FOUND_FORCED : FOUND_DEFER; + 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 (fc_dependsversion) + thisf = (dependtry >= 3) ? FOUND_FORCED : FOUND_DEFER; + debug(dbg_depcondetail, " bad version"); + goto unsuitable; + } + } } if (possdependee->status == PKG_STAT_INSTALLED || possdependee->status == PKG_STAT_TRIGGERSPENDING) { @@ -382,10 +401,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, if (removing || !(f_triggers || possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)) { - if (providing) { + if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s awaits trigger processing.\n"), - pkg_name(possdependee, pnaw_nonambig), providing->name); + pkg_name(possdependee, pnaw_nonambig), + provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s awaits trigger processing.\n"), @@ -424,10 +444,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, sincenothing = 0; return FOUND_DEFER; } else { - if (providing) { + if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not configured yet.\n"), - pkg_name(possdependee, pnaw_nonambig), providing->name); + pkg_name(possdependee, pnaw_nonambig), + provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is not configured yet.\n"), pkg_name(possdependee, pnaw_nonambig)); @@ -438,10 +459,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby, } default: - if (providing) { + if (provider) { varbuf_printf(oemsgs, _(" Package %s which provides %s is not installed.\n"), - pkg_name(possdependee, pnaw_nonambig), providing->name); + pkg_name(possdependee, pnaw_nonambig), + provider->ed->name); } else { varbuf_printf(oemsgs, _(" Package %s is not installed.\n"), pkg_name(possdependee, pnaw_nonambig)); @@ -461,13 +483,13 @@ unsuitable: 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 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->name : "<none>"); + virtbroken ? virtbroken->ed->name : "<none>"); if (breaker->status == PKG_STAT_NOTINSTALLED || breaker->status == PKG_STAT_CONFIGFILES) @@ -479,7 +501,9 @@ breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok, if (!archsatisfied(&broken->installed, breaks)) return; if (ignore_depends(breaker)) return; - if (virtbroken && ignore_depends(&virtbroken->pkg)) + if (virtbroken && ignore_depends(&virtbroken->ed->pkg)) + return; + if (virtbroken && !pkg_virtual_deppossi_satisfied(breaks, virtbroken)) return; varbufdependency(&depmsg, breaks->up); @@ -494,7 +518,7 @@ breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok, varbuf_printf(aemsgs, _(" %s (%s) provides %s.\n"), pkg_name(broken, pnaw_nonambig), versiondescribe(&broken->installed.version, vdew_nonambig), - virtbroken->name); + 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), @@ -508,14 +532,12 @@ breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok, static void breaks_check_target(struct varbuf *aemsgs, enum dep_check *ok, struct pkginfo *broken, struct pkgset *target, - struct pkgset *virtbroken) + struct deppossi *virtbroken) { struct deppossi *possi; for (possi = target->depended.installed; possi; possi = possi->rev_next) { if (possi->up->type != dep_breaks) continue; - if (virtbroken && possi->verrel != DPKG_RELATION_NONE) - continue; breaks_check_one(aemsgs, ok, possi, broken, possi->up->up, virtbroken); } } @@ -524,7 +546,7 @@ enum dep_check breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs) { struct dependency *dep; - struct pkgset *virtbroken; + struct deppossi *virtbroken; enum dep_check ok = DEP_CHECK_OK; debug(dbg_depcon, " checking Breaks"); @@ -533,9 +555,9 @@ breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs) for (dep= pkg->installed.depends; dep; dep= dep->next) { if (dep->type != dep_provides) continue; - virtbroken = dep->list->ed; - debug(dbg_depcondetail, " checking virtbroken %s", virtbroken->name); - breaks_check_target(aemsgs, &ok, pkg, virtbroken, virtbroken); + virtbroken = dep->list; + debug(dbg_depcondetail, " checking virtbroken %s", virtbroken->ed->name); + breaks_check_target(aemsgs, &ok, pkg, virtbroken->ed, virtbroken); } return ok; } @@ -597,7 +619,7 @@ dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing, } deppossi_pkg_iter_free(possi_iter); - if (found != FOUND_OK && possi->verrel == DPKG_RELATION_NONE) { + if (found != FOUND_OK) { for (provider = possi->ed->depended.installed; found != FOUND_OK && provider; provider = provider->rev_next) { @@ -610,10 +632,15 @@ dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing, debug(dbg_depcondetail, " provider does not satisfy arch"); continue; } - thisf = deppossi_ok_found(provider->up->up, pkg, removing, - possi->ed, - &possfixbytrig, &matched, NULL, + 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; } |