Forráskód Böngészése

Implement support for Breaks field.

As a side effect, run the deconfiguration of each package to be
deconfigured once, instead of once per each conflicting package being
removed.
Ian Jackson 19 éve
szülő
commit
b301c0e71a
18 módosított fájl, 298 hozzáadás és 55 törlés
  1. 37 0
      ChangeLog
  2. 5 0
      debian/changelog
  3. 8 0
      man/deb-control.5
  4. 1 0
      man/dpkg-query.1
  5. 3 0
      man/dpkg.1
  6. 1 1
      scripts/controllib.pl
  7. 1 1
      scripts/dpkg-genchanges.pl
  8. 1 1
      scripts/dpkg-source.pl
  9. 97 15
      src/archives.c
  10. 2 0
      src/archives.h
  11. 7 5
      src/cleanup.c
  12. 3 1
      src/configure.c
  13. 26 9
      src/depcon.c
  14. 6 0
      src/help.c
  15. 2 1
      src/main.c
  16. 5 2
      src/main.h
  17. 73 0
      src/packages.c
  18. 20 19
      src/processarc.c

+ 37 - 0
ChangeLog

@@ -1,3 +1,40 @@
+2007-08-07  Ian Jackson  <iwj@ubuntu.com>
+
+	* man/deb-control.5: Document Breaks field.
+	* man/dpkg-query.1: Document Breaks as a recognized field.
+	* man/dpkg.1: Add description of '--force-breaks'.
+	* scripts/controllib.pl (@pkg_dep_fields): Add 'Breaks'.
+	* scripts/dpkg-genchanges.pl: Ignore Breaks field.
+	* scripts/dpkg-source.pl: Likewise.
+	* src/archives.c (try_remove_can): Rename to ...
+	(try_deconfigure_can): ... this. Generalize dependency force check
+	by taking a function as argument. Store the possible package removal
+	which caused the deconfiguration in the xinfo member of the package
+	to be deconfigured.
+	(try_remove_can): New function.
+	(check_breaks): Likewise.
+	* src/archives.h (check_breaks): New prototype.
+	* src/cleanup.c (cu_prermdeconfigure): Handle case when argv[1]
+	might be 0, if deconfigure was due to Breaks.
+	* src/configure.c (deferred_configure): Call breakses_ok.
+	* src/depcon.c (depisok): Add Breaks support.
+	* src/help.c (force_breaks): New function.
+	* src/main.c (fc_breaks): New variable.
+	(forceinfo): Add 'breaks' as a supported option for '--force-...'.
+	* src/main.h (struct perpackagestate): Add xinfo member.
+	(fc_breaks): New variable definition.
+	(breakses_ok): New prototype.
+	(force_depends): Likewise.
+	* src/packages.c (breaks_check_one): New function.
+	(breaks_check_target): Likewise.
+	(breakses_ok): Likewise.
+	* src/processarc.c (process_archive): Check for Breaks dependencies,
+	instead of bailing out if field found. Distinguish between deconfigure
+	due to a removal due to Conflicts or Depends, and deconfigure due to
+	an installation due to Breaks. Run the deconfiguration of each
+	package to be deconfigured once, instead of once per each conflicting
+	package being removed.
+
 2007-07-31  Ian Jackson  <iwj@ubuntu.com>
 
 	* src/archives.c (quote_filename): Change formatting to match the

+ 5 - 0
debian/changelog

@@ -17,6 +17,11 @@ dpkg (1.14.6) UNRELEASED; urgency=low
   * Move variables automatically modified at build time for the perl scripts
     to a new style perl module (Dpkg) and make all programs use it.
   * Switch 'dpkg-gettext.pl' to a new style perl module (Dpkg::Gettext).
+  * Implement support for Breaks field. Closes: #379140
+    Thanks to Ian Jackson.
+  * Run the deconfiguration of each package to be deconfigured once, instead
+    of once per each conflicting package being removed. Closes: #378003
+    Thanks to Ian Jackson.
 
   [ Updated scripts translations ]
   * French (Frédéric Bothamy, Christian Perrier).

