[PATCH 1/7] Split some useful functions from help.c to (new) util.c
A small number of functions from help.c are required for outside-of-dpkg
functioning of the conffiledb routines. As we want to be able to have
functional unit tests as well as to use these routines in other cmdline
programs (such as a hypothetical dpkg-conffile utility), we need to move
these functions out of help.c which is otherwise hopelessly intertwined with
the main dpkg code.
Therefore, the following functions have been moved to a new util.c file:
* void debug(int which, const char *fmt, ...)
* void ensure_pathname_nonexisting(const char *pathname)
* int secure_unlink(const char *pathname)
* int secure_unlink_statted(const char *pathname, const struct stat *stab)
Doxygen documentation has been added to the functions in the process.
Note that debug() still references an external int f_debug, which must be
provided by a cmdline program. It's left for discussion and/or future
implementation changes to fix that.
The Makefile.am automake template has also been updated to include this file
in dpkg_SOURCES. No further changes are required to dpkg source code.
---
src/Makefile.am | 3 +-
src/help.c | 72 --------------------------
src/util.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 156 insertions(+), 73 deletions(-)
create mode 100644 src/util.c
diff --git a/src/Makefile.am b/src/Makefile.am
index a29b629..6a3c783 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,7 +35,8 @@ dpkg_SOURCES = \
remove.c \
select.c \
trigproc.c \
- update.c
+ update.c \
+ util.c
dpkg_LDADD = \
../lib/dpkg/libdpkg.a \
diff --git a/src/help.c b/src/help.c
index 669ad13..981e9e2 100644
--- a/src/help.c
+++ b/src/help.c
@@ -464,16 +464,6 @@ void clear_istobes(void) {
iterpkgend(it);
}
-void debug(int which, const char *fmt, ...) {
- va_list ap;
- if (!(f_debug & which)) return;
- fprintf(stderr,"D0%05o: ",which);
- va_start(ap,fmt);
- vfprintf(stderr,fmt,ap);
- va_end(ap);
- putc('\n',stderr);
-}
-
/*
* Returns true if the directory contains conffiles belonging to pkg,
* false otherwise.
@@ -538,68 +528,6 @@ void oldconffsetflags(const struct conffile *searchconff) {
}
}
-/*
- * If the pathname to remove is:
- *
- * 1. a sticky or set-id file, or
- * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
- *
- * we change its mode so that a malicious user cannot use it, even if it's
- * linked to another file.
- */
-int
-secure_unlink(const char *pathname)
-{
- struct stat stab;
-
- if (lstat(pathname,&stab)) return -1;
-
- return secure_unlink_statted(pathname, &stab);
-}
-
-int
-secure_unlink_statted(const char *pathname, const struct stat *stab)
-{
- if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
- !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
- S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
- if (chmod(pathname, 0600))
- return -1;
- }
- if (unlink(pathname)) return -1;
- return 0;
-}
-
-void ensure_pathname_nonexisting(const char *pathname) {
- int c1;
- const char *u;
-
- u = path_skip_slash_dotslash(pathname);
- assert(*u);
-
- debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",pathname);
- if (!rmdir(pathname)) return; /* Deleted it OK, it was a directory. */
- if (errno == ENOENT || errno == ELOOP) return;
- if (errno == ENOTDIR) {
- /* Either it's a file, or one of the path components is. If one
- * of the path components is this will fail again ...
- */
- if (secure_unlink(pathname) == 0)
- return; /* OK, it was */
- if (errno == ENOTDIR) return;
- }
- if (errno != ENOTEMPTY && errno != EEXIST) { /* Huh ? */
- ohshite(_("unable to securely remove '%.255s'"), pathname);
- }
- c1= m_fork();
- if (!c1) {
- execlp(RM, "rm", "-rf", "--", pathname, NULL);
- ohshite(_("failed to exec rm for cleanup"));
- }
- debug(dbg_eachfile,"ensure_pathname_nonexisting running rm -rf");
- subproc_wait_check(c1, "rm cleanup", 0);
-}
-
void log_action(const char *action, struct pkginfo *pkg) {
log_message("%s %s %s %s", action, pkg->name,
versiondescribe(&pkg->installed.version, vdew_nonambig),
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..8a698f1
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,154 @@
+/**
+ * @file util.c
+ *
+ * Miscellaneous utility functions.
+ *
+ * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#include "dpkg/dpkg.h"
+#include "dpkg/i18n.h"
+#include "dpkg/path.h"
+#include "dpkg/subproc.h"
+
+/**
+ * General purpose and configurable debug output.
+ *
+ * @param which The logging category/severity, which should correspond to
+ * one or more bitwise maskings of enum debugflags. This parameter
+ * is then masked against the externally linked f_debug flag from
+ * the main program (which in turn is set by -Dh in the dpkg(1) main
+ * program, for example). In the case of a match the given format
+ * string and arguments are printed to stderr.
+ * @param fmt A standard printf(1) compatible format string, followed by any
+ * formatting variables.
+ */
+void
+debug(int which, const char *fmt, ...)
+{
+ va_list ap;
+ if (!(f_debug & which)) return;
+ fprintf(stderr,"D0%05o: ",which);
+ va_start(ap,fmt);
+ vfprintf(stderr,fmt,ap);
+ va_end(ap);
+ putc('\n',stderr);
+}
+
+/**
+ * Delete a pathname and anything that may be beneath it.
+ *
+ * This function is a generic catch-all delete utility, which will remove
+ * anything that may exist at the given pathname. If The pathname is
+ * a nonempty directory, it will be recursively removed with a fork/exec
+ * of rm -rf.
+ *
+ * @param pathname the path to be removed.
+ */
+void
+ensure_pathname_nonexisting(const char *pathname)
+{
+ int c1;
+ const char *u;
+
+ u = path_skip_slash_dotslash(pathname);
+ assert(*u);
+
+ debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",pathname);
+ if (!rmdir(pathname)) return; /* Deleted it OK, it was a directory. */
+ if (errno == ENOENT || errno == ELOOP) return;
+ if (errno == ENOTDIR) {
+ /* Either it's a file, or one of the path components is. If one
+ * of the path components is this will fail again ...
+ */
+ if (secure_unlink(pathname) == 0)
+ return; /* OK, it was */
+ if (errno == ENOTDIR) return;
+ }
+ if (errno != ENOTEMPTY && errno != EEXIST) { /* Huh ? */
+ ohshite(_("unable to securely remove '%.255s'"), pathname);
+ }
+ c1= m_fork();
+ if (!c1) {
+ execlp(RM, "rm", "-rf", "--", pathname, NULL);
+ ohshite(_("failed to exec rm for cleanup"));
+ }
+ debug(dbg_eachfile,"ensure_pathname_nonexisting running rm -rf");
+ subproc_wait_check(c1,"rm cleanup",0);
+}
+
+/**
+ * Safely unlink a given pathname, with checks on file type and mode.
+ *
+ * If the pathname to remove is:
+ *
+ * -# a sticky or set-id file, or
+ * -# an unknown object (i.e., not a file, link, directory, fifo or socket)
+ *
+ * we change its mode so that a malicious user cannot use it, even if it's
+ * linked to another file.
+ *
+ * @param pathname the path to unlink.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
+secure_unlink(const char *pathname)
+{
+ struct stat stab;
+
+ if (lstat(pathname,&stab))
+ return -1;
+
+ return secure_unlink_statted(pathname, &stab);
+}
+
+/**
+ * Safely unlink a given pathname, checking file type and mode against
+ * externally provided file type and mode information.
+ *
+ * See notes in secure_unlink.
+ *
+ * @param pathname the path to unlink.
+ * @param stab a struct stat containing information about the path.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
+secure_unlink_statted(const char *pathname, const struct stat *stab)
+{
+ if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
+ !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
+ S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
+ if (chmod(pathname, 0600))
+ return -1;
+ }
+ if (unlink(pathname))
+ return -1;
+ return 0;
+}
--
1.6.5.3
Reply to: