Просмотр исходного кода

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.

This commit is very slightly based on the code reverted in commit
7df7d53a57b9913f4a20b2c9dcd554a2d88ff9f3, which was mostly skeletal.

Closes: #7330, #24934, #112131, #134582, #180316

Based-on-patch-by: Ben Collins <bcollins@debian.org>
Guillem Jover лет назад: 14
Родитель
Сommit
5bb02fe80e
10 измененных файлов с 145 добавлено и 51 удалено
  1. 8 0
      debian/changelog
  2. 5 4
      dselect/pkgdepcon.cc
  3. 3 3
      dselect/pkgsublist.cc
  4. 40 0
      lib/dpkg/depcon.c
  5. 4 0
      lib/dpkg/dpkg-db.h
  6. 9 6
      src/depcon.c
  7. 10 2
      src/enquiry.c
  8. 2 1
      src/main.c
  9. 2 0
      src/main.h
  10. 62 35
      src/packages.c

+ 8 - 0
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
   * Do not write to the available file when unpacking binary packages. This
     information is not useful as dpkg has never recorded the archive path,
     information is not useful as dpkg has never recorded the archive path,
     so it has never been truly available for re-installation anyway.
     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 ]
   [ Updated programs translations ]
   * Danish (Joe Dalton). Closes: #754127
   * Danish (Joe Dalton). Closes: #754127

+ 5 - 4
dselect/pkgdepcon.cc

@@ -414,8 +414,7 @@ packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade)
       return false;
       return false;
     }
     }
   }
   }
-  if (possi->verrel != DPKG_RELATION_NONE)
-    return false;
+
   deppossi *provider;
   deppossi *provider;
 
 
   for (provider = possi->ed->depended.installed;
   for (provider = possi->ed->depended.installed;
@@ -427,7 +426,8 @@ packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade)
         provider->up->up->clientdata &&
         provider->up->up->clientdata &&
         !useavailable(provider->up->up) &&
         !useavailable(provider->up->up) &&
         would_like_to_install(provider->up->up->clientdata->selected,
         would_like_to_install(provider->up->up->clientdata->selected,
-                              provider->up->up))
+                              provider->up->up) &&
+        pkg_virtual_deppossi_satisfied(possi, provider))
       return true;
       return true;
   }
   }
   for (provider = possi->ed->depended.available;
   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->set == possi->up->up->set) ||
         !provider->up->up->clientdata ||
         !provider->up->up->clientdata ||
         !would_like_to_install(provider->up->up->clientdata->selected,
         !would_like_to_install(provider->up->up->clientdata->selected,
-                               provider->up->up))
+                               provider->up->up) ||
+        !pkg_virtual_deppossi_satisfied(possi, provider))
       continue;
       continue;
     if (useavailable(provider->up->up))
     if (useavailable(provider->up->up))
       return true;
       return true;

+ 3 - 3
dselect/pkgsublist.cc