+ 8 - 0
man/deb-control.5

@@ -136,6 +136,14 @@ by a hyphen). Accepted version relationships are ">>" for greater than,
 "<<" for less than, ">=" for greater than or equal to, "<=" for less than
 or equal to, and "=" for equal to.
 .TP
+.BR Breaks: " <package list>"
+Lists packages that this one breaks, for example by exposing bugs
+when the named packages rely on this one. The package maintenance
+software will not allow broken packages to be configured; generally
+the resolution is to upgrade the packages named in a
+.B Breaks
+field.
+.TP
 .BR Conflicts: " <package list>"
 Lists packages that conflict with this one, for example by containing
 files with the same names. The package maintenance software will not

+ 1 - 0
man/dpkg-query.1

@@ -103,6 +103,7 @@ alignment will be used. The following \fIfield\fRs are recognised:
     \fBConffiles\fP
     \fBConfig\-Version\fP
     \fBConflicts\fP
+    \fBBreaks\fP
     \fBDepends\fP
     \fBDescription\fP
     \fBEnhances\fP

+ 3 - 0
man/dpkg.1

@@ -372,6 +372,9 @@ Turn all dependency problems into warnings.
 \fBdepends\-version\fP:
 Don't care about versions when checking dependencies.
 
+\fBbreaks\fP:
+Install, even if this would break another package.
+
 \fBconflicts\fP:
 Install, even if it conflicts with another package. This is dangerous,
 for it will usually cause overwriting of some files.

+ 1 - 1
scripts/controllib.pl

@@ -26,7 +26,7 @@ our %substvar;      # - map with substitution variables
 my $parsechangelog = 'dpkg-parsechangelog';
 
 our @pkg_dep_fields = qw(Pre-Depends Depends Recommends Suggests Enhances
-                         Conflicts Replaces Provides);
+                         Conflicts Breaks Replaces Provides);
 our @src_dep_fields = qw(Build-Depends Build-Depends-Indep
                          Build-Conflicts Build-Conflicts-Indep);
 

+ 1 - 1
scripts/dpkg-genchanges.pl

