+/* 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
*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);
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) {
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;
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);
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. */
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')",
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);