summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoerg <joerg>2008-08-05 22:56:24 +0000
committerjoerg <joerg>2008-08-05 22:56:24 +0000
commit149956fff8e877f3b47f8accc8a38c7e57d83425 (patch)
tree5ea2b4f847730463704895893816f0dee44fbb48
parente21bb0302cd16136a2ccca2e5ca11da4d06ad0d7 (diff)
downloadpkgsrc-149956fff8e877f3b47f8accc8a38c7e57d83425.tar.gz
pkg_install-20080806:
Provide and use internal implementation of rm -rf.
-rw-r--r--pkgtools/pkg_install/files/add/perform.c13
-rw-r--r--pkgtools/pkg_install/files/delete/perform.c8
-rw-r--r--pkgtools/pkg_install/files/lib/Makefile.in4
-rw-r--r--pkgtools/pkg_install/files/lib/lib.h25
-rw-r--r--pkgtools/pkg_install/files/lib/plist.c8
-rw-r--r--pkgtools/pkg_install/files/lib/remove.c184
-rw-r--r--pkgtools/pkg_install/files/lib/version.h4
7 files changed, 215 insertions, 31 deletions
diff --git a/pkgtools/pkg_install/files/add/perform.c b/pkgtools/pkg_install/files/add/perform.c
index 6bf4d2d6631..603b2ba122d 100644
--- a/pkgtools/pkg_install/files/add/perform.c
+++ b/pkgtools/pkg_install/files/add/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.70.4.16 2008/08/05 20:38:10 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.70.4.17 2008/08/05 22:56:24 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
@@ -6,7 +6,7 @@
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
-__RCSID("$NetBSD: perform.c,v 1.70.4.16 2008/08/05 20:38:10 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.70.4.17 2008/08/05 22:56:24 joerg Exp $");
/*-
* Copyright (c) 2003 Grant Beattie <grant@NetBSD.org>
@@ -1327,7 +1327,8 @@ nuke_pkg:
nuke_pkgdb:
if (!Fake) {
- (void) fexec(REMOVE_CMD, "-fr", pkg->install_logdir, (void *)NULL);
+ if (recursive_remove(pkg->install_logdir, 1))
+ warn("Couldn't remove %s", pkg->install_logdir);
free(pkg->install_logdir);
free(pkg->logdir);
pkg->install_logdir = NULL;
@@ -1335,8 +1336,10 @@ nuke_pkgdb:
}
clean_memory:
- if (pkg->logdir != NULL && NoRecord && !Fake)
- (void) fexec(REMOVE_CMD, "-fr", pkg->install_logdir, (void *)NULL);
+ if (pkg->logdir != NULL && NoRecord && !Fake) {
+ if (recursive_remove(pkg->install_logdir, 1))
+ warn("Couldn't remove %s", pkg->install_logdir);
+ }
free(pkg->install_prefix);
free(pkg->install_logdir);
free(pkg->logdir);
diff --git a/pkgtools/pkg_install/files/delete/perform.c b/pkgtools/pkg_install/files/delete/perform.c
index b50609df67b..259b1fbe062 100644
--- a/pkgtools/pkg_install/files/delete/perform.c
+++ b/pkgtools/pkg_install/files/delete/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.23.2.9 2008/08/05 22:25:54 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.23.2.10 2008/08/05 22:56:24 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.23.2.9 2008/08/05 22:25:54 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.23.2.10 2008/08/05 22:56:24 joerg Exp $");
#endif
#endif
@@ -839,8 +839,8 @@ pkg_do(char *pkg)
else if (is_depoted_pkg)
warnx("%s is not empty", pkgdir);
else if (Force) {
- if (fexec(REMOVE_CMD, "-rf", pkgdir, NULL) != 0) {
- warnx("couldn't remove log entry in %s", pkgdir);
+ if (recursive_remove(pkgdir, 1)) {
+ warn("Couldn't remove log entry in %s", pkgdir);
free(pkgdir);
return 1;
} else {
diff --git a/pkgtools/pkg_install/files/lib/Makefile.in b/pkgtools/pkg_install/files/lib/Makefile.in
index 4f8fc5b5455..913dbeb95e2 100644
--- a/pkgtools/pkg_install/files/lib/Makefile.in
+++ b/pkgtools/pkg_install/files/lib/Makefile.in
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.in,v 1.21.2.6 2008/08/02 20:33:50 joerg Exp $
+# $NetBSD: Makefile.in,v 1.21.2.7 2008/08/05 22:56:24 joerg Exp $
srcdir= @srcdir@
@@ -28,7 +28,7 @@ LIB= libinstall.a
OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \
global.o iterate.o lpkg.o opattern.o \
- parse-config.o path.o pkgdb.o plist.o \
+ parse-config.o path.o pkgdb.o plist.o remove.o \
str.o var.o version.o vulnerabilities-file.o xwrapper.o
CPPFLAGS+= -DSYSCONFDIR=\"$(sysconfdir)\"
diff --git a/pkgtools/pkg_install/files/lib/lib.h b/pkgtools/pkg_install/files/lib/lib.h
index 35916d9d169..48f4979c7f2 100644
--- a/pkgtools/pkg_install/files/lib/lib.h
+++ b/pkgtools/pkg_install/files/lib/lib.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lib.h,v 1.42.2.12 2008/08/05 19:09:35 joerg Exp $ */
+/* $NetBSD: lib.h,v 1.42.2.13 2008/08/05 22:56:24 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@@ -86,23 +86,16 @@
#define DEF_UMASK 022
#endif
-/* Usually "rm", but often "echo" during debugging! */
-#define REMOVE_CMD "rm"
-
-/* Usually "rm", but often "echo" during debugging! */
-#define RMDIR_CMD "rmdir"
-
-#ifndef CHMOD_CMD
-#define CHMOD_CMD "chmod"
-#endif
-
-/* some operating systems don't have this */
-#ifndef MAXPATHLEN
-#define MAXPATHLEN 1024
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 1024
+# endif
#endif
enum {
- MaxPathSize = MAXPATHLEN
+ MaxPathSize = PATH_MAX
};
/* The names of our "special" files */
@@ -318,6 +311,8 @@ void remove_files(const char *, const char *);
int delete_hierarchy(char *, Boolean, Boolean);
int format_cmd(char *, size_t, const char *, const char *, const char *);
+int recursive_remove(const char *, int);
+
/* pkg_io.c: Local and remote archive handling */
struct archive;
struct archive_entry;
diff --git a/pkgtools/pkg_install/files/lib/plist.c b/pkgtools/pkg_install/files/lib/plist.c
index da9853c68ab..7fffbd78d3b 100644
--- a/pkgtools/pkg_install/files/lib/plist.c
+++ b/pkgtools/pkg_install/files/lib/plist.c
@@ -1,4 +1,4 @@
-/* $NetBSD: plist.c,v 1.17.4.6 2008/08/02 20:33:50 joerg Exp $ */
+/* $NetBSD: plist.c,v 1.17.4.7 2008/08/05 22:56:24 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp";
#else
-__RCSID("$NetBSD: plist.c,v 1.17.4.6 2008/08/02 20:33:50 joerg Exp $");
+__RCSID("$NetBSD: plist.c,v 1.17.4.7 2008/08/05 22:56:24 joerg Exp $");
#endif
#endif
@@ -689,8 +689,10 @@ delete_hierarchy(char *dir, Boolean ign_err, Boolean nukedirs)
isdir(dir) ? "directory" : "file", dir);
return !ign_err;
} else if (nukedirs) {
- if (fexec_skipempty(REMOVE_CMD, "-r", ign_err ? "-f" : "", dir, NULL))
+ if (recursive_remove(dir, ign_err)) {
+ warn("Couldn't remove %s", dir);
return 1;
+ }
} else if (isdir(dir)) {
if (rmdir(dir) && !ign_err)
return 1;
diff --git a/pkgtools/pkg_install/files/lib/remove.c b/pkgtools/pkg_install/files/lib/remove.c
new file mode 100644
index 00000000000..b8c45e15c26
--- /dev/null
+++ b/pkgtools/pkg_install/files/lib/remove.c
@@ -0,0 +1,184 @@
+/* $NetBSD: remove.c,v 1.1.2.1 2008/08/05 22:56:24 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#if HAVE_ERR_H
+#include <err.h>
+#endif
+#include <errno.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lib.h"
+
+static int
+safe_fchdir(int cwd)
+{
+ int tmp_errno, rv;
+
+ tmp_errno = errno;
+ rv = fchdir(cwd);
+ errno = tmp_errno;
+
+ return rv;
+}
+
+static int
+long_remove(const char **path_ptr, int missing_ok, int *did_chdir)
+{
+ char tmp_path[PATH_MAX + 1];
+ const char *slash, *path;
+ size_t i, len;
+ int rv;
+
+ path = *path_ptr;
+ len = strlen(path);
+ *did_chdir = 0;
+
+ while (len >= PATH_MAX) {
+ slash = path;
+ for (i = PATH_MAX - 1; i > 0; --i) {
+ if (path[i] == '/')
+ break;
+ }
+ if (i == 0) {
+ errno = ENAMETOOLONG;
+ return -1; /* Assumes PATH_MAX > NAME_MAX */
+ }
+ memcpy(tmp_path, path, i);
+ tmp_path[i] = '\0';
+ if (chdir(tmp_path))
+ return -1;
+ *did_chdir = 1;
+ path += i + 1;
+ len -= i + 1;
+ }
+
+ if (remove(path) == 0 || (errno == ENOENT && missing_ok))
+ rv = 0;
+ else
+ rv = -1;
+
+ *path_ptr = path;
+
+ return rv;
+}
+
+static int
+recursive_remove_internal(const char *path, int missing_ok, int cwd)
+{
+ DIR *dir;
+ struct dirent *de;
+ const char *sub_path;
+ char *subdir;
+ int did_chdir, rv;
+
+ /*
+ * If the argument is longer than PATH_MAX, long_remove
+ * will try to shorten it using chdir. So before returning,
+ * make sure to fchdir back to the original cwd.
+ */
+ sub_path = path;
+ if (long_remove(&sub_path, missing_ok, &did_chdir) == 0)
+ rv = 0;
+ else if (errno != ENOTEMPTY) /* Other errors are terminal. */
+ rv = -1;
+ else
+ rv = 1;
+
+ if (rv != 1) {
+ if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
+ rv = -1;
+ return rv;
+ }
+
+ if ((dir = opendir(sub_path)) == NULL) {
+ if (errno == EMFILE)
+ warn("opendir failed");
+ return -1;
+ }
+
+ if (did_chdir && fchdir(cwd) == -1)
+ return -1;
+
+ rv = 0;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strcmp(de->d_name, ".") == 0)
+ continue;
+ if (strcmp(de->d_name, "..") == 0)
+ continue;
+ subdir = xasprintf("%s/%s", path, de->d_name);
+ rv = recursive_remove_internal(subdir, 1, cwd);
+ free(subdir);
+ }
+
+ closedir(dir);
+
+ safe_fchdir(cwd);
+
+ rv |= long_remove(&path, missing_ok, &did_chdir);
+
+ if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
+ rv = -1;
+
+ return rv;
+}
+
+int
+recursive_remove(const char *path, int missing_ok)
+{
+ int orig_cwd, rv;
+
+ /* First try the easy case of regular file or empty directory. */
+ if (remove(path) == 0 || (errno == ENOENT && missing_ok))
+ return 0;
+
+ /*
+ * If the path is too long, long_remove will use chdir to shorten it,
+ * so remember the current directory first.
+ */
+ if ((orig_cwd = open(".", O_RDONLY)) == -1)
+ return -1;
+
+ rv = recursive_remove_internal(path, missing_ok, orig_cwd);
+
+ close(orig_cwd);
+ return rv;
+}
diff --git a/pkgtools/pkg_install/files/lib/version.h b/pkgtools/pkg_install/files/lib/version.h
index 21aff915969..57b12159a20 100644
--- a/pkgtools/pkg_install/files/lib/version.h
+++ b/pkgtools/pkg_install/files/lib/version.h
@@ -1,4 +1,4 @@
-/* $NetBSD: version.h,v 1.102.2.12 2008/08/05 20:42:54 joerg Exp $ */
+/* $NetBSD: version.h,v 1.102.2.13 2008/08/05 22:56:24 joerg Exp $ */
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
@@ -27,6 +27,6 @@
#ifndef _INST_LIB_VERSION_H_
#define _INST_LIB_VERSION_H_
-#define PKGTOOLS_VERSION "20080805"
+#define PKGTOOLS_VERSION "20080806"
#endif /* _INST_LIB_VERSION_H_ */