@@ -251,7 +251,7 @@ for $_ (keys %fi) {
 		}
 		push(@archvalues,$v) unless !$v || $archadded{$v}++;
 	    } elsif (m/^(Package|Essential|Pre-Depends|Depends|Provides)$/ ||
-		     m/^(Recommends|Suggests|Enhances|Optional|Conflicts|Replaces)$/ ||
+		     m/^(Recommends|Suggests|Enhances|Optional|Conflicts|Breaks|Replaces)$/ ||
 		     m/^X[CS]+-/i) {
 	    } else {
 		&unknown(_g("package's section of control info file"));

+ 1 - 1
scripts/dpkg-source.pl

@@ -281,7 +281,7 @@ if ($opmode eq 'build') {
                 $f{$_}= $v;
             } elsif (m/^(Package|Essential|Pre-Depends|Depends|Provides)$/i ||
                      m/^(Recommends|Suggests|Optional|Conflicts|Replaces)$/i ||
-                     m/^(Enhances|Description|Section|Priority)$/i ||
+                     m/^(Breaks|Enhances|Description|Section|Priority)$/i ||
                      m/^X[BC]+-/i) {
             } else {
                 &unknown(_g("package's section of control info file"));

+ 97 - 15
src/archives.c

@@ -780,42 +780,124 @@ int tarobject(struct TarInfo *ti) {
   return 0;
 }
 
-static int try_remove_can(struct deppossi *pdep,
-                          struct pkginfo *fixbyrm,
+static int try_deconfigure_can(int (*force_p)(struct deppossi*),
+                               struct pkginfo *pkg,
+                               struct deppossi *pdep,
+                               const char *action,
+                               struct pkginfo *removal,
                           const char *why) {
+  /* Also checks whether the pdep is forced, first, according to force_p.
+   * force_p may be 0 in which case nothing is considered forced.
+   *
+   * Action is a string describing the action which causes the
+   * deconfiguration:
+   *     removal of <package>         (due to Conflicts+Depends   removal!=0)
+   *     installation of <package>    (due to Breaks              removal==0)
+   *
+   * Return values:  2: forced (no deconfiguration needed, why is printed)
+   *                 1: deconfiguration queued ok (no message printed)
+   *                 0: not possible (why is printed)
+   */
   struct packageinlist *newdeconf;
   
-  if (force_depends(pdep)) {
+  if (force_p && force_p(pdep)) {
     fprintf(stderr, _("dpkg: warning - "
-            "ignoring dependency problem with removal of %s:\n%s"),
-            fixbyrm->name, why);
-    return 1;
+                      "ignoring dependency problem with %s:\n%s"),
+            action, why);
+    return 2;
   } else if (f_autodeconf) {
-    if (pdep->up->up->installed.essential) {
+    if (pkg->installed.essential) {
       if (fc_removeessential) {
         fprintf(stderr, _("dpkg: warning - considering deconfiguration of essential\n"
-                " package %s, to enable removal of %s.\n"),
-                pdep->up->up->name,fixbyrm->name);
+                          " package %s, to enable %s.\n"),
+                pkg->name, action);
       } else {
         fprintf(stderr, _("dpkg: no, %s is essential, will not deconfigure\n"
-                " it in order to enable removal of %s.\n"),
-                pdep->up->up->name,fixbyrm->name);
+                          " it in order to enable %s.\n"),
+                pkg->name, action);
         return 0;
       }
     }
-    pdep->up->up->clientdata->istobe= itb_deconfigure;
+    pkg->clientdata->istobe= itb_deconfigure;
     newdeconf= malloc(sizeof(struct packageinlist));
     newdeconf->next= deconfigure;
-    newdeconf->pkg= pdep->up->up;
+    newdeconf->pkg= pkg;
+    newdeconf->xinfo= removal;
     deconfigure= newdeconf;
     return 1;
   } else {
-    fprintf(stderr, _("dpkg: no, cannot remove %s (--auto-deconfigure will help):\n%s"),
-            fixbyrm->name, why);
+    fprintf(stderr, _("dpkg: no, cannot proceed with %s (--auto-deconfigure will help):\n%s"),
+            action, why);
     return 0;
   }
 }
 
