]> err.no Git - dpkg/commitdiff
Implement support for Breaks field.
authorIan Jackson <iwj@ubuntu.com>
Tue, 7 Aug 2007 02:52:46 +0000 (05:52 +0300)
committerGuillem Jover <guillem@debian.org>
Tue, 7 Aug 2007 03:22:34 +0000 (06:22 +0300)
As a side effect, run the deconfiguration of each package to be
deconfigured once, instead of once per each conflicting package being
removed.

18 files changed:
ChangeLog
debian/changelog
man/deb-control.5
man/dpkg-query.1
man/dpkg.1
scripts/controllib.pl
scripts/dpkg-genchanges.pl
scripts/dpkg-source.pl
src/archives.c
src/archives.h
src/cleanup.c
src/configure.c
src/depcon.c
src/help.c
src/main.c
src/main.h
src/packages.c
src/processarc.c

index 34e3038469b87e80bde9b5bc425033696252e737..87304163eeac2cc80fe2f520466949fe94d3cffe 100644 (file)
--- a/ChangeLog
+++ b/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
index 7a477547a6e24aeb1b879421c360ffa04dc94fe3..638ba6d8dd73b98085314c6d5d811ae6a0a2093d 100644 (file)
@@ -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).
index 41613932d41fbccc4b3234fce9938aa7b099407e..3cde45c7f6cb4c0ae54f0a5b46f838c8a35491bb 100644 (file)
@@ -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
index e030d6237236d7c8f3f2bd6817c131964c1d2699..9f03411ef70ad180f509c072905aaa3106234932 100644 (file)
@@ -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
index 6f8624e8aaae063939f4fe1bbef88dad4bb39c94..4d97649818d184054892e01b18327b4df23865d4 100644 (file)
@@ -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.
index 08cbd31121452565557719f82d0c411e53f240a7..a94ff2bfbe59eae2f277728068ce6ab53012180f 100755 (executable)
@@ -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);
 
index 42564c9da93a8e98d02f5169c71fc942c681e347..967eede4f8b8e9864f9a8d9c87011f9c1b640a39 100755 (executable)
@@ -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"));
index 1ed1213b340284820085ea58f2dfc4acd2cc2b21..9706f23c449329106f1fbb356dcbebcf430d75c5 100755 (executable)
@@ -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"));
index 826cbf3d6fa6bd5dfda4eac76d28a9eef4ff620f..b907d92662c8c4b598f616800238a8c42c2f4847 100644 (file)
@@ -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;
index 60b3aae38cb133371fd6b4af204b20e6bb0e74d8..5696c198ba0eb9ec6a760521a4dea712376f283b 100644 (file)
@@ -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);
index d1996b16c7ec6838d4ac31117becd55ab8d46cf2..6a96836f3dc8f0cf91135ba9f285a8708376932e 100644 (file)
@@ -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);
index 0df4582c3338ffa2d6cc9adab6b9c2cded8a289d..0615728a44e7faff01cae08d418b95a45044589b 100644 (file)
@@ -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,
index a54279cbeaad8557320201235419946ba9f00768..24f93aea3126492a80190851ae949b1d54adf521 100644 (file)
@@ -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]));
index cacca11f484a948998dced9b146c2455d9f4b073..ba4a84550c2cc14979a5e57cf3aa3c9a6a3f8b70 100644 (file)
@@ -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;
 }
index 29e4cc7d5422d7e2d785ef7f954d355cfe10d6e7..28c4d5ae29183dce02b23f980ba1576b10dec8de 100644 (file)
@@ -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                },
index 0560c4c9d58e661e8b66e2f50b9d75a6c81d6060..10110942f4ded752488acc835168d0a6ae237e58 100644 (file)
@@ -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);
index 8e5a77b54492536462f8aedcd2b638f327f9b05b..ebbd5a90f8c7daa5ba210bb4c8353f6d6c05e6c5 100644 (file)
@@ -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;
index c22f623e539d6b45328c7f5f2c0eb73816f048fd..31f28e9492ba0e324d8a324e779462be9e30215e 100644 (file)
@@ -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,