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

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
Родитель
Сommit
b301c0e71a
18 измененных файлов с 298 добавлено и 55 удалено
  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,