From 149956fff8e877f3b47f8accc8a38c7e57d83425 Mon Sep 17 00:00:00 2001 From: joerg Date: Tue, 5 Aug 2008 22:56:24 +0000 Subject: pkg_install-20080806: Provide and use internal implementation of rm -rf. --- pkgtools/pkg_install/files/add/perform.c | 13 +- pkgtools/pkg_install/files/delete/perform.c | 8 +- pkgtools/pkg_install/files/lib/Makefile.in | 4 +- pkgtools/pkg_install/files/lib/lib.h | 25 ++-- pkgtools/pkg_install/files/lib/plist.c | 8 +- pkgtools/pkg_install/files/lib/remove.c | 184 ++++++++++++++++++++++++++++ pkgtools/pkg_install/files/lib/version.h | 4 +- 7 files changed, 215 insertions(+), 31 deletions(-) create mode 100644 pkgtools/pkg_install/files/lib/remove.c 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 #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 @@ -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 . + * 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 +#endif +#if HAVE_ERR_H +#include +#endif +#include +#if HAVE_FCNTL_H +#include +#endif +#include +#include +#include +#include +#include + +#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_ */ -- cgit v1.2.3