diff --git a/bin/Makefile b/bin/Makefile index 98c877ff5..4444f2aec 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -2,6 +2,6 @@ .include -SUBDIR= mkdir +SUBDIR= mkdir rm rmdir .include diff --git a/bin/rm/Makefile b/bin/rm/Makefile new file mode 100644 index 000000000..85e9917cd --- /dev/null +++ b/bin/rm/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.9 1997/07/20 22:37:50 christos Exp $ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +PROG= rm + +.include diff --git a/bin/rm/rm.1 b/bin/rm/rm.1 new file mode 100644 index 000000000..ac37b896b --- /dev/null +++ b/bin/rm/rm.1 @@ -0,0 +1,207 @@ +.\" $NetBSD: rm.1,v 1.24 2006/09/02 23:28:32 wiz Exp $ +.\" +.\" Copyright (c) 1990, 1993, 1994, 2003 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" 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. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" @(#)rm.1 8.5 (Berkeley) 12/5/94 +.\" +.Dd August 25, 2006 +.Dt RM 1 +.Os +.Sh NAME +.Nm rm +.Nd remove directory entries +.Sh SYNOPSIS +.Nm +.Op Fl f | Fl i +.Op Fl dPRrvW +.Ar +.Sh DESCRIPTION +The +.Nm +utility attempts to remove the non-directory type files specified on the +command line. +If the permissions of the file do not permit writing, and the standard +input device is a terminal, the user is prompted (on the standard error +output) for confirmation. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl d +Attempt to remove directories as well as other types of files. +.It Fl f +Attempt to remove the files without prompting for confirmation, +regardless of the file's permissions. +If the file does not exist, do not display a diagnostic message or modify +the exit status to reflect an error. +The +.Fl f +option overrides any previous +.Fl i +options. +.It Fl i +Request confirmation before attempting to remove each file, regardless of +the file's permissions, or whether or not the standard input device is a +terminal. +The +.Fl i +option overrides any previous +.Fl f +options. +.It Fl P +Overwrite regular files before deleting them. +Files are overwritten three times, first with the byte pattern 0xff, +then 0x00, and then with random data, before they are deleted. +Some care is taken to ensure that the data are actually written to +disk, but this cannot be guaranteed, even on traditional filesystems; +on log-structured filesystems or if any block-journaling scheme is +in use, this option is completely useless. +If the file cannot be +overwritten, it will not be removed. +.It Fl R +Attempt to remove the file hierarchy rooted in each file argument. +The +.Fl R +option implies the +.Fl d +option. +If the +.Fl i +option is specified, the user is prompted for confirmation before +each directory's contents are processed (as well as before the attempt +is made to remove the directory). +If the user does not respond affirmatively, the file hierarchy rooted in +that directory is skipped. +.Pp +.It Fl r +Equivalent to +.Fl R . +.It Fl v +Cause +.Nm +to be verbose, showing files as they are processed. +.It Fl W +Attempts to undelete the named files. +Currently, this option can only be used to recover +files covered by whiteouts. +.El +.Pp +The +.Nm +utility removes symbolic links, not the files referenced by the links. +.Pp +It is an error to attempt to remove the files ``.'' and ``..''. +.Sh EXIT STATUS +The +.Nm +utility exits 0 if all of the named files or file hierarchies were removed, +or if the +.Fl f +option was specified and all of the existing files or file hierarchies were +removed. +If an error occurs, +.Nm +exits with a value \*[Gt]0. +.Sh EXAMPLES +.Nm +uses +.Xr getopt 3 +standard argument processing. +Removing filenames that begin with a dash +.Pq e.g., Ar -file +in the current directory which might otherwise be taken as option flags to +.Nm +can be accomplished as follows: +.Pp +.Ic "rm -- -file" +.Pp +or +.Pp +.Ic "rm ./-file" +.Sh SEE ALSO +.Xr rmdir 1 , +.Xr undelete 2 , +.Xr unlink 2 , +.Xr fts 3 , +.Xr getopt 3 , +.Xr symlink 7 +.Sh BUGS +The +.Fl P +option assumes that the underlying file system is a fixed-block file +system. +FFS is a fixed-block file system, LFS is not. +In addition, only regular files are overwritten, other types of files +are not. +Recent research indicates that as many as 35 overwrite passes with +carefully chosen data patterns may be necessary to actually prevent +recovery of data from a magnetic disk. +Thus the +.Fl P +option is likely both insufficient for its design purpose and far +too costly for default operation. +However, it will at least prevent the recovery of data from FFS +volumes with +.Xr fsdb 8 . +.Sh COMPATIBILITY +The +.Nm +utility differs from historical implementations in that the +.Fl f +option only masks attempts to remove non-existent files instead of +masking a large variety of errors. +.Pp +Also, historical +.Bx +implementations prompted on the standard output, +not the standard error output. +.Sh STANDARDS +The +.Nm +utility is expected to be +.St -p1003.2 +compatible. +The +.Fl v +option is an extension. +.Pp +The +.Fl P +option attempts to conform to U.S. DoD 5220-22.M, "National Industrial +Security Program Operating Manual" ("NISPOM") as updated by Change +2 and the July 23, 2003 "Clearing \*[Am] Sanitization Matrix". +However, unlike earlier revisions of NISPOM, the 2003 matrix imposes +requirements which make it clear that the standard does not and +can not apply to the erasure of individual files, in particular +requirements relating to spare sector management for an entire +magnetic disk. +.Em Because these requirements are not met, the +.Fl P +.Em option does not conform to the standard . diff --git a/bin/rm/rm.c b/bin/rm/rm.c new file mode 100644 index 000000000..ddf85dc71 --- /dev/null +++ b/bin/rm/rm.c @@ -0,0 +1,605 @@ +/* $NetBSD: rm.c,v 1.50 2011/08/29 14:48:46 joerg Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994, 2003 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rm.c 8.8 (Berkeley) 4/27/95"; +#else +__RCSID("$NetBSD: rm.c,v 1.50 2011/08/29 14:48:46 joerg Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag; + +static int check(char *, char *, struct stat *); +static void checkdot(char **); +static void rm_file(char **); +static int rm_overwrite(char *, struct stat *); +static void rm_tree(char **); +__dead static void usage(void); + +#ifdef __minix +# ifndef O_SYNC +# define O_SYNC 0 +# endif +# ifndef O_RSYNC +# define O_RSYNC 0 +# endif +#endif + +/* + * For the sake of the `-f' flag, check whether an error number indicates the + * failure of an operation due to an non-existent file, either per se (ENOENT) + * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR). + */ +#define NONEXISTENT(x) \ + ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR) + +/* + * rm -- + * This rm is different from historic rm's, but is expected to match + * POSIX 1003.2 behavior. The most visible difference is that -f + * has two specific effects now, ignore non-existent files and force + * file removal. + */ +int +main(int argc, char *argv[]) +{ + int ch, rflag; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + Pflag = rflag = 0; + while ((ch = getopt(argc, argv, "dfiPRrvW")) != -1) + switch (ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + fflag = 0; + iflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + case 'r': /* Compatibility. */ + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'W': + Wflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + if (fflag) + return 0; + usage(); + } + + checkdot(argv); + + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (rflag) + rm_tree(argv); + else + rm_file(argv); + } + + exit(eval); + /* NOTREACHED */ +} + +static void +rm_tree(char **argv) +{ + FTS *fts; + FTSENT *p; + int flags, needstat, rval; + + /* + * Remove a file hierarchy. If forcing removal (-f), or interactive + * (-i) or can't ask anyway (stdin_ok), don't stat the file. + */ + needstat = !fflag && !iflag && stdin_ok; + + /* + * If the -i option is specified, the user can skip on the pre-order + * visit. The fts_number field flags skipped directories. + */ +#define SKIPPED 1 + + flags = FTS_PHYSICAL; + if (!needstat) + flags |= FTS_NOSTAT; +#ifndef __minix + if (Wflag) + flags |= FTS_WHITEOUT; +#endif + if ((fts = fts_open(argv, flags, NULL)) == NULL) + err(1, "fts_open failed"); + while ((p = fts_read(fts)) != NULL) { + + switch (p->fts_info) { + case FTS_DNR: + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", p->fts_path, + strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_ERR: + errx(EXIT_FAILURE, "%s: %s", p->fts_path, + strerror(p->fts_errno)); + /* NOTREACHED */ + case FTS_NS: + /* + * FTS_NS: assume that if can't stat the file, it + * can't be unlinked. + */ + if (fflag && NONEXISTENT(p->fts_errno)) + continue; + if (needstat) { + warnx("%s: %s", p->fts_path, + strerror(p->fts_errno)); + eval = 1; + continue; + } + break; + case FTS_D: + /* Pre-order: give user chance to skip. */ + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) { + (void)fts_set(fts, p, FTS_SKIP); + p->fts_number = SKIPPED; + } + continue; + case FTS_DP: + /* Post-order: see if user skipped. */ + if (p->fts_number == SKIPPED) + continue; + break; + default: + if (!fflag && + !check(p->fts_path, p->fts_accpath, p->fts_statp)) + continue; + } + + rval = 0; + /* + * If we can't read or search the directory, may still be + * able to remove it. Don't print out the un{read,search}able + * message unless the remove fails. + */ + switch (p->fts_info) { + case FTS_DP: + case FTS_DNR: + rval = rmdir(p->fts_accpath); + if (rval != 0 && fflag && errno == ENOENT) + continue; + break; + +#ifndef __minix + case FTS_W: + rval = undelete(p->fts_accpath); + if (rval != 0 && fflag && errno == ENOENT) + continue; + break; +#endif + + default: + if (Pflag) { + if (rm_overwrite(p->fts_accpath, NULL)) + continue; + } + rval = unlink(p->fts_accpath); + if (rval != 0 && fflag && NONEXISTENT(errno)) + continue; + break; + } + if (rval != 0) { + warn("%s", p->fts_path); + eval = 1; + } else if (vflag) + (void)printf("%s\n", p->fts_path); + } + if (errno) + err(1, "fts_read"); + fts_close(fts); +} + +static void +rm_file(char **argv) +{ + struct stat sb; + int rval; + char *f; + + /* + * Remove a file. POSIX 1003.2 states that, by default, attempting + * to remove a directory is an error, so must always stat the file. + */ + while ((f = *argv++) != NULL) { + /* Assume if can't stat the file, can't unlink it. */ + if (lstat(f, &sb)) { + if (Wflag) { +#ifdef __minix + sb.st_mode = S_IWUSR|S_IRUSR; +#else + sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; +#endif + } else { + if (!fflag || !NONEXISTENT(errno)) { + warn("%s", f); + eval = 1; + } + continue; + } + } else if (Wflag) { + warnx("%s: %s", f, strerror(EEXIST)); + eval = 1; + continue; + } + + if (S_ISDIR(sb.st_mode) && !dflag) { + warnx("%s: is a directory", f); + eval = 1; + continue; + } +#ifndef __minix + if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) +#else + if (!fflag && !check(f, f, &sb)) +#endif + continue; +#ifndef __minix + if (S_ISWHT(sb.st_mode)) + rval = undelete(f); + else +#endif + if (S_ISDIR(sb.st_mode)) + rval = rmdir(f); + else { + if (Pflag) { + if (rm_overwrite(f, &sb)) + continue; + } + rval = unlink(f); + } + if (rval && (!fflag || !NONEXISTENT(errno))) { + warn("%s", f); + eval = 1; + } + if (vflag && rval == 0) + (void)printf("%s\n", f); + } +} + +/* + * rm_overwrite -- + * Overwrite the file 3 times with varying bit patterns. + * + * This is an expensive way to keep people from recovering files from your + * non-snapshotted FFS filesystems using fsdb(8). Really. No more. Only + * regular files are deleted, directories (and therefore names) will remain. + * Also, this assumes a fixed-block file system (like FFS, or a V7 or a + * System V file system). In a logging file system, you'll have to have + * kernel support. + * + * A note on standards: U.S. DoD 5220.22-M "National Industrial Security + * Program Operating Manual" ("NISPOM") is often cited as a reference + * for clearing and sanitizing magnetic media. In fact, a matrix of + * "clearing" and "sanitization" methods for various media was given in + * Chapter 8 of the original 1995 version of NISPOM. However, that + * matrix was *removed from the document* when Chapter 8 was rewritten + * in Change 2 to the document in 2001. Recently, the Defense Security + * Service has made a revised clearing and sanitization matrix available + * in Microsoft Word format on the DSS web site. The standardization + * status of this matrix is unclear. Furthermore, one must be very + * careful when referring to this matrix: it is intended for the "clearing" + * prior to reuse or "sanitization" prior to disposal of *entire media*, + * not individual files and the only non-physically-destructive method of + * "sanitization" that is permitted for magnetic disks of any kind is + * specifically noted to be prohibited for media that have contained + * Top Secret data. + * + * It is impossible to actually conform to the exact procedure given in + * the matrix if one is overwriting a file, not an entire disk, because + * the procedure requires examination and comparison of the disk's defect + * lists. Any program that claims to securely erase *files* while + * conforming to the standard, then, is not correct. We do as much of + * what the standard requires as can actually be done when erasing a + * file, rather than an entire disk; but that does not make us conformant. + * + * Furthermore, the presence of track caches, disk and controller write + * caches, and so forth make it extremely difficult to ensure that data + * have actually been written to the disk, particularly when one tries + * to repeatedly overwrite the same sectors in quick succession. We call + * fsync(), but controllers with nonvolatile cache, as well as IDE disks + * that just plain lie about the stable storage of data, will defeat this. + * + * Finally, widely respected research suggests that the given procedure + * is nowhere near sufficient to prevent the recovery of data using special + * forensic equipment and techniques that are well-known. This is + * presumably one reason that the matrix requires physical media destruction, + * rather than any technique of the sort attempted here, for secret data. + * + * Caveat Emptor. + * + * rm_overwrite will return 0 on success. + */ + +static int +rm_overwrite(char *file, struct stat *sbp) +{ + struct stat sb; + int fd, randint; + char randchar; + + fd = -1; + if (sbp == NULL) { + if (lstat(file, &sb)) + goto err; + sbp = &sb; + } + if (!S_ISREG(sbp->st_mode)) + return 0; + + /* flags to try to defeat hidden caching by forcing seeks */ + if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC, 0)) == -1) + goto err; + +#define RAND_BYTES 1 +#define THIS_BYTE 0 + +#define WRITE_PASS(mode, byte) do { \ + off_t len; \ + size_t wlen, i; \ + char buf[8 * 1024]; \ + \ + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ + goto err; \ + \ + if (mode == THIS_BYTE) \ + memset(buf, byte, sizeof(buf)); \ + for (len = sbp->st_size; len > 0; len -= wlen) { \ + if (mode == RAND_BYTES) { \ + for (i = 0; i < sizeof(buf); \ + i+= sizeof(u_int32_t)) \ + *(int *)(buf + i) = arc4random(); \ + } \ + wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ + if ((size_t)write(fd, buf, wlen) != wlen) \ + goto err; \ + } \ + sync(); /* another poke at hidden caches */ \ +} while (/* CONSTCOND */ 0) + +#define READ_PASS(byte) do { \ + off_t len; \ + size_t rlen; \ + char pattern[8 * 1024]; \ + char buf[8 * 1024]; \ + \ + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \ + goto err; \ + \ + memset(pattern, byte, sizeof(pattern)); \ + for(len = sbp->st_size; len > 0; len -= rlen) { \ + rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \ + if((size_t)read(fd, buf, rlen) != rlen) \ + goto err; \ + if(memcmp(buf, pattern, rlen)) \ + goto err; \ + } \ + sync(); /* another poke at hidden caches */ \ +} while (/* CONSTCOND */ 0) + + /* + * DSS sanitization matrix "clear" for magnetic disks: + * option 'c' "Overwrite all addressable locations with a single + * character." + */ + randint = arc4random(); + randchar = *(char *)&randint; + WRITE_PASS(THIS_BYTE, randchar); + + /* + * DSS sanitization matrix "sanitize" for magnetic disks: + * option 'd', sub 2 "Overwrite all addressable locations with a + * character, then its complement. Verify "complement" character + * was written successfully to all addressable locations, then + * overwrite all addressable locations with random characters; or + * verify third overwrite of random characters." The rest of the + * text in d-sub-2 specifies requirements for overwriting spared + * sectors; we cannot conform to it when erasing only a file, thus + * we do not conform to the standard. + */ + + /* 1. "a character" */ + WRITE_PASS(THIS_BYTE, 0xff); + + /* 2. "its complement" */ + WRITE_PASS(THIS_BYTE, 0x00); + + /* 3. "Verify 'complement' character" */ + READ_PASS(0x00); + + /* 4. "overwrite all addressable locations with random characters" */ + + WRITE_PASS(RAND_BYTES, 0x00); + + /* + * As the file might be huge, and we note that this revision of + * the matrix says "random characters", not "a random character" + * as the original did, we do not verify the random-character + * write; the "or" in the standard allows this. + */ + + if (close(fd) == -1) { + fd = -1; + goto err; + } + + return 0; + +err: eval = 1; + warn("%s", file); + if (fd != -1) + close(fd); + return 1; +} + +static int +check(char *path, char *name, struct stat *sp) +{ + int ch, first; + char modep[15]; + + /* Check -i first. */ + if (iflag) + (void)fprintf(stderr, "remove '%s'? ", path); + else { + /* + * If it's not a symbolic link and it's unwritable and we're + * talking to a terminal, ask. Symbolic links are excluded + * because their permissions are meaningless. Check stdin_ok + * first because we may not have stat'ed the file. + */ + if (!stdin_ok || S_ISLNK(sp->st_mode) || + !(access(name, W_OK) && (errno != ETXTBSY))) + return (1); + strmode(sp->st_mode, modep); + if (Pflag) { + warnx( + "%s: -P was specified but file could not" + " be overwritten", path); + return 0; + } + (void)fprintf(stderr, "override %s%s%s:%s for '%s'? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sp->st_uid, 0), + group_from_gid(sp->st_gid, 0), path); + } + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +/* + * POSIX.2 requires that if "." or ".." are specified as the basename + * portion of an operand, a diagnostic message be written to standard + * error and nothing more be done with such operands. + * + * Since POSIX.2 defines basename as the final portion of a path after + * trailing slashes have been removed, we'll remove them here. + */ +#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) +static void +checkdot(char **argv) +{ + char *p, **save, **t; + int complained; + + complained = 0; + for (t = argv; *t;) { + /* strip trailing slashes */ + p = strrchr(*t, '\0'); + while (--p > *t && *p == '/') + *p = '\0'; + + /* extract basename */ + if ((p = strrchr(*t, '/')) != NULL) + ++p; + else + p = *t; + + if (ISDOT(p)) { + if (!complained++) + warnx("\".\" and \"..\" may not be removed"); + eval = 1; + for (save = t; (t[0] = t[1]) != NULL; ++t) + continue; + t = save; + } else + ++t; + } +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvW] file ...\n", + getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/bin/rmdir/Makefile b/bin/rmdir/Makefile new file mode 100644 index 000000000..73dcabea2 --- /dev/null +++ b/bin/rmdir/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.8 1997/07/20 22:37:52 christos Exp $ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +PROG= rmdir + +.include diff --git a/bin/rmdir/rmdir.1 b/bin/rmdir/rmdir.1 new file mode 100644 index 000000000..73fc2c492 --- /dev/null +++ b/bin/rmdir/rmdir.1 @@ -0,0 +1,90 @@ +.\" $NetBSD: rmdir.1,v 1.15 2003/08/07 09:05:29 agc Exp $ +.\" +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" 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. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93 +.\" +.Dd May 31, 1993 +.Dt RMDIR 1 +.Os +.Sh NAME +.Nm rmdir +.Nd remove directories +.Sh SYNOPSIS +.Nm +.Op Fl p +.Ar directory ... +.Sh DESCRIPTION +The rmdir utility removes the directory entry specified by +each +.Ar directory +argument, provided it is empty. +.Pp +Arguments are processed in the order given. +In order to remove both a parent directory and a subdirectory +of that parent, the subdirectory +must be specified first so the parent directory +is empty when +.Nm +tries to remove it. +.Pp +The following option is available: +.Bl -tag -width Ds +.It Fl p +Each +.Ar directory +argument is treated as a pathname of which all +components will be removed, if they are empty, +starting with the last most component. +(See +.Xr rm 1 +for fully non-discriminant recursive removal.) +.El +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Bl -tag -width Ds +.It Li \&0 +Each directory entry specified by a dir operand +referred to an empty directory and was removed +successfully. +.It Li \&\*[Gt]\&0 +An error occurred. +.El +.Sh SEE ALSO +.Xr rm 1 +.Sh STANDARDS +The +.Nm +utility is expected to be +.St -p1003.2 +compatible. diff --git a/bin/rmdir/rmdir.c b/bin/rmdir/rmdir.c new file mode 100644 index 000000000..03261ced5 --- /dev/null +++ b/bin/rmdir/rmdir.c @@ -0,0 +1,121 @@ +/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rmdir.c 8.3 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $"); +#endif +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include + +static int rm_path(char *); +__dead static void usage(void); + +int +main(int argc, char *argv[]) +{ + int ch, errors, pflag; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + pflag = 0; + while ((ch = getopt(argc, argv, "p")) != -1) + switch(ch) { + case 'p': + pflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + for (errors = 0; *argv; argv++) { + /* We rely on the kernel to ignore trailing '/' characters. */ + if (rmdir(*argv) < 0) { + warn("%s", *argv); + errors = 1; + } else if (pflag) + errors |= rm_path(*argv); + } + + exit(errors); + /* NOTREACHED */ +} + +static int +rm_path(char *path) +{ + char *p; + + while ((p = strrchr(path, '/')) != NULL) { + *p = 0; + if (p[1] == 0) + /* Ignore trailing '/' on deleted name */ + continue; + + if (rmdir(path) < 0) { + warn("%s", path); + return (1); + } + } + + return (0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/commands/Makefile b/commands/Makefile index 78387078e..4283f7f47 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -23,7 +23,7 @@ SUBDIR= aal add_route arp ash at autil awk \ ping postinstall poweroff pr prep printf printroot \ profile progressbar proto pr_routes ps pwd pwdauth \ ramdisk rarpd rawspeed rcp rdate readall readclock \ - reboot remsync rev rget rlogin rlogind rmdir \ + reboot remsync rev rget rlogin rlogind \ rotate rsh rshd sed service setup shar acksize \ sleep slip sort spell split srccrc ackstrip \ stty su sum svclog swifi sync synctree sysenv \ diff --git a/commands/cp/Makefile b/commands/cp/Makefile index f895a942b..e9bc2bf39 100644 --- a/commands/cp/Makefile +++ b/commands/cp/Makefile @@ -2,7 +2,6 @@ PROG= cp BINDIR= /bin MAN= -LINKS+= ${BINDIR}/cp ${BINDIR}/rm LINKS+= ${BINDIR}/cp ${BINDIR}/mv LINKS+= ${BINDIR}/cp ${BINDIR}/ln LINKS+= ${BINDIR}/cp ${BINDIR}/clone diff --git a/commands/rmdir/Makefile b/commands/rmdir/Makefile deleted file mode 100644 index 6727bd9fb..000000000 --- a/commands/rmdir/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= rmdir -MAN= - -.include diff --git a/commands/rmdir/rmdir.c b/commands/rmdir/rmdir.c deleted file mode 100644 index 6d4ba833d..000000000 --- a/commands/rmdir/rmdir.c +++ /dev/null @@ -1,46 +0,0 @@ -/* rmdir - remove directory. Author: Kees J. Bot - */ -#define nil 0 -#include -#include -#include -#include -#include -#include - -void tell(char *what) -{ - write(2, what, strlen(what)); -} - -void report(char *label) -{ - char *err= strerror(errno); - - tell("rmdir: "); - tell(label); - tell(": "); - tell(err); - tell("\n"); -} - -int main(int argc, char **argv) -{ - int i, ex= 0; - - if (argc < 2) { - tell("Usage: rmdir directory ...\n"); - exit(1); - } - - i=1; - do { - if (rmdir(argv[i]) < 0) { - report(argv[i]); - ex= 1; - } - } while (++i < argc); - - exit(ex); -} -/* Kees J. Bot 27-12-90. */ diff --git a/docs/UPDATING b/docs/UPDATING index 1c656ab38..8b4da10c5 100644 --- a/docs/UPDATING +++ b/docs/UPDATING @@ -1,3 +1,14 @@ +20120112: + Replace our native rm and rmdir with NetBSD version. + + As our native rm is a hard link to cp, simply overwriting rm with + the new version would cause mv, cp, ln, etc to stop working. + + Do this BEFORE a 'make world': + # rm /bin/rm + # cp /bin/cp /bin/rm + Then 'make clean world' as usual. + 20111222: This update requires /etc/fstab having the new format. diff --git a/etc/usr/rc b/etc/usr/rc index d09af1644..71042a13c 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -113,7 +113,7 @@ start) test -f /etc/font && loadfont /etc/font /dev/null 2>&1"); + system("rm -rf DIR_046 > /dev/null 2>&1"); system("mkdir DIR_046"); system("chmod u=rwx,g=,o= DIR_046"); /* Only access for superuser */ system("chgrp "IMAGINARY_GID_STR" DIR_046"); /* Make imaginary group @@ -275,7 +275,7 @@ void group_test() { system("chmod g+r DIR_046"); if(dotest(group_test_5) == 0) e(18); } - system("rm -r DIR_046"); + system("rm -rf DIR_046"); free(grouplist); } diff --git a/tools/nbsd_ports b/tools/nbsd_ports index ea4d61148..920598491 100644 --- a/tools/nbsd_ports +++ b/tools/nbsd_ports @@ -17,6 +17,8 @@ common/lib/libutil src/common/lib/libutil lib/libbz2 src/lib/libbz2 nbsd_include src/include bin/mkdir src/bin/mkdir +bin/rm src/bin/rm +bin/rmdir src/bin/rmdir usr.sbin/fsck src/usr.sbin/fsck usr.bin/chpass src/usr.bin/chpass usr.bin/m4 src/usr.bin/m4