@@ -159,9 +159,9 @@ packagelist::add(dependency *depends, showpriority displayimportance)
   add(depends->up,info.string(),displayimportance);
   add(depends->up,info.string(),displayimportance);
   for (possi=depends->list; possi; possi=possi->next) {
   for (possi=depends->list; possi; possi=possi->next) {
     add(&possi->ed->pkg, info.string(), displayimportance);
     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;
       deppossi *provider;
       for (provider = possi->ed->depended.available;
       for (provider = possi->ed->depended.available;
            provider;
            provider;

+ 40 - 0
lib/dpkg/depcon.c

@@ -83,3 +83,43 @@ archsatisfied(struct pkgbin *it, struct deppossi *against)
 {
 {
 	return deparchsatisfied(it, it->arch, 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);
+}

+ 4 - 0
lib/dpkg/dpkg-db.h

@@ -406,6 +406,10 @@ bool deparchsatisfied(struct pkgbin *it, const struct dpkg_arch *arch,
                       struct deppossi *against);
                       struct deppossi *against);
 bool archsatisfied(struct pkgbin *it, 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 ***/
 /*** from nfmalloc.c ***/
 void *nfmalloc(size_t);
 void *nfmalloc(size_t);
 char *nfstrsave(const char*);
 char *nfstrsave(const char*);

+ 9 - 6
src/depcon.c

@@ -460,13 +460,13 @@ depisok(struct dependency *dep, struct varbuf *whynot,
       }
       }
       deppossi_pkg_iter_free(possi_iter);
       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. */
         /* See if the package we're about to install Provides it. */
         for (provider = possi->ed->depended.available;
         for (provider = possi->ed->depended.available;
              provider;
              provider;
              provider = provider->rev_next) {
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides) continue;
           if (provider->up->type != dep_provides) continue;
+          if (!pkg_virtual_deppossi_satisfied(possi, provider))
+            continue;
           if (provider->up->up->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)
           if (provider->up->up->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)
             return true;
             return true;
         }
         }
@@ -476,6 +476,8 @@ depisok(struct dependency *dep, struct varbuf *whynot,
              provider;
              provider;
              provider = provider->rev_next) {
              provider = provider->rev_next) {
           if (provider->up->type != dep_provides) continue;
           if (provider->up->type != dep_provides) continue;
+          if (!pkg_virtual_deppossi_satisfied(possi, provider))
+            continue;
 
 
           switch (provider->up->up->clientdata->istobe) {
           switch (provider->up->up->clientdata->istobe) {
           case PKG_ISTOBE_INSTALLNEW:
           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);
           sprintf(linebuf, _("  %.250s is not installed.\n"), possi->ed->name);
           varbuf_add_str(whynot, linebuf);
           varbuf_add_str(whynot, linebuf);
         }
         }
-      }
     }
     }
 
 
     return false;
     return false;
@@ -600,8 +601,6 @@ depisok(struct dependency *dep, struct varbuf *whynot,
       deppossi_pkg_iter_free(possi_iter);
       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. */
       /* See if the package we're about to install Provides it. */
       for (provider = possi->ed->depended.available;
       for (provider = possi->ed->depended.available;
            provider;
            provider;
@@ -611,6 +610,8 @@ depisok(struct dependency *dep, struct varbuf *whynot,
           continue;
           continue;
         if (provider->up->up->set == dep->up->set)
         if (provider->up->up->set == dep->up->set)
           continue; /* Conflicts and provides the same. */
           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"),
         sprintf(linebuf, _("  %.250s provides %.250s and is to be installed.\n"),
                 pkgbin_name(provider->up->up, &provider->up->up->available,
                 pkgbin_name(provider->up->up, &provider->up->up->available,
                             pnaw_nonambig), possi->ed->name);
                             pnaw_nonambig), possi->ed->name);
@@ -630,6 +631,9 @@ depisok(struct dependency *dep, struct varbuf *whynot,
         if (provider->up->up->set == dep->up->set)
         if (provider->up->up->set == dep->up->set)
           continue; /* Conflicts and provides the same. */
           continue; /* Conflicts and provides the same. */
 
 
+        if (!pkg_virtual_deppossi_satisfied(possi, provider))
+          continue;
+
         switch (provider->up->up->clientdata->istobe) {
         switch (provider->up->up->clientdata->istobe) {
         case PKG_ISTOBE_INSTALLNEW:
         case PKG_ISTOBE_INSTALLNEW:
           /* Don't pay any attention to the Provides field of the
           /* 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);
                     provider->up->up->clientdata->istobe);
         }
         }
       }
       }
-    }
 
 
     if (!nconflicts)
     if (!nconflicts)
       return true;
       return true;

+ 10 - 2
src/enquiry.c

@@ -432,6 +432,14 @@ assertmultiarch(const char *const *argv)
   return assert_version_support(argv, &version, _("multi-arch"));
   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:
  * Print a single package which:
  *  (a) is the target of one or more relevant predependencies.
  *  (a) is the target of one or more relevant predependencies.
@@ -508,13 +516,13 @@ predeppackage(const char *const *argv)
           pkg = trypkg;
           pkg = trypkg;
           break;
           break;
         }
         }
-        if (possi->verrel != DPKG_RELATION_NONE)
-          continue;
         for (provider = possi->ed->depended.available;
         for (provider = possi->ed->depended.available;
              !pkg && provider;
              !pkg && provider;
              provider = provider->next) {
              provider = provider->next) {
           if (provider->up->type != dep_provides)
           if (provider->up->type != dep_provides)
             continue;
             continue;
+          if (!pkg_virtual_deppossi_satisfied(possi, provider))
+            continue;
           trypkg = provider->up->up;
           trypkg = provider->up->up;
           if (!trypkg->files)
           if (!trypkg->files)
             continue;
             continue;

+ 2 - 1
src/main.c

@@ -126,7 +126,7 @@ usage(const struct cmdinfo *ci, const char *value)
   printf(_(
   printf(_(
 "For internal use: dpkg --assert-support-predepends | --predep-package |\n"
 "For internal use: dpkg --assert-support-predepends | --predep-package |\n"
 "  --assert-working-epoch | --assert-long-filenames | --assert-multi-conrep |\n"
 "  --assert-working-epoch | --assert-long-filenames | --assert-multi-conrep |\n"
-"  --assert-multi-arch.\n"
+"  --assert-multi-arch | --assert-versioned-provides.\n"
 "\n"));
 "\n"));
 
 
   printf(_(
   printf(_(
@@ -672,6 +672,7 @@ static const struct cmdinfo cmdinfos[]= {
   ACTION( "assert-long-filenames",           0,  act_assertlongfilenames,  assertlongfilenames ),
   ACTION( "assert-long-filenames",           0,  act_assertlongfilenames,  assertlongfilenames ),
   ACTION( "assert-multi-conrep",             0,  act_assertmulticonrep,    assertmulticonrep ),
   ACTION( "assert-multi-conrep",             0,  act_assertmulticonrep,    assertmulticonrep ),
   ACTION( "assert-multi-arch",               0,  act_assertmultiarch,      assertmultiarch ),
   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( "add-architecture",                0,  act_arch_add,             arch_add        ),
   ACTION( "remove-architecture",             0,  act_arch_remove,          arch_remove     ),
   ACTION( "remove-architecture",             0,  act_arch_remove,          arch_remove     ),
   ACTION( "print-architecture",              0,  act_printarch,            printarch   ),
   ACTION( "print-architecture",              0,  act_printarch,            printarch   ),

+ 2 - 0
src/main.h

@@ -101,6 +101,7 @@ enum action {
 	act_assertlongfilenames,
 	act_assertlongfilenames,
 	act_assertmulticonrep,
 	act_assertmulticonrep,
 	act_assertmultiarch,
 	act_assertmultiarch,
+	act_assertverprovides,
 
 
 	act_audit,
 	act_audit,
 	act_unpackchk,
 	act_unpackchk,
@@ -165,6 +166,7 @@ int assertpredep(const char *const *argv);
 int assertlongfilenames(const char *const *argv);
 int assertlongfilenames(const char *const *argv);
 int assertmulticonrep(const char *const *argv);
 int assertmulticonrep(const char *const *argv);
 int assertmultiarch(const char *const *argv);
 int assertmultiarch(const char *const *argv);
+int assertverprovides(const char *const *argv);
 int predeppackage(const char *const *argv);
 int predeppackage(const char *const *argv);
 int printarch(const char *const *argv);
 int printarch(const char *const *argv);
 int printinstarch(const char *const *argv);
 int printinstarch(const char *const *argv);

+ 62 - 35
src/packages.c

@@ -328,7 +328,7 @@ enum found_status {
  */
  */
 static enum found_status
 static enum found_status
 deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
 deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
-                  struct pkginfo *removing, struct pkgset *providing,
+                  struct pkginfo *removing, struct deppossi *provider,
                   struct pkginfo **fixbytrig,
                   struct pkginfo **fixbytrig,
                   bool *matched, struct deppossi *checkversion,
                   bool *matched, struct deppossi *checkversion,
                   int *interestingwarnings, struct varbuf *oemsgs)
                   int *interestingwarnings, struct varbuf *oemsgs)
@@ -341,10 +341,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
   }
   }
   thisf = FOUND_NONE;
   thisf = FOUND_NONE;
   if (possdependee == removing) {
   if (possdependee == removing) {
-    if (providing) {
+    if (provider) {
       varbuf_printf(oemsgs,
       varbuf_printf(oemsgs,
                     _("  Package %s which provides %s is to be removed.\n"),
                     _("  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 {
     } else {
       varbuf_printf(oemsgs, _("  Package %s is to be removed.\n"),
       varbuf_printf(oemsgs, _("  Package %s is to be removed.\n"),
                     pkg_name(possdependee, pnaw_nonambig));
                     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_TRIGGERSAWAITED:
   case PKG_STAT_TRIGGERSPENDING:
   case PKG_STAT_TRIGGERSPENDING:
   case PKG_STAT_INSTALLED:
   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 ||
     if (possdependee->status == PKG_STAT_INSTALLED ||
         possdependee->status == PKG_STAT_TRIGGERSPENDING) {
         possdependee->status == PKG_STAT_TRIGGERSPENDING) {
@@ -382,10 +401,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
       if (removing ||
       if (removing ||
           !(f_triggers ||
           !(f_triggers ||
             possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)) {
             possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW)) {
-        if (providing) {
+        if (provider) {
           varbuf_printf(oemsgs,
           varbuf_printf(oemsgs,
                         _("  Package %s which provides %s awaits trigger processing.\n"),
                         _("  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 {
         } else {
           varbuf_printf(oemsgs,
           varbuf_printf(oemsgs,
                         _("  Package %s awaits trigger processing.\n"),
                         _("  Package %s awaits trigger processing.\n"),
@@ -424,10 +444,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
       sincenothing = 0;
       sincenothing = 0;
       return FOUND_DEFER;
       return FOUND_DEFER;
     } else {
     } else {
-      if (providing) {
+      if (provider) {
         varbuf_printf(oemsgs,
         varbuf_printf(oemsgs,
                       _("  Package %s which provides %s is not configured yet.\n"),
                       _("  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 {
       } else {
         varbuf_printf(oemsgs, _("  Package %s is not configured yet.\n"),
         varbuf_printf(oemsgs, _("  Package %s is not configured yet.\n"),
                       pkg_name(possdependee, pnaw_nonambig));
                       pkg_name(possdependee, pnaw_nonambig));
@@ -438,10 +459,11 @@ deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
     }
     }
 
 
   default:
   default:
-    if (providing) {
+    if (provider) {
       varbuf_printf(oemsgs,
       varbuf_printf(oemsgs,
                     _("  Package %s which provides %s is not installed.\n"),
                     _("  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 {
     } else {
       varbuf_printf(oemsgs, _("  Package %s is not installed.\n"),
       varbuf_printf(oemsgs, _("  Package %s is not installed.\n"),
                     pkg_name(possdependee, pnaw_nonambig));
                     pkg_name(possdependee, pnaw_nonambig));
@@ -461,13 +483,13 @@ unsuitable:
 static void
 static void
 breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok,
 breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok,
                  struct deppossi *breaks, struct pkginfo *broken,
                  struct deppossi *breaks, struct pkginfo *broken,
-                 struct pkginfo *breaker, struct pkgset *virtbroken)
+                 struct pkginfo *breaker, struct deppossi *virtbroken)
 {
 {
   struct varbuf depmsg = VARBUF_INIT;
   struct varbuf depmsg = VARBUF_INIT;
 
 
   debug(dbg_depcondetail, "      checking breaker %s virtbroken %s",
   debug(dbg_depcondetail, "      checking breaker %s virtbroken %s",
         pkg_name(breaker, pnaw_always),
         pkg_name(breaker, pnaw_always),
-        virtbroken ? virtbroken->name : "<none>");
+        virtbroken ? virtbroken->ed->name : "<none>");
 
 
   if (breaker->status == PKG_STAT_NOTINSTALLED ||
   if (breaker->status == PKG_STAT_NOTINSTALLED ||
       breaker->status == PKG_STAT_CONFIGFILES)
       breaker->status == PKG_STAT_CONFIGFILES)
@@ -479,7 +501,9 @@ breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok,
   if (!archsatisfied(&broken->installed, breaks))
   if (!archsatisfied(&broken->installed, breaks))
     return;
     return;
   if (ignore_depends(breaker)) 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;
     return;
 
 
   varbufdependency(&depmsg, breaks->up);
   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"),
     varbuf_printf(aemsgs, _("  %s (%s) provides %s.\n"),
                   pkg_name(broken, pnaw_nonambig),
                   pkg_name(broken, pnaw_nonambig),
                   versiondescribe(&broken->installed.version, vdew_nonambig),
                   versiondescribe(&broken->installed.version, vdew_nonambig),
-                  virtbroken->name);
+                  virtbroken->ed->name);
   } else if (breaks->verrel != DPKG_RELATION_NONE) {
   } else if (breaks->verrel != DPKG_RELATION_NONE) {
     varbuf_printf(aemsgs, _("  Version of %s to be configured is %s.\n"),
     varbuf_printf(aemsgs, _("  Version of %s to be configured is %s.\n"),
                   pkg_name(broken, pnaw_nonambig),
                   pkg_name(broken, pnaw_nonambig),
@@ -508,14 +532,12 @@ breaks_check_one(struct varbuf *aemsgs, enum dep_check *ok,
 static void
 static void
 breaks_check_target(struct varbuf *aemsgs, enum dep_check *ok,
 breaks_check_target(struct varbuf *aemsgs, enum dep_check *ok,
                     struct pkginfo *broken, struct pkgset *target,
                     struct pkginfo *broken, struct pkgset *target,
-                    struct pkgset *virtbroken)
+                    struct deppossi *virtbroken)
 {
 {
   struct deppossi *possi;
   struct deppossi *possi;
 
 
   for (possi = target->depended.installed; possi; possi = possi->rev_next) {
   for (possi = target->depended.installed; possi; possi = possi->rev_next) {
     if (possi->up->type != dep_breaks) continue;
     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);
     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)
 breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs)
 {
 {
   struct dependency *dep;
   struct dependency *dep;
-  struct pkgset *virtbroken;
+  struct deppossi *virtbroken;
   enum dep_check ok = DEP_CHECK_OK;
   enum dep_check ok = DEP_CHECK_OK;
 
 
   debug(dbg_depcon, "    checking Breaks");
   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) {
   for (dep= pkg->installed.depends; dep; dep= dep->next) {
     if (dep->type != dep_provides) continue;
     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;
   return ok;
 }
 }
@@ -597,7 +619,7 @@ dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
       }
       }
       deppossi_pkg_iter_free(possi_iter);
       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;
         for (provider = possi->ed->depended.installed;
              found != FOUND_OK && provider;
              found != FOUND_OK && provider;
              provider = provider->rev_next) {
              provider = provider->rev_next) {
@@ -610,10 +632,15 @@ dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
             debug(dbg_depcondetail, "       provider does not satisfy arch");
             debug(dbg_depcondetail, "       provider does not satisfy arch");
             continue;
             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);
                                     &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)
           if (thisf > found)
             found = thisf;
             found = thisf;
         }
         }