]> err.no Git - dpkg/commitdiff
Retry removing empty dirs during purge.
authorAdam Heath <doogie@debian.org>
Sat, 13 Sep 2003 21:17:14 +0000 (21:17 +0000)
committerAdam Heath <doogie@debian.org>
Sat, 13 Sep 2003 21:17:14 +0000 (21:17 +0000)
ChangeLog
debian/changelog
main/remove.c

index e63d7e03c59b0f6252d158652b9d8fa4367241df..ebd5cbcf1c9b79f318bb0bf0af244b56fdf7e44f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sat Sep 13 16:16:52 CDT 2003 Adam Heath <doogie@debian.org>
+
+  * main/remove.c: Retry removing empty dirs during purge.
+
 Sat Sep 13 16:09:13 CDT 2003 Adam Heath <doogie@debian.org>
 
   * main/filesdb.c: Increase filesdb bin size, and alter hashing function.
index 82f299d65432a4b06d1391f4336d0ad6b50cbf50..8c3b8be81bb89f7b6b9446dfb183135d5bdf8357 100644 (file)
@@ -32,6 +32,8 @@ dpkg (1.10.11) unstable; urgency=low
   * Sami Liedes <sliedes@cc.hut.fi>:
     Increase filesdb bin size, and alter hashing function.  Closes:
     #179385
+  * Anthony Towns <aj@azure.humbug.org.au>:
+    Retry removing empty dirs during purge.  Closes: #112386
 
  -- Wichert Akkerman <debian@extern.wiggy.net>  UNRELEASED
 
