From 825144f5ceedcd433b14d20dea4121c1d6d65426 Mon Sep 17 00:00:00 2001 From: Adam Heath Date: Sat, 13 Sep 2003 21:17:14 +0000 Subject: [PATCH] Retry removing empty dirs during purge. --- ChangeLog | 4 + debian/changelog | 2 + main/remove.c | 187 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 148 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index e63d7e03..ebd5cbcf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Sat Sep 13 16:16:52 CDT 2003 Adam Heath + + * main/remove.c: Retry removing empty dirs during purge. + Sat Sep 13 16:09:13 CDT 2003 Adam Heath * main/filesdb.c: Increase filesdb bin size, and alter hashing function. diff --git a/debian/changelog b/debian/changelog index 82f299d6..8c3b8be8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -32,6 +32,8 @@ dpkg (1.10.11) unstable; urgency=low * Sami Liedes : Increase filesdb bin size, and alter hashing function. Closes: #179385 + * Anthony Towns : + Retry removing empty dirs during purge. Closes: #112386 -- Wichert Akkerman UNRELEASED diff --git a/main/remove.c b/main/remove.c index f6ea83a7..7b111b16 100644 --- a/main/remove.c +++ b/main/remove.c @@ -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); -- 2.39.5