+static int try_remove_can(struct deppossi *pdep,
+                          struct pkginfo *fixbyrm,
+                          const char *why) {
+  char action[512];
+  sprintf(action, _("removal of %.250s"), fixbyrm->name);
+  return try_deconfigure_can(force_depends, pdep->up->up, pdep,
+                             action, fixbyrm, why);
+}
+
+void check_breaks(struct dependency *dep, struct pkginfo *pkg,
+                  const char *pfilename) {
+  struct pkginfo *fixbydeconf;
+  struct varbuf why;
+  int ok;
+
+  varbufinit(&why);
+
+  fixbydeconf= 0;
+  if (depisok(dep, &why, &fixbydeconf, 0)) {
+    varbuffree(&why);
+    return;
+  }
+
+  varbufaddc(&why, 0);
+
+  if (fixbydeconf && f_autodeconf) {
+    char action[512];
+
+    ensure_package_clientdata(fixbydeconf);
+    assert(fixbydeconf->clientdata->istobe == itb_normal);
+
+    sprintf(action, _("installation of %.250s"), pkg->name);
+    fprintf(stderr, _("dpkg: considering deconfiguration of %s,"
+                      " which would be broken by %s ...\n"),
+            fixbydeconf->name, action);
+
+    ok= try_deconfigure_can(force_breaks, fixbydeconf, dep->list,
+                            action, 0, why.buf);
+    if (ok == 1) {
+      fprintf(stderr, _("dpkg: yes, will deconfigure %s (broken by %s).\n"),
+              fixbydeconf->name, pkg->name);
+    }
+  } else {
+    fprintf(stderr, _("dpkg: regarding %s containing %s:\n%s"),
+            pfilename, pkg->name, why.buf);
+    ok= 0;
+  }
+  varbuffree(&why);
+  if (ok > 0) return;
+
+  if (force_breaks(dep->list)) {
+    fprintf(stderr, _("dpkg: warning - ignoring breakage,"
+                      " may proceed anyway !\n"));
+    return;
+  }
+
+  if (fixbydeconf && !f_autodeconf) {
+    ohshit(_("installing %.250s would break %.250s, and\n"
+             " deconfiguration is not permitted (--auto-deconfigure might help)"),
+           pkg->name, fixbydeconf->name);
+  } else {
+    ohshit(_("installing %.250s would break existing software"),
+           pkg->name);
+  }
+}
+
 void check_conflict(struct dependency *dep, struct pkginfo *pkg,
                     const char *pfilename) {
   struct pkginfo *fixbyrm;

+ 2 - 0
src/archives.h

@@ -65,6 +65,8 @@ int filesavespackage(struct fileinlist*, struct pkginfo*,
 
 void check_conflict(struct dependency *dep, struct pkginfo *pkg,
                     const char *pfilename);
+void check_breaks(struct dependency *dep, struct pkginfo *pkg,
+                  const char *pfilename);
 
 struct fileinlist *addfiletolist(struct tarcontext *tc,
 				 struct filenamenode *namenode);

+ 7 - 5
src/cleanup.c

@@ -120,7 +120,8 @@ void cu_prermupgrade(int argc, void **argv) {
 
 void ok_prermdeconfigure(int argc, void **argv) {
   struct pkginfo *deconf= (struct pkginfo*)argv[0];
-  /* also has conflictor in argv[1] and infavour in argv[2] */
+  /* also has conflictor in argv[1] and infavour in argv[2].
+   * conflictor may be 0 if deconfigure was due to Breaks */
   
   if (cipaction->arg == act_install)
     add_to_queue(deconf);
@@ -128,16 +129,17 @@ void ok_prermdeconfigure(int argc, void **argv) {
 
 void cu_prermdeconfigure(int argc, void **argv) {
   struct pkginfo *deconf= (struct pkginfo*)argv[0];
-  struct pkginfo *conflictor= (struct pkginfo*)argv[1];
+  struct pkginfo *conflictor= (struct pkginfo*)argv[1]; /* may be 0 */
   struct pkginfo *infavour= (struct pkginfo*)argv[2];
 
   maintainer_script_installed(deconf,POSTINSTFILE,"post-installation",
                               "abort-deconfigure", "in-favour", infavour->name,
                               versiondescribe(&infavour->available.version,
                                               vdew_nonambig),
-                              "removing", conflictor->name,
-                              versiondescribe(&conflictor->installed.version,
-                                              vdew_nonambig),
+                              conflictor ? "removing" : (char*)0,
+                              conflictor ? conflictor->name : (char*)0,
+                              conflictor ? versiondescribe(&conflictor->installed.version,
+                                                           vdew_nonambig) : (char*)0,
                               (char*)0);
   deconf->status= stat_installed;
   modstatdb_note(deconf);

+ 3 - 1
src/configure.c

@@ -108,7 +108,9 @@ void deferred_configure(struct pkginfo *pkg) {
 		pkg->clientdata->istobe= itb_installnew;
 		add_to_queue(pkg);
 		return;
-	} else if (ok == 0) {
+	}
+	ok = breakses_ok(pkg, &aemsgs) ? ok : 0;
+	if (ok == 0) {
 		sincenothing= 0;
 		varbufaddc(&aemsgs,0);
 		fprintf(stderr,

+ 26 - 9
src/depcon.c

@@ -196,6 +196,10 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
    * 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 0 return (`not OK'), *canfixbyremove refers to a package which
+   * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix
+   * the problem.  Caller may pass 0 for canfixbyremove and need not
+   * initialise *canfixbyremove.
    */
   struct deppossi *possi;
   struct deppossi *provider;
@@ -213,6 +217,8 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
 	 dep->type == dep_recommends || dep->type == dep_suggests ||
 	 dep->type == dep_enhances);
   
+  if (canfixbyremove) *canfixbyremove= 0;
+
   /* The dependency is always OK if we're trying to remove the depend*ing*
    * package.
    */
@@ -380,12 +386,11 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
       }
     }
 
-    if (canfixbyremove) *canfixbyremove= 0;
     return 0;
 
   } else {
     
-    /* It's a conflict.  There's only one main alternative,
+    /* It's conflicts or breaks.  There's only one main alternative,
      * but we also have to consider Providers.  We return `0' 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 `1'.
@@ -395,9 +400,10 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
     nconflicts= 0;
 
     if (possi->ed != possi->up->up) {
-      /* If the package conflicts with itself it must mean that it conflicts
-       * with other packages which provide the same virtual name.  We therefore
-       * don't look at the real package and go on to the virtual ones.
+      /* 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.
        */
       
       switch (possi->ed->clientdata->istobe) {
@@ -413,11 +419,17 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
         nconflicts++;
         *canfixbyremove= possi->ed;
         break;
-      case itb_normal: case itb_deconfigure: case itb_preinstall:
+      case itb_deconfigure:
+        if (dep->type == dep_breaks) break; /* already deconfiguring this */
+        /* fall through */
+      case itb_normal: case itb_preinstall:
         switch (possi->ed->status) {
         case stat_notinstalled: case stat_configfiles:
           break;
-        default:
+        case stat_halfinstalled: case stat_unpacked:
+        case stat_halfconfigured:
+          if (dep->type == dep_breaks) break; /* no problem */
+        case stat_installed:
           if (!versionsatisfied(&possi->ed->installed, possi)) break;
           sprintf(linebuf, _("  %.250s (version %.250s) is %s.\n"),
                   possi->ed->name,
@@ -470,11 +482,16 @@ int depisok(struct dependency *dep, struct varbuf *whynot,
           continue; 
         case itb_remove:
           continue;
-        case itb_normal: case itb_deconfigure: case itb_preinstall:
+        case itb_deconfigure:
+          if (dep->type == dep_breaks) continue; /* already deconfiguring */
+        case itb_normal: case itb_preinstall:
           switch (provider->up->up->status) {
           case stat_notinstalled: case stat_configfiles:
             continue;
-          default:
+          case stat_halfinstalled: case stat_unpacked:
+          case stat_halfconfigured:
+            if (dep->type == dep_breaks) break; /* no problem */
+          case stat_installed:
             sprintf(linebuf, _("  %.250s provides %.250s and is %s.\n"),
                     provider->up->up->name, possi->ed->name,
                     gettext(statusstrings[provider->up->up->status]));

+ 6 - 0
src/help.c

@@ -152,6 +152,12 @@ int force_depends(struct deppossi *possi) {
          ignore_depends(possi->up->up);
 }
 
+int force_breaks(struct deppossi *possi) {
+  return fc_breaks ||
+         ignore_depends(possi->ed) ||
+         ignore_depends(possi->up->up);
+}
+
 int force_conflicts(struct deppossi *possi) {
   return fc_conflicts;
 }

+ 2 - 1
src/main.c

@@ -154,7 +154,7 @@ unsigned long f_debug=0;
 /* Change fc_overwrite to 1 to enable force-overwrite by default */
 int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, fc_overwrite=0;
 int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0;
-int fc_badpath=0, fc_overwritediverted=0, fc_architecture=0;
+int fc_breaks=0, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0;
 int fc_nonroot=0, fc_overwritedir=0, fc_conff_new=0, fc_conff_miss=0;
 int fc_conff_old=0, fc_conff_def=0;
 int fc_badverify = 0;
@@ -180,6 +180,7 @@ static const struct forceinfo {
   { "confmiss",            &fc_conff_miss               },
   { "depends",             &fc_depends                  },
   { "depends-version",     &fc_dependsversion           },
+  { "breaks",              &fc_breaks                   },
   { "bad-path",            &fc_badpath                  },
   { "not-root",            &fc_nonroot                  },
   { "overwrite",           &fc_overwrite                },

+ 5 - 2
src/main.h

@@ -46,6 +46,7 @@ struct perpackagestate {
 struct packageinlist {
   struct packageinlist *next;
   struct pkginfo *pkg;
+  void *xinfo;
 };
 
 enum action { act_unset, act_install, act_unpack, act_avail, act_configure,
@@ -86,7 +87,7 @@ extern int f_autodeconf, f_largemem, f_nodebsig;
 extern unsigned long f_debug;
 extern int fc_downgrade, fc_configureany, fc_hold, fc_removereinstreq, fc_overwrite;
 extern int fc_removeessential, fc_conflicts, fc_depends, fc_dependsversion;
-extern int fc_badpath, fc_overwritediverted, fc_architecture;
+extern int fc_breaks, fc_badpath, fc_overwritediverted, fc_architecture;
 extern int fc_nonroot, fc_overwritedir, fc_conff_new, fc_conff_miss;
 extern int fc_conff_old, fc_conff_def;
 extern int fc_badverify;
@@ -150,7 +151,8 @@ void packages(const char *const *argv);
 void removal_bulk(struct pkginfo *pkg);
 int conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in);
 int dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
-                    struct varbuf *aemsgs);
+                    struct varbuf *aemsgs); /* checks [Pre]-Depends only */
+int breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs);
 
 void deferred_remove(struct pkginfo *pkg);
 void deferred_configure(struct pkginfo *pkg);
@@ -177,6 +179,7 @@ void cu_closedir(int argc, void **argv);
 void cu_closefd(int argc, void **argv);
 
 int ignore_depends(struct pkginfo *pkg);
+int force_breaks(struct deppossi *possi);
 int force_depends(struct deppossi *possi);
 int force_conff_new(struct deppossi *possi);
 int force_conff_miss(struct deppossi *possi);

+ 73 - 0
src/packages.c

@@ -339,6 +339,79 @@ static int deppossi_ok_found(struct pkginfo *possdependee,
   }
 }
 
+static void breaks_check_one(struct varbuf *aemsgs, int *ok,
+                             struct deppossi *breaks,
+                             struct pkginfo *broken,
+                             struct pkginfo *breaker,
+                             struct pkginfo *virtbroken) {
+  struct varbuf depmsg;
+
+  debug(dbg_depcondetail, "      checking breaker %s virtbroken %s",
+        breaker->name, virtbroken ? virtbroken->name : "<none>");
+
+  if (breaker->status == stat_notinstalled ||
+      breaker->status == stat_configfiles) return;
+  if (broken == breaker) return;
+  if (!versionsatisfied(&broken->installed, breaks)) return;
+  if (ignore_depends(breaker)) return;
+  if (virtbroken && ignore_depends(virtbroken)) return;
+
+  varbufinit(&depmsg);
+  varbufdependency(&depmsg, breaks->up);
+  varbufaddc(&depmsg, 0);
+  varbufprintf(aemsgs, _(" %s (%s) breaks %s and is %s.\n"),
+               breaker->name,
+               versiondescribe(&breaker->installed.version, vdew_nonambig),
+               depmsg.buf,
+               gettext(statusstrings[breaker->status]));
+  varbuffree(&depmsg);
+
+  if (virtbroken) {
+    varbufprintf(aemsgs, _("  %s (%s) provides %s.\n"),
+                 broken->name,
+                 versiondescribe(&broken->installed.version, vdew_nonambig),
+                 virtbroken->name);
+  } else if (breaks->verrel != dvr_none) {
+    varbufprintf(aemsgs, _("  Version of %s to be configured is %s.\n"),
+                 broken->name,
+                 versiondescribe(&broken->installed.version, vdew_nonambig));
+    if (fc_dependsversion) return;
+  }
+  if (force_breaks(breaks)) return;
+  *ok= 0;
+}
+
+void breaks_check_target(struct varbuf *aemsgs, int *ok,
+                         struct pkginfo *broken,
+                         struct pkginfo *target,
+                         struct pkginfo *virtbroken) {
+  struct deppossi *possi;
+
+  for (possi= target->installed.depended; possi; possi= possi->nextrev) {
+    if (possi->up->type != dep_breaks) continue;
+    if (virtbroken && possi->verrel != dvr_none) continue;
+    breaks_check_one(aemsgs, ok, possi, broken, possi->up->up, virtbroken);
+  }
+}
+
+int breakses_ok(struct pkginfo *pkg, struct varbuf *aemsgs) {
+  struct dependency *dep;
+  struct pkginfo *virtbroken;
+  int ok= 2;
+
+  debug(dbg_depcon, "    checking Breaks");
+
+  breaks_check_target(aemsgs, &ok, pkg, pkg, 0);
+
+  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);
+  }
+  return ok;
+}
+
 int dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
                     struct varbuf *aemsgs) {
   int ok, matched, found, thisf, interestingwarnings;

+ 20 - 19
src/processarc.c

@@ -241,6 +241,10 @@ void process_archive(const char *filename) {
       /* Look for things we conflict with. */
       check_conflict(dsearch, pkg, pfilename);
       break;
+    case dep_breaks:
+      /* Look for things we break. */
+      check_breaks(dsearch, pkg, pfilename);
+      break;
     case dep_provides:
       /* Look for things that conflict with what we provide. */
       if (dsearch->list->ed->installed.valid) {
@@ -252,16 +256,6 @@ void process_archive(const char *filename) {
         }
       }
       break;
-    case dep_breaks:
-      fprintf(stderr, _("dpkg: regarding %s containing %s:\n"
-			" package uses Breaks; not supported in this dpkg\n"),
-	      pfilename, pkg->name);
-      if (!force_depends(dsearch->list))
-	ohshit(_("unsupported dependency problem - not installing %.250s"),
-	       pkg->name);
-      fprintf(stderr, _("dpkg: warning - ignoring Breaks !\n"));
-      /* FIXME: implement Breaks */
-      break;
     case dep_suggests:
     case dep_recommends:
     case dep_depends:
@@ -404,12 +398,14 @@ void process_archive(const char *filename) {
     modstatdb_note(pkg);
   }
 
-  for (i = 0 ; i < cflict_index ; i++) {
-    if (!(conflictor[i]->status == stat_halfconfigured ||
-	  conflictor[i]->status == stat_installed)) continue;
     for (deconpil= deconfigure; deconpil; deconpil= deconpil->next) {
-      printf(_("De-configuring %s, so that we can remove %s ...\n"),
-             deconpil->pkg->name, conflictor[i]->name);
+      struct pkginfo *removing= deconpil->xinfo;
+
+      printf(removing ?
+             _("De-configuring %s, to allow removal of %s ...\n") :
+             _("De-configuring %s ...\n"),
+             deconpil->pkg->name, removing ? removing->name : 0);
+
       deconpil->pkg->status= stat_halfconfigured;
       modstatdb_note(deconpil->pkg);
       /* This means that we *either* go and run postinst abort-deconfigure,
@@ -419,16 +415,21 @@ void process_archive(const char *filename) {
       push_cleanup(cu_prermdeconfigure,~ehflag_normaltidy,
                    ok_prermdeconfigure,ehflag_normaltidy,
                    3,(void*)deconpil->pkg,
-		   (void*)conflictor[i],(void*)pkg);
+                   (void*)removing, (void*)pkg);
       maintainer_script_installed(deconpil->pkg, PRERMFILE, "pre-removal",
                                   "deconfigure", "in-favour", pkg->name,
                                   versiondescribe(&pkg->available.version,
                                                   vdew_nonambig),
-                                  "removing", conflictor[i]->name,
-                                  versiondescribe(&conflictor[i]->installed.version,
-                                                  vdew_nonambig),
+                                  removing ? "removing" : (char*)0,
+                                  removing ? removing->name : (char*)0,
+                                  removing ? versiondescribe(&removing->installed.version,
+                                                             vdew_nonambig) : (char*)0,
                                   (char*)0);
     }
+
+  for (i = 0 ; i < cflict_index; i++) {
+    if (!(conflictor[i]->status == stat_halfconfigured ||
+          conflictor[i]->status == stat_installed)) continue;
     conflictor[i]->status= stat_halfconfigured;
     modstatdb_note(conflictor[i]);
     push_cleanup(cu_prerminfavour,~ehflag_normaltidy, 0,0,