index f6ea83a7b7e8ec5a50ebf6f282c4ab85eb00d603..7b111b16569d1ead225e3cec3eaf8863515e9949 100644 (file)
@@ -1,3 +1,17 @@
+/* Change: separate removal_bulk handling of halfinstalled or unpacked pkgs
+ *         (ie, remove the real files in the .deb) into its own function.
+ *         Note that "installed" state is converted to unpacked by 
+ *         deferred_remove() or halfinstalled by process_archive())
+ *
+ * Change: separate purging of configfiles and running of postrm to its
+ *         own function.
+ *
+ * Change: retry removing directories after postrm purge is finished, to
+ *         handle directories that had conffiles or config files and so
+ *         forth in them. also only warn about non-empty directories at
+ *         that point.
+ */
+
 /*
  * dpkg - main program for package management
  * remove.c - functionality for removing packages
@@ -173,32 +187,20 @@ static void push_leftover(struct fileinlist **leftoverp,
   *leftoverp= newentry;
 }
 
-void removal_bulk(struct pkginfo *pkg) {
-  /* This is used both by deferred_remove in this file, and at
-   * the end of process_archive in archives.c if it needs to finish
-   * removing a conflicting package.
-   */
-  static const char *const removeconffexts[]= { REMOVECONFFEXTS, 0 };
-
-  static struct varbuf fnvb, removevb;
-  
-  int before, r, foundpostrm= 0, removevbbase;
-  int infodirbaseused, conffnameused, conffbasenamelen, pkgnameused;
-  char *conffbasename;
+static void removal_bulk_remove_files(
+    struct pkginfo *pkg, 
+    int *out_foundpostrm) 
+{
+  int before;
+  int infodirbaseused;
   struct reversefilelistiter rlistit;
-  struct conffile *conff, **lconffp;
-  struct fileinlist *searchfile, *leftover;
-  struct stat stab;
+  struct fileinlist *leftover;
+  struct filenamenode *namenode;
+  static struct varbuf fnvb;
   DIR *dsd;
   struct dirent *de;
-  char *p;
-  const char *const *ext;
-  const char *postrmfilename;
-  struct filenamenode *namenode;
-
-  debug(dbg_general,"removal_bulk package %s",pkg->name);
+  struct stat stab;
   
-  if (pkg->status == stat_halfinstalled || pkg->status == stat_unpacked) {
     pkg->status= stat_halfinstalled;
     modstatdb_note(pkg);
     push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
@@ -242,10 +244,6 @@ void removal_bulk(struct pkginfo *pkg) {
       debug(dbg_eachfiledetail, "removal_bulk removing `%s'", fnvb.buf);
       if (!rmdir(fnvb.buf) || errno == ENOENT || errno == ELOOP) continue;
       if (errno == ENOTEMPTY) {
-        fprintf(stderr,
-                _("dpkg - warning: while removing %.250s, directory `%.250s' not empty "
-                "so not removed.\n"),
-                pkg->name, namenode->name);
         push_leftover(&leftover,namenode);
         continue;
       } else if (errno == EBUSY || errno == EPERM) {
@@ -286,11 +284,13 @@ void removal_bulk(struct pkginfo *pkg) {
     varbufaddc(&fnvb,0);
     dsd= opendir(fnvb.buf); if (!dsd) ohshite(_("cannot read info directory"));
     push_cleanup(cu_closedir,~0, 0,0, 1,(void*)dsd);
-    foundpostrm= 0;
+  *out_foundpostrm= 0;
 
     debug(dbg_general, "removal_bulk cleaning info directory");
 
     while ((de= readdir(dsd)) != 0) {
+    char *p;
+
       debug(dbg_veryverbose, "removal_bulk info file `%s'", de->d_name);
       if (de->d_name[0] == '.') continue;
       p= strrchr(de->d_name,'.'); if (!p) continue;
@@ -299,7 +299,7 @@ void removal_bulk(struct pkginfo *pkg) {
       debug(dbg_stupidlyverbose, "removal_bulk info this pkg");
       /* We need the postrm and list files for --purge. */
       if (!strcmp(p+1,LISTFILE)) continue;
-      if (!strcmp(p+1,POSTRMFILE)) { foundpostrm=1; continue; }
+    if (!strcmp(p+1,POSTRMFILE)) { *out_foundpostrm=1; continue; }
       debug(dbg_stupidlyverbose, "removal_bulk info not postrm or list");
       fnvb.used= infodirbaseused;
       varbufaddstr(&fnvb,de->d_name);
@@ -314,26 +314,80 @@ void removal_bulk(struct pkginfo *pkg) {
     pkg->installed.essential= 0;
     modstatdb_note(pkg);
     push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+}
 
-  } else {
+static void removal_bulk_remove_leftover_dirs(struct pkginfo *pkg) {
+  struct reversefilelistiter rlistit;
+  struct fileinlist *leftover;
+  struct filenamenode *namenode;
+  static struct varbuf fnvb;
+  struct stat stab;
 
-    postrmfilename= pkgadminfile(pkg,POSTRMFILE);
-    if (!lstat(postrmfilename,&stab)) foundpostrm= 1;
-    else if (errno == ENOENT) foundpostrm= 0;
-    else ohshite(_("unable to check existence of `%.250s'"),postrmfilename);
+  modstatdb_note(pkg);
+  push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+
+  reversefilelist_init(&rlistit,pkg->clientdata->files);
+  leftover= 0;
+  while ((namenode= reversefilelist_next(&rlistit))) {
+    debug(dbg_eachfile, "removal_bulk `%s' flags=%o",
+          namenode->name, namenode->flags);
+    if (namenode->flags & fnnf_old_conff) {
+      push_leftover(&leftover,namenode);
+      continue;
+    }
 
+    varbufreset(&fnvb);
+    varbufaddstr(&fnvb,instdir);
+    varbufaddstr(&fnvb,namenodetouse(namenode,pkg)->name);
+
+    if (!stat(fnvb.buf,&stab) && S_ISDIR(stab.st_mode)) {
+      debug(dbg_eachfiledetail, "removal_bulk is a directory");
+      /* Only delete a directory or a link to one if we're the only
+       * package which uses it.  Other files should only be listed
+       * in this package (but we don't check).
+       */
+      if (isdirectoryinuse(namenode,pkg)) continue;
+    }
+
+    debug(dbg_eachfiledetail, "removal_bulk removing `%s'", fnvb.buf);
+    if (!rmdir(fnvb.buf) || errno == ENOENT || errno == ELOOP) continue;
+    if (errno == ENOTEMPTY) {
+      fprintf(stderr,
+              _("dpkg - warning: while removing %.250s, directory `%.250s' not empty "
+              "so not removed.\n"),
+              pkg->name, namenode->name);
+      push_leftover(&leftover,namenode);
+      continue;
+    } else if (errno == EBUSY || errno == EPERM) {
+      fprintf(stderr, _("dpkg - warning: while removing %.250s,"
+              " unable to remove directory `%.250s':"
+              " %s - directory may be a mount point ?\n"),
+              pkg->name, namenode->name, strerror(errno));
+      push_leftover(&leftover,namenode);
+      continue;
+    }
+    if (errno != ENOTDIR) ohshite(_("cannot remove `%.250s'"),fnvb.buf);
+
+    push_leftover(&leftover,namenode);
+    continue;
   }
-  
-  debug(dbg_general, "removal_bulk purging? foundpostrm=%d",foundpostrm);
-  
-  if (!foundpostrm && !pkg->installed.conffiles) {
-    /* If there are no config files and no postrm script then we
-     * go straight into `purge'.
-     */
-    debug(dbg_general, "removal_bulk no postrm, no conffiles, purging");
-    pkg->want= want_purge;
+  write_filelist_except(pkg,leftover,0);
 
-  } else if (pkg->want == want_purge) {
+  modstatdb_note(pkg);
+  push_checkpoint(~ehflag_bombout, ehflag_normaltidy);
+}
+
+static void removal_bulk_remove_configfiles(struct pkginfo *pkg) {
+  static const char *const removeconffexts[]= { REMOVECONFFEXTS, 0 };
+  int r, removevbbase;
+  int conffnameused, conffbasenamelen;
+  char *conffbasename;
+  struct conffile *conff, **lconffp;
+  struct fileinlist *searchfile;
+  DIR *dsd;
+  struct dirent *de;
+  char *p;
+  const char *const *ext;
 
     printf(_("Purging configuration files for %s ...\n"),pkg->name);
     ensure_packagefiles_available(pkg); /* We may have modified this above. */
@@ -372,6 +426,7 @@ void removal_bulk(struct pkginfo *pkg) {
     modstatdb_note(pkg);
     
     for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
+    static struct varbuf fnvb, removevb;
       varbufreset(&fnvb);
       r= conffderef(pkg, &fnvb, conff->name);
       debug(dbg_conffdetail, "removal_bulk conffile `%s' (= `%s')",
@@ -441,14 +496,56 @@ void removal_bulk(struct pkginfo *pkg) {
         
     maintainer_script_installed(pkg, POSTRMFILE, "post-removal",
                                 "purge", (char*)0);
+}
+
+void removal_bulk(struct pkginfo *pkg) {
+  /* This is used both by deferred_remove in this file, and at
+   * the end of process_archive in archives.c if it needs to finish
+   * removing a conflicting package.
+   */
+
+  int pkgnameused;
+  int foundpostrm= 0;
+  const char *postrmfilename;
+
+  debug(dbg_general,"removal_bulk package %s",pkg->name);
+
+  if (pkg->status == stat_halfinstalled || pkg->status == stat_unpacked) {
+
+    removal_bulk_remove_files(pkg, &foundpostrm);
 
-    /* fixme: retry empty directories */
+  } else {
+    struct stat stab;
+
+    postrmfilename= pkgadminfile(pkg,POSTRMFILE);
+    if (!lstat(postrmfilename,&stab)) foundpostrm= 1;
+    else if (errno == ENOENT) foundpostrm= 0;
+    else ohshite(_("unable to check existence of `%.250s'"),postrmfilename);
 
   }
 
-  if (pkg->want == want_purge) {
+  debug(dbg_general, "removal_bulk purging? foundpostrm=%d",foundpostrm);
+  
+  if (!foundpostrm && !pkg->installed.conffiles) {
+    /* If there are no config files and no postrm script then we
+     * go straight into `purge'.
+     */
+    debug(dbg_general, "removal_bulk no postrm, no conffiles, purging");
+    pkg->want= want_purge;
+
+  } else if (pkg->want == want_purge) {
 
+    removal_bulk_remove_configfiles(pkg);
+
+  }
+
+  if (pkg->want == want_purge) {
     /* ie, either of the two branches above. */
+    static struct varbuf fnvb;
+
+    /* retry empty directories, and warn on any leftovers that aren't */
+    removal_bulk_remove_leftover_dirs(pkg);
+
     varbufreset(&fnvb);
     varbufaddstr(&fnvb,admindir);
     varbufaddstr(&fnvb,"/" INFODIR);