[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

interdiff (Re: [PATCH 3/6] Conffile database handling functions)



Jonathan Nieder wrote:

> For reference when looking at other patches, I made a bunch of
> cosmetic changes to make this patch a little easier to read.  This
> does not address Guillem’s comments, nor even all of my own.  The
> changes have not been considered carefully.  But maybe it can be of
> some use nevertheless.
> 
> Changes from Sean’s original:
[...]

Here is the promised interdiff.

 src/conffiledb.c   |  253 +++++++++++++++++++++++++++++------------------------
 src/conffiledb.h   |  141 +++++++++++++++++------------
 lib/dpkg/subproc.c |   34 +++----
 lib/dpkg/subproc.h |    1 
 4 files changed, 243 insertions(+), 186 deletions(-)

diff -u b/src/conffiledb.c b/src/conffiledb.c
--- b/src/conffiledb.c
+++ b/src/conffiledb.c
@@ -12,95 +12,94 @@
 
 #include <dpkg/dpkg.h>
 #include <dpkg/i18n.h>
+#include <dpkg/varbuf.h>
 #include <dpkg/buffer.h>
 #include <dpkg/path.h>
+#include <dpkg/subproc.h>
 #include <dpkg/dpkg-db.h>
 #include "main.h"
 
 const char *conffiledb_base_dirs[] = { "current", "new", "resolved", "tmp" };
 
-char* 
-conffiledb_path(const char *pkg, const char *path, conffiledb_base base)
+/* Find a conffiledb entry, conffiledb, or conffiledb base dir. */
+char *
+conffiledb_path(const struct pkginfo *pkg, const char *path,
+		conffiledb_base base)
 {
-	char *full_path = NULL, *hash = NULL;
-	const char *basedir = NULL;
-	size_t basedir_sz = 0, conffiledb_sz = 0, full_path_sz = 0;
+	struct varbuf full_path = VARBUF_INIT;
+	const char *basedir;
 
-	/* sanity check for a valid base dir */
+	/* sanity check */
 	if (base >= conffiledb_base_COUNT)
-		ohshit("conffiledb_path called with unsupported base %x", base);
+		ohshit(_("conffiledb_path called with unsupported base %x"),
+			base);
 
 	basedir = conffiledb_base_dirs[base];
+	varbufprintf(&full_path, "%s/%s%s/",
+		admindir, CONFFILEDBDIRROOT, basedir);
 
-	/* the root path is <admindir>/<#CONFFILEDBDIRROOT/><basedir>/
-	 * (note that the '/' after #CONFFILEDBDIRROOT is implicitly included 
-	 * in the #define'd string). The null byte is also accounted for
-	 * at this point. */
-	basedir_sz = strlen(admindir) + 1 + strlen(CONFFILEDBDIRROOT) +
-	             strlen(basedir) + 2;
-	full_path_sz = conffiledb_sz = basedir_sz;
-	
-	/* we will add "<pkg>/" to the string later if <pkg> is not null */
-	if (pkg != NULL) 
-		full_path_sz = conffiledb_sz += strlen(pkg) + 1;
-
-	/* and if a conffile is being requested (not just the db root)... */
-	if (path != NULL)
-		full_path_sz += CONFFILEDB_MD5SUM_LEN;
-
-	/* this is the path to the conffile db for the given base/pkg */
-	full_path = m_malloc(full_path_sz);
-	snprintf(full_path, basedir_sz, "%s/%s%s/", admindir, 
-	         CONFFILEDBDIRROOT, basedir);
-	
-	/* append "<pkg>/" if needed */
-	if (pkg != NULL)
-		sprintf(full_path + basedir_sz - 1, "%s/", pkg);
-
-	/* append the pathname's hash if relevant */
-	if (path != NULL) {
-		hash = full_path + conffiledb_sz - 1;
-		buffer_md5(path, hash, strlen(path));
-	}
-
-	debug(dbg_conffdetail, "confffiledb_path(%s, %s, %x) = %s\n", pkg, 
-	      path, base, full_path);
-
-	return full_path;
+	if (pkg == NULL)
+		goto done;
+	varbufprintf(&full_path, "%s/", pkg->name);
+
+	if (path == NULL)
+		goto done;
+	varbuf_grow(&full_path, CONFFILEDB_MD5SUM_LEN + 1);
+	buffer_md5(path, full_path.buf + full_path.used,
+		strlen(path));
+	full_path.used += CONFFILEDB_MD5SUM_LEN;
+
+done:
+	debug(dbg_conffdetail, "confffiledb_path(%s, %s, %x) = %s\n",
+		pkg ? pkg->name : "(null)", path ? path : "(null)", base,
+		full_path.buf);
+	return full_path.buf;
 }
 
-/** Ensure that a particular conffiledb dir exists.
+/**
+ * Ensure that a particular conffiledb dir exists.
+ *
+ * mkdir -p $CONFFILEDBDIRROOT/$base/$pkg
  *
  * @param pkg The package owning the conffiledb dir.
  * @param base Which conffiledb basedir to use.
  */
 static void
-conffiledb_ensure_db(const char *pkg, conffiledb_base base)
+conffiledb_ensure_db(const struct pkginfo *pkg, conffiledb_base base)
 {
-	struct stat s; 
-	short i = 0;
-	char *dbdir = NULL;
-	char *separators[3];
+	struct stat s;
+	int i;
+	char *dbdir, *end, *separators[3];
 
 	dbdir = conffiledb_path(pkg, NULL, base);
-	/* temporarily truncate the string to cheaply traverse up to the
+
+	/* sanity check */
+	if (*dbdir != '/')
+		ohshit(_("conffiledb_path returned a relative path"));
+
+	/*
+	 * Temporarily truncate the string to cheaply traverse up to the
 	 * the parent and its parent. store the locations so we can cheaply
-	 * get back to them later. */
+	 * get back to them later.
+	 */
+	end = dbdir + strlen(dbdir);
 	for (i = 0; i < 3; i++) {
-		separators[i] = rindex(dbdir, '/');
-		*separators[i] = '\0';
+		while (*end != '/' && end != dbdir)
+			end--;
+		*end = '\0';
+		separators[i] = end;
 	}
 
-	/* now ensure each directory exists while reconstructing the path */
+	/* Now ensure each directory exists while reconstructing the path. */
 	for (i = 2; i >= 0; i--) {
 		if (stat(dbdir, &s)) {
-			debug(dbg_conffdetail, 
+			debug(dbg_conffdetail,
 			      "conffiledb_ensure_db: creating %s\n", dbdir);
-			if (errno != ENOENT) 
-				ohshite("conffiledb_ensure_db: stat(%s)", 
+			if (errno != ENOENT)
+				ohshite("conffiledb_ensure_db: stat(%s)",
 				        dbdir);
-			if (mkdir(dbdir, S_IRWXU)) 
-				ohshite("conffiledb_ensure_db: mkdir(%s)", 
+			if (mkdir(dbdir, S_IRWXU))
+				ohshite("conffiledb_ensure_db: mkdir(%s)",
 				        dbdir);
 		}
 		*separators[i] = '/';
@@ -109,76 +108,93 @@
 	free(dbdir);
 }
 
+/* Add a new entry to $CONFFILEDBDIRROOT/new/$pkg. */
 void
-conffiledb_register_new_conffile(const char *pkg, const char *path, int fd, 
-                                 size_t sz)
+conffiledb_register_new_conffile(const struct pkginfo *pkg,
+		const char *path, int fd, size_t sz)
 {
 	int cfgfd;
-	/* get the path to where the registered file goes */
-	char *p = conffiledb_path(pkg, path, conffiledb_base_new);
-	char fnamebuf[256];
+	char *dest;
+	char msg_dest[256];
+
+	/* sanity check */
+	if (path == NULL || pkg == NULL)
+		ohshit(_("conffiledb_register_new_conffile called "
+			"with NULL arguments"));
+
+	dest = conffiledb_path(pkg, path, conffiledb_base_new);
+	path_quote_filename(msg_dest, dest, sizeof(msg_dest));
+	debug(dbg_conff, "conffile_register_new_conffile: %s, %s, %s\n",
+		pkg->name, path, msg_dest);
 
 	conffiledb_ensure_db(pkg, conffiledb_base_new);
-	debug(dbg_conff, "conffile_reg_fd: %s, %s, %s\n", pkg, path, p);
-	/* make a mode 600 copy of file to p */
-	cfgfd = open(p, (O_CREAT|O_EXCL|O_WRONLY), (S_IRUSR|S_IWUSR));
-	if (cfgfd < 0) 
-		ohshite(_("unable to create `%.255s'"),p);
-	fd_fd_copy(fd, cfgfd, sz, _("backend dpkg-deb during `%.255s'"),
-	           path_quote_filename(fnamebuf, p, 256));
-	if (close(cfgfd))
-		ohshite("can't close %s", p);
 
-	free(p);
+	cfgfd = open(dest, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
+	if (cfgfd < 0)
+		ohshite(_("unable to create `%.255s'"), msg_dest);
+	fd_fd_copy(fd, cfgfd, sz, _("new conffiledb entry '%.255s'"),
+	           msg_dest);
+
+	if (close(cfgfd))
+		ohshite("can't close %.255s", msg_dest);
+	free(dest);
 }
 
+/* Open a conffiledb entry for reading. */
 int
-conffiledb_get_conffile(const char *pkg, const char *path, conffiledb_base base)
+conffiledb_get_conffile(const struct pkginfo *pkg,
+		const char *path, conffiledb_base base)
 {
-	int fd = -1;
+	int fd;
 	char *p = conffiledb_path(pkg, path, base);
 
 	fd = open(p, O_RDONLY);
-	if (fd == -1)
-		ohshite("error opening conffile registered at %s", p);
+	if (fd == -1) {
+		char msg_p[256];
+		ohshite(_("error opening conffile registered at %.255s"),
+			path_quote_filename(msg_p, p, sizeof(msg_p)));
+	}
 
 	free(p);
 	return fd;
 }
 
+/*
+ * Update the conffiles "db" dir.  This consists of the following steps:
+ * - nuke the tmp dir if it exists
+ * - rename to_base to the tmp dir
+ * - rename from_base to to_base
+ * - nuke the tmp dir
+ */
 void
-conffiledb_commit(const char *pkg, conffiledb_base from_base, 
+conffiledb_commit(const struct pkginfo *pkg, conffiledb_base from_base,
                   conffiledb_base to_base)
 {
-	/* update the conffiles "db" dir.  this consists of the following steps:
-	 * - nuke the tmp dir if it exists
-	 * - rename to_base to the tmp dir
-	 * - rename from_base to to_base
-	 * - nuke the tmp dir
-	 */
 	char *cfdb_to = NULL, *cfdb_from = NULL, *cfdb_tmp = NULL;
-	debug(dbg_conff, "conffiledb_commit(%s, %d, %d)", pkg, from_base, 
-	      to_base);
+
+	/* sanity check */
+	if (pkg == NULL)
+		ohshit(_("conffiledb_commit called for NULL package"));
+
+	debug(dbg_conff, "conffiledb_commit(%s, %d, %d)",
+		pkg->name, from_base, to_base);
 
 	cfdb_from = conffiledb_path(pkg, NULL, from_base);
 	cfdb_to = conffiledb_path(pkg, NULL, to_base);
 	cfdb_tmp = conffiledb_path(pkg, NULL, conffiledb_base_tmp);
 
-	/* Make sure all leading components of the tmp conffiledb exist */
 	conffiledb_ensure_db(pkg, conffiledb_base_tmp);
-	/* Then nuke the tmp conffiledb if it exists */
 	conffiledb_remove(pkg, conffiledb_base_tmp);
-	/* Make sure all leading components of the target conffiledb exist */
+
 	conffiledb_ensure_db(pkg, to_base);
-	/* Rename the target conffiledb to the tmp one */
 	if (rename(cfdb_to, cfdb_tmp))
-		ohshite("conffiledb_commit: rename(%s,%s)", cfdb_to, cfdb_tmp);
-	/* Make sure all leading components of the source conffiledb exist */
+		ohshite(_("conffiledb_commit: rename(%s, %s)"),
+			cfdb_to, cfdb_tmp);
 	conffiledb_ensure_db(pkg, from_base);
-	/* Rename from_base to to_base */
 	if (rename(cfdb_from, cfdb_to))
-		ohshite("conffiledb_commit: rename(%s,%s)", cfdb_from, cfdb_to);
-	/* Nuke the tmp version if it exists */
+		ohshite(_("conffiledb_commit: rename(%s, %s)"),
+			cfdb_from, cfdb_to);
+
 	conffiledb_remove(pkg, conffiledb_base_tmp);
 
 	free(cfdb_from);
@@ -188,31 +204,44 @@
 
+/* Remove a conffiledb with all of its entries. */
 void
-conffiledb_remove(const char *pkg, conffiledb_base base)
+conffiledb_remove(const struct pkginfo *pkg, conffiledb_base base)
 {
-	char *cfdb = conffiledb_path(pkg, NULL, base);
+	char *cfdb;
+
+	/* sanity check */
+	if (pkg == NULL)
+		ohshit(_("conffiledb_remove called for NULL package"));
 
-	debug(dbg_conff, "conffiledb_remove(%s): removing %s\n", pkg, cfdb);
+	cfdb = conffiledb_path(pkg, NULL, base);
+	debug(dbg_conff, "conffiledb_remove(%s): removing %s\n",
+		pkg->name, cfdb);
 	ensure_pathname_nonexisting(cfdb);
 
 	free(cfdb);
 }
 
+/* Spawn 'diff -u <conffiledb entry> <installed conffile>'. */
 int
-conffiledb_diff (const char *pkg, const char *path, conffiledb_base base)
+conffiledb_diff(const struct pkginfo *pkg, const char *path,
+		conffiledb_base base)
 {
-	int status;
-	char *src = conffiledb_path(pkg, path, base);
-	char *cmd = NULL;
-	const char *opts = "-u";
-	/* DIFF + ' ' + <opts> + ' ' + <srcfile> + ' ' + <dstfile> + '\0' */
-	size_t cmd_sz = strlen(DIFF) + 1 + strlen(opts) + 1 + strlen(src) +
-	                1 + strlen(path) + 1;
-
-	cmd = m_malloc(cmd_sz);
-	sprintf(cmd, "%s %s %s %s", DIFF, opts, src, path);
-	status = system(cmd);
+	int child, result;
+	char *src;
+
+	/* sanity check */
+	if (pkg == NULL || path == NULL)
+		ohshit(_("conffiledb_diff called for NULL conffile"));
+
+	src = conffiledb_path(pkg, path, base);
+
+	if (!(child = m_fork())) {
+		execlp(DIFF, "diff", "-u", src, path, NULL);
+		ohshite(_("failed to exec 'diff -u %s %s'"),
+			src, path);
+	}
+
+	result = waitsubproc(child, "diff", PROCNOERR | PROCSAVESTATUS);
 
 	free(src);
-	free(cmd);
-	return WEXITSTATUS(status);
+	return result;
 }
diff -u b/src/conffiledb.h b/src/conffiledb.h
--- b/src/conffiledb.h
+++ b/src/conffiledb.h
@@ -1,7 +1,7 @@
 /**
  * @file conffiledb.h
  *
- * Functions for tracking referencable versions of packages' conffiles.
+ * Functions for tracking referenceable versions of packages' conffiles.
  *
  * This library allows for tracking the pristine versions (and in some specific
  * cases a few other versions) of packages' conffiles.  This allows for a
@@ -15,19 +15,23 @@
  *	#CONFFILEDBDIRROOT/\<base\>/\<pkg\>/\<md5\>
  *
  * where:
- * - @b \<base\> is a short string which corresponds to the base reference
- *   type in question. See the documentation for conffiledb_base for the 
- *   enumerated values and conffiledb_base_dirs for the corresponding
- *   string values.
- * - @b \<pkg\> is the conffile database directory for an individual package.
- * - @b \<md5\> is the md5 hash of the location of a package's conffile.  A 
+ * - @b \<base\> is a short string describing which version of the conffile
+ *   this is. See enum #conffiledb_base for the enumerated values and
+ *   #conffiledb_base_dirs for the corresponding strings.
+ * - @b \<pkg\> is the package name.
+ * - @b \<md5\> is the md5 hash of the location of a package's conffile.  A
  *   hash is used to keep a flat and balanced directory structure, and has
  *   the added benefit of a simpler implementation.
  *
  * Some further terminology to keep things clear later on:
  *
- * - @b "conffiledb root" refers to the top-most directory containing
- *   all conffile databases, and is defined by #CONFFILEDBDIRROOT.
+ * - @b "conffiledb file" or @b "conffiledb entry" refers to a file whose
+ *   contents correspond to a particular conffiledb_base/package/conffile
+ *   triplet.
+ * - @anchor conffiledb @b "conffile database" or @b "conffiledb" refers
+ *   to a directory specific to a conffiledb_base + package tuple.  Such a
+ *   directory will contain copies of the conffiles named after the hash
+ *   of their respective installed locations.
  * - @b "conffiledb basedir" refers to the subdirectory directly
  *   underneath the conffiledb root directory, which divides the the
  *   different conffiledbs by different "reference types" (i.e. the
@@ -35,19 +39,17 @@
  *   a newly unpacked version). The available basedirs are defined in
  *   conffiledb_base_dirs, which is indexed on the respective enumerated
  *   values from conffiledb_base.
- * - @anchor conffiledb @b "conffile database" or @b "conffiledb" refers
- *   to a directory specific to a conffiledb_base + package tuple.  Such a
- *   directory will contain copies of the conffiles named after the hash
- *   of their respective installed locations.
- * - @b "conffiledb file" or @b "conffiledb entry" refers to a file whose 
- *   contents correspond to a particular conffiledb_base/package/conffile 
- *   triplet.
+ * - @b "conffiledb root" refers to the top-most directory containing
+ *   all conffile databases, and is defined by #CONFFILEDBDIRROOT.
  */
 #ifndef CONFFILES_H
 #define CONFFILES_H
 
 #include <sys/types.h>
 
+/* Defined in dpkg/dpkg-db.h. */
+struct pkginfo;
+
 /** The different base reference types underneath the conffile db. */
 typedef enum {
 	conffiledb_base_current, /**< The currently installed version */
@@ -57,7 +59,7 @@
 	conffiledb_base_COUNT /**< The count of possible values for this type */
 } conffiledb_base;
 
-/** 
+/**
  * The directory names of the conffiledb base dirs, indexed by the respective
  * conffiledb_base value.
  */
@@ -66,13 +68,14 @@
 /** Length of the MD5 string used in conffile path hashing (NULL not counted) */
 #define CONFFILEDB_MD5SUM_LEN 32
 
-/** Return the canonical path for a conffiledb entry or other location.
+/**
+ * Determine the canonical path for a conffiledb entry.
  *
- * This is a helper function to resolve the full path to a specific location 
+ * This is a helper function to resolve the full path to a specific location
  * within the conffile database. The primary use is to find the location
  * of a conffiledb file, but it can also be used to find the location
  * of the @ref conffiledb for a particular conffiledb_base + package,
- * as well as the parent conffiledb basedir corresponding to a particular 
+ * as well as the parent conffiledb basedir corresponding to a particular
  * conffiledb_base.
  *
  * @param pkg The package name. If NULL, the returned value will be
@@ -81,75 +84,99 @@
  *        value will be the conffiledb directory which should contain all
  *        conffiledb files for the combination of pkg and base.
- * @param base Which conffiledb basedir is requested.
+ * @param base Which conffiledb base reference type is requested.
+ *
  * @return An allocated string with the path (your job to free it).
  */
-char* conffiledb_path(const char *pkg, const char *path, conffiledb_base base);
+char *conffiledb_path(const struct pkginfo *pkg, const char *path,
+	conffiledb_base base);
 
-/** Register a new conffiledb file for a package.
+/**
+ * Add a new conffiledb entry for a package.
  *
- * Create a conffiledb entry in the conffiledb dir for the::conffiledb_base_new
- * version of a particular package. The conffile will be later processed in the
- * package configuration stage, after which there should be a call to
- * conffiledb_commit_new before configuration can be considered successful.
- *
- * The use of a filedescriptor is due to the fact that the new conffile is
- * intercepted very early during the unpack phase, before it exists on disk.
- * Therefore this interface is designed to hook cleanly into what's available 
- * at that point, which is a filedescriptor generated from a struct TarInfo
- * (see tarobject in archives.c).
+ * For use when unpacking a package.  Create a conffiledb entry in the
+ * conffiledb dir for the #conffiledb_base_new version of a particular
+ * package. The conffile will be later processed in the package configuration
+ * stage, after which there should be a call to conffiledb_commit() before
+ * configuration can be considered successful.
+ *
+ * The use of a file descriptor allows the new entry to be written very early
+ * in the unpack phase, before it exists on disk.  This interface is designed
+ * to hook cleanly with what's available, which is filedescriptor representing
+ * output from tar extraction.
  *
  * @param pkg The package owning the conffile.
  * @param path The installed location of the conffile.
  * @param fd A file descriptor holding the contents of the conffile.
- * @param sz The size of the conffile.
+ * @param sz Size of the conffile in bytes.
+ *           (XXX why is this not off_t, -1 allowed?)
  */
-void conffiledb_register_new_conffile(const char *pkg, const char *path, int fd,
-                                      size_t sz);
+void conffiledb_register_new_conffile(const struct pkginfo *pkg,
+	const char *path, int fd, size_t sz);
 
-/** Get a readable filehandle to the contents of a conffiledb entry.
+/**
+ * Open a conffiledb entry for reading.
  *
  * @param pkg The package owning the conffile.
  * @param path The installed location of the conffile.
  * @param base Which conffiledb basedir to use.
- * @return A read-only file descriptor for the registered conffile.
+ *
+ * @return A read-only file descriptor for the registered conffile
+ *         (your job to close it).
  */
-int conffiledb_get_conffile(const char *pkg, const char *path, 
-                            conffiledb_base base);
+int conffiledb_get_conffile(const struct pkginfo *pkg,
+	const char *path, conffiledb_base base);
 
-/** Remove a conffiledb directory for a package.
+/**
+ * Remove a package’s conffiledb.
+ *
+ * Remove the indicated version of the specified package’s conffiledb.
  *
- * This is designed to be used in two use cases: 
- * - package removal and cleanup
- * - after one conffiledb directory has been replaced by another.
+ * This should be useful in two cases:
+ * - purging a package’s configuration files
+ * - replacing one conffiledb with another.
  *
  * @param pkg The package owning the conffile db to be removed.
  * @param base Which conffiledb basedir to use with respect to pkg.
  */
-void conffiledb_remove(const char *pkg, conffiledb_base base);
+void conffiledb_remove(const struct pkginfo *pkg, conffiledb_base base);
 
-/** Commit one conffiledb as another, replacing any existing one.
+/**
+ * Move a conffiledb from one base reference type to another.
  *
- * This function takes the conffiledb defined by pkg and from_base and
- * commits it as being defined by pkg and to_base. Any existing conffiledb
- * for pkg / to_base is first renamed as conffiledb_base_tmp and then
- * removed after the successful "commit" (to keep things as atomic as 
- * possible).
+ * This is a safer way to perform the operation
+ *  
+ *	rm -r $CONFFILEDBDIRROOT/$to_base/$pkg
+ *	mv $CONFFILEDBDIRROOT/$from_base/$pkg $CONFFILEDBDIRROOT/$to_base/
+ *
+ * The conffiledb corresponding to pkg and the tmp base reference type
+ * is used as a temporary location to hold the entries from to_base until
+ * the entries from from_base are put into place.
+ *
+ * Any entries already in the tmp/$pkg conffiledb will be removed.  The
+ * invoking program is responsible for putting things back in order upon
+ * failure.
  *
  * @param pkg The package owning the conffile database
  * @param from_base The current conffiledb basedir which should be renamed.
  * @param to_base The conffiledb basedir which should be replaced by the
  *        version in from_base.
  */
-void conffiledb_commit(const char *pkg, conffiledb_base from_base, 
-                       conffiledb_base to_base);
+void conffiledb_commit(const struct pkginfo *pkg,
+	conffiledb_base from_base, conffiledb_base to_base);
 
-/** Show the diff between a conffiledb entry and a corresponding conffile.
- * 
+/**
+ * Print a diff between a conffiledb entry and the installed version.
+ *
+ * Print a unified diff between a conffiledb entry and the corresponding
+ * installed conffile to stdout.
+ *
  * @param pkg The package that owns the conffile.
  * @param path The pathname to the installed version of the conffile.
  * @param base Which conffiledb basedir to use.
- * @return The exit status of the underlying call to diff(1).
+ *
+ * @return The exit status from diff(1).
  */
-int conffiledb_diff(const char *pkg, const char *path, conffiledb_base base);
+int conffiledb_diff(const struct pkginfo *pkg, const char *path,
+	conffiledb_base base);
 
 #endif /* CONFFILES_H */
only in patch2:
unchanged:
--- a/lib/dpkg/subproc.c
+++ b/lib/dpkg/subproc.c
@@ -73,22 +73,24 @@ cu_subproc_signals(int argc, void **argv)
 int
 checksubprocerr(int status, const char *description, int flags)
 {
-	int n;
+	if (flags & PROCWARN)
+		flags |= PROCNOERR;
 
 	if (WIFEXITED(status)) {
-		n = WEXITSTATUS(status);
+		int n = WEXITSTATUS(status);
+
 		if (!n)
 			return 0;
-		if (flags & PROCNOERR)
-			return -1;
 		if (flags & PROCWARN)
 			warning(_("%s returned error exit status %d"),
 			        description, n);
-		else
-			ohshit(_("subprocess %s returned error exit status %d"),
-			       description, n);
+		if (flags & PROCNOERR)
+			return flags & PROCSAVESTATUS ? n : -1;
+		ohshit(_("subprocess %s returned error exit status %d"),
+		       description, n);
 	} else if (WIFSIGNALED(status)) {
-		n = WTERMSIG(status);
+		int n = WTERMSIG(status);
+
 		if (!n)
 			return 0;
 		if ((flags & PROCPIPE) && n == SIGPIPE)
@@ -97,16 +99,14 @@ checksubprocerr(int status, const char *description, int flags)
 			warning(_("%s killed by signal (%s)%s"),
 			        description, strsignal(n),
 			        WCOREDUMP(status) ? _(", core dumped") : "");
-		else
-			ohshit(_("subprocess %s killed by signal (%s)%s"),
-			       description, strsignal(n),
-			       WCOREDUMP(status) ? _(", core dumped") : "");
-	} else {
-		ohshit(_("subprocess %s failed with wait status code %d"),
-		       description, status);
+		if (flags & PROCNOERR)
+			return -1;
+		ohshit(_("subprocess %s killed by signal (%s)%s"),
+		       description, strsignal(n),
+		       WCOREDUMP(status) ? _(", core dumped") : "");
 	}
-
-	return -1;
+	ohshit(_("subprocess %s failed with wait status code %d"),
+	       description, status);
 }
 
 int
only in patch2:
unchanged:
--- a/lib/dpkg/subproc.h
+++ b/lib/dpkg/subproc.h
@@ -34,6 +34,7 @@ void cu_subproc_signals(int argc, void **argv);
 #define PROCPIPE 1
 #define PROCWARN 2
 #define PROCNOERR 4
+#define PROCSAVESTATUS 8
 
 int checksubprocerr(int status, const char *desc, int flags);
 int waitsubproc(pid_t pid, const char *desc, int flags);


Reply to: