Merge with 4.4-Lite version.

This commit is contained in:
mycroft 1994-09-20 00:37:13 +00:00
parent 80525d6b91
commit 9baa91f322
3 changed files with 176 additions and 105 deletions

View File

@ -1,5 +1,5 @@
# from: @(#)Makefile 5.3 (Berkeley) 12/8/90
# $Id: Makefile,v 1.5 1994/01/28 00:24:19 cgd Exp $
# from: @(#)Makefile 8.1 (Berkeley) 5/31/93
# $Id: Makefile,v 1.6 1994/09/20 00:37:13 mycroft Exp $
PROG= rm

View File

@ -1,5 +1,5 @@
.\" Copyright (c) 1990 The Regents of the University of California.
.\" All rights reserved.
.\" Copyright (c) 1990, 1993, 1994
.\" 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.
@ -32,19 +32,19 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" from: @(#)rm.1 6.9 (Berkeley) 7/27/91
.\" $Id: rm.1,v 1.4 1993/08/01 07:48:04 mycroft Exp $
.\" from: @(#)rm.1 8.2 (Berkeley) 4/18/94
.\" $Id: rm.1,v 1.5 1994/09/20 00:37:14 mycroft Exp $
.\"
.Dd July 27, 1991
.Dd April 18, 1994
.Dt RM 1
.Os
.Sh NAME
.Nm rm
.Nd Remove directory entries.
.Nd remove directory entries
.Sh SYNOPSIS
.Nm rm
.Op Fl f | Fl i
.Op Fl dRr
.Op Fl dPRr
.Ar file ...
.Sh DESCRIPTION
The
@ -78,6 +78,10 @@ The
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 0xff again, before they are deleted.
.It Fl R
Attempt to remove the file hierarchy rooted in each file argument.
The
@ -117,7 +121,16 @@ exits with a value >0.
.Sh SEE ALSO
.Xr rmdir 1 ,
.Xr unlink 2 ,
.Xr fts 3
.Xr fts 3 ,
.Xr symlink 7
.Sh BUGS
The
.Fl P
option assumes that the underlying file system is a fixed-block file
system.
UFS is a fixed-block file system, LFS is not.
In addition, only regular files are overwritten, other types of files
are not.
.Sh COMPATIBILITY
The
.Nm rm

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 1990, 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
@ -32,34 +32,37 @@
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
static char copyright[] =
"@(#) Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
/*static char sccsid[] = "from: @(#)rm.c 4.26 (Berkeley) 3/10/91";*/
static char rcsid[] = "$Id: rm.c,v 1.14 1994/03/16 17:49:40 jtc Exp $";
/*static char sccsid[] = "from: @(#)rm.c 8.5 (Berkeley) 4/18/94";*/
static char *rcsid = "$Id: rm.c,v 1.15 1994/09/20 00:37:15 mycroft Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <locale.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int check __P((char *, char *, struct stat *));
void checkdot __P((char **));
void error __P((char *, int));
void rmtree __P((char **));
void rmfile __P((char **));
void usage __P((void));
int dflag, eval, fflag, iflag, Pflag, stdin_ok;
int dflag, fflag, iflag, retval, stdin_ok;
int check __P((char *, char *, struct stat *));
void checkdot __P((char **));
void rm_file __P((char **));
void rm_overwrite __P((char *, struct stat *));
void rm_tree __P((char **));
void usage __P((void));
/*
* rm --
@ -68,18 +71,17 @@ int dflag, fflag, iflag, retval, stdin_ok;
* has two specific effects now, ignore non-existent files and force
* file removal.
*/
int
main(argc, argv)
int argc;
char **argv;
char *argv[];
{
int ch, rflag;
setlocale(LC_ALL, "");
rflag = 0;
while ((ch = getopt(argc, argv, "dfiRr")) != -1)
Pflag = rflag = 0;
while ((ch = getopt(argc, argv, "dfiPRr")) != -1)
switch(ch) {
case 'd':
dflag = 1;
@ -92,8 +94,11 @@ main(argc, argv)
fflag = 0;
iflag = 1;
break;
case 'P':
Pflag = 1;
break;
case 'R':
case 'r': /* compatibility */
case 'r': /* Compatibility. */
rflag = 1;
break;
case '?':
@ -112,21 +117,21 @@ main(argc, argv)
stdin_ok = isatty(STDIN_FILENO);
if (rflag)
rmtree(argv);
rm_tree(argv);
else
rmfile(argv);
rm_file(argv);
}
exit(retval);
exit (eval);
}
void
rmtree(argv)
rm_tree(argv)
char **argv;
{
register FTS *fts;
register FTSENT *p;
register int needstat;
FTS *fts;
FTSENT *p;
int needstat;
/*
* Remove a file hierarchy. If forcing removal (-f), or interactive
@ -142,44 +147,48 @@ rmtree(argv)
if (!(fts = fts_open(argv,
needstat ? FTS_PHYSICAL : FTS_PHYSICAL|FTS_NOSTAT,
(int (*)())NULL))) {
(void)fprintf(stderr, "rm: %s.\n", strerror(errno));
exit (1);
}
(int (*)())NULL)))
err(1, NULL);
while ((p = fts_read(fts)) != NULL) {
switch(p->fts_info) {
switch (p->fts_info) {
case FTS_DNR:
case FTS_ERR:
error(p->fts_path, errno);
if (!fflag || p->fts_errno != ENOENT) {
warnx("%s: %s",
p->fts_path, strerror(p->fts_errno));
eval = 1;
}
continue;
/*
* FTS_NS: assume that if can't stat the file, it can't be
* unlinked.
*/
case FTS_ERR:
errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
case FTS_NS:
/*
* FTS_NS: assume that if can't stat the file, it
* can't be unlinked.
*/
if (!needstat)
break;
if (!fflag || errno != ENOENT)
error(p->fts_path, errno);
if (!fflag || p->fts_errno != ENOENT) {
warnx("%s: %s",
p->fts_path, strerror(p->fts_errno));
eval = 1;
}
continue;
/* Pre-order: give user chance to skip. */
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;
/* Post-order: see if user skipped. */
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))
if (!fflag &&
!check(p->fts_path, p->fts_accpath, p->fts_statp))
continue;
}
@ -189,68 +198,125 @@ rmtree(argv)
* message unless the remove fails.
*/
if (p->fts_info == FTS_DP || p->fts_info == FTS_DNR) {
if (!rmdir(p->fts_accpath) || fflag && errno == ENOENT)
if (!rmdir(p->fts_accpath) || fflag && errno == ENOENT)
continue;
} else {
if (Pflag)
rm_overwrite(p->fts_accpath, NULL);
if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
continue;
}
error(p->fts_path, errno);
warn("%s", p->fts_path);
eval = 1;
}
if (errno)
err(1, "fts_read");
}
void
rmfile(argv)
rm_file(argv)
char **argv;
{
register char *f;
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) {
/* If the file does not exist:
* If the -f option was not specified, write a diagnostic
* to the standard error...
*/
/* Assume if can't stat the file, can't unlink it. */
if (lstat(f, &sb)) {
if (!fflag || errno != ENOENT) {
error(f, errno);
warn("%s", f);
eval = 1;
}
continue;
}
/* If the file is of type directory and neither the -r or -R
* (or -d) options are specified, write a diagnostic to the
* standard error...
*/
if (S_ISDIR(sb.st_mode) && !dflag) {
error (f, EISDIR);
warnx("%s: is a directory", f);
eval = 1;
continue;
}
if (!fflag && !check(f, f, &sb)) {
if (!fflag && !check(f, f, &sb))
continue;
if (S_ISDIR(sb.st_mode))
rval = rmdir(f);
else {
if (Pflag)
rm_overwrite(f, &sb);
rval = unlink(f);
}
/*
* rmdir() directories, unlink() files...
*/
if ((S_ISDIR(sb.st_mode) ? rmdir(f) : unlink(f))) {
error(f, errno);
if (rval && (!fflag || errno != ENOENT)) {
warn("%s", f);
eval = 1;
}
}
}
/*
* rm_overwrite --
* Overwrite the file 3 times with varying bit patterns.
*
* XXX
* This is a cheap way to *really* delete files. Note that 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.
*/
void
rm_overwrite(file, sbp)
char *file;
struct stat *sbp;
{
struct stat sb;
off_t len;
int fd, wlen;
char buf[8 * 1024];
fd = -1;
if (sbp == NULL) {
if (lstat(file, &sb))
goto err;
sbp = &sb;
}
if (!S_ISREG(sbp->st_mode))
return;
if ((fd = open(file, O_WRONLY, 0)) == -1)
goto err;
#define PASS(byte) { \
memset(buf, byte, sizeof(buf)); \
for (len = sbp->st_size; len > 0; len -= wlen) { \
wlen = len < sizeof(buf) ? len : sizeof(buf); \
if (write(fd, buf, wlen) != wlen) \
goto err; \
} \
}
PASS(0xff);
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
goto err;
PASS(0x00);
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
goto err;
PASS(0xff);
if (!fsync(fd) && !close(fd))
return;
err: eval = 1;
warn("%s", file);
}
int
check(path, name, sp)
char *path, *name;
struct stat *sp;
{
register int first, ch;
char modep[15], *user_from_uid(), *group_from_gid();
int ch, first;
char modep[15];
/* Check -i first. */
if (iflag)
@ -259,10 +325,11 @@ check(path, name, sp)
/*
* 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.
* 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))
return(1);
return (1);
strmode(sp->st_mode, modep);
(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
modep + 1, modep[9] == ' ' ? "" : " ",
@ -274,7 +341,7 @@ check(path, name, sp)
first = ch = getchar();
while (ch != '\n' && ch != EOF)
ch = getchar();
return(first == 'y' || first == 'Y');
return (first == 'y' || first == 'Y');
}
#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || (a)[1] == '.' && !(a)[2]))
@ -282,21 +349,20 @@ void
checkdot(argv)
char **argv;
{
register char *p, **t, **save;
char *p, **save, **t;
int complained;
complained = 0;
for (t = argv; *t;) {
if ((p = rindex(*t, '/')) != NULL)
if ((p = strrchr(*t, '/')) != NULL)
++p;
else
p = *t;
if (ISDOT(p)) {
if (!complained++)
(void)fprintf(stderr,
"rm: \".\" and \"..\" may not be removed.\n");
retval = 1;
for (save = t; t[0] = t[1]; ++t)
warnx("\".\" and \"..\" may not be removed");
eval = 1;
for (save = t; (t[0] = t[1]) != NULL; ++t)
continue;
t = save;
} else
@ -304,18 +370,10 @@ checkdot(argv)
}
}
void
error(name, val)
char *name;
int val;
{
(void)fprintf(stderr, "rm: %s: %s.\n", name, strerror(val));
retval = 1;
}
void
usage()
{
(void)fprintf(stderr, "usage: rm [-dfiRr] file ...\n");
(void)fprintf(stderr, "usage: rm [-dfiPRr] file ...\n");
exit(1);
}