2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 static const char copyright
[] =
33 "@(#) Copyright (c) 1990, 1993, 1994\n\
34 The Regents of the University of California. All rights reserved.\n";
38 static char sccsid
[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94";
40 #include <sys/cdefs.h>
41 //__FBSDID("$FreeBSD: src/bin/rm/rm.c,v 1.47 2004/04/06 20:06:50 markm Exp $");
46 # include <sys/param.h>
47 # include <sys/mount.h>
64 # include "mscfakes.h"
66 #if defined(__OS2__) || defined(_MSC_VER)
70 #include "kmkbuiltin.h"
71 #include "kbuild_protection.h"
73 #if defined(__EMX__) || defined(_MSC_VER)
74 # define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
75 # define HAVE_DOS_PATHS 1
76 # define DEFAULT_PROTECTION_DEPTH 1
78 # define IS_SLASH(ch) ( (ch) == '/' )
79 # undef HAVE_DOS_PATHS
80 # define DEFAULT_PROTECTION_DEPTH 2
90 #define undelete(s) (-1)
93 extern void bsd_strmode(mode_t mode
, char *p
);
95 static int dflag
, eval
, fflag
, iflag
, Pflag
, vflag
, Wflag
, stdin_ok
;
99 static KBUILDPROTECTION g_ProtData
;
101 static struct option long_options
[] =
103 { "help", no_argument
, 0, 261 },
104 { "version", no_argument
, 0, 262 },
105 { "disable-protection", no_argument
, 0, 263 },
106 { "enable-protection", no_argument
, 0, 264 },
107 { "enable-full-protection", no_argument
, 0, 265 },
108 { "disable-full-protection", no_argument
, 0, 266 },
109 { "protection-depth", required_argument
, 0, 267 },
114 static int check(char *, char *, struct stat
*);
115 static void checkdot(char **);
116 static int rm_file(char **);
117 static int rm_overwrite(char *, struct stat
*);
118 static int rm_tree(char **);
119 static int count_path_components(const char *);
120 static int usage(FILE *);
126 * This rm is different from historic rm's, but is expected to match
127 * POSIX 1003.2 behavior. The most visible difference is that -f
128 * has two specific effects now, ignore non-existent files and force
132 kmk_builtin_rm(int argc
, char *argv
[], char **envp
)
136 /* reinitialize globals */
138 dflag
= eval
= fflag
= iflag
= Pflag
= vflag
= Wflag
= stdin_ok
= 0;
140 kBuildProtectionInit(&g_ProtData
);
142 /* kmk: reset getopt and set program name. */
143 g_progname
= argv
[0];
147 optind
= 0; /* init */
150 while ((ch
= getopt_long(argc
, argv
, "dfiPRvW", long_options
, NULL
)) != -1)
168 case 'r': /* Compatibility. */
181 kBuildProtectionTerm(&g_ProtData
);
185 kBuildProtectionTerm(&g_ProtData
);
186 return kbuild_version(argv
[0]);
188 kBuildProtectionDisable(&g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
);
191 kBuildProtectionEnable(&g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
);
194 kBuildProtectionEnable(&g_ProtData
, KBUILDPROTECTIONTYPE_FULL
);
197 kBuildProtectionDisable(&g_ProtData
, KBUILDPROTECTIONTYPE_FULL
);
200 if (kBuildProtectionSetDepth(&g_ProtData
, optarg
)) {
201 kBuildProtectionTerm(&g_ProtData
);
207 kBuildProtectionTerm(&g_ProtData
);
208 return usage(stderr
);
214 kBuildProtectionTerm(&g_ProtData
);
217 return usage(stderr
);
220 if (!kBuildProtectionScanEnv(&g_ProtData
, envp
, "KMK_RM_")) {
225 stdin_ok
= isatty(STDIN_FILENO
);
227 eval
|= rm_tree(argv
);
229 eval
|= rm_file(argv
);
235 kBuildProtectionTerm(&g_ProtData
);
249 * Check up front before anything is deleted. This will not catch
250 * everything, but we'll check the individual items later.
253 for (i
= 0; argv
[i
]; i
++) {
254 if (kBuildProtectionEnforce(&g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
, argv
[i
])) {
260 * Remove a file hierarchy. If forcing removal (-f), or interactive
261 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
263 needstat
= !uid
|| (!fflag
&& !iflag
&& stdin_ok
);
266 * If the -i option is specified, the user can skip on the pre-order
267 * visit. The fts_number field flags skipped directories.
271 flags
= FTS_PHYSICAL
;
276 flags
|= FTS_WHITEOUT
;
278 if (!(fts
= fts_open(argv
, flags
, NULL
))) {
279 return err(1, "fts_open");
281 while ((p
= fts_read(fts
)) != NULL
) {
282 switch (p
->fts_info
) {
284 if (!fflag
|| p
->fts_errno
!= ENOENT
) {
285 fprintf(stderr
, "%s: %s: %s\n",
286 argv0
, p
->fts_path
, strerror(p
->fts_errno
));
292 return errx(1, "%s: %s", p
->fts_path
, strerror(p
->fts_errno
));
295 * Assume that since fts_read() couldn't stat the
296 * file, it can't be unlinked.
300 if (!fflag
|| p
->fts_errno
!= ENOENT
) {
301 fprintf(stderr
, "%s: %s: %s\n",
302 argv0
, p
->fts_path
, strerror(p
->fts_errno
));
307 /* Pre-order: give user chance to skip. */
308 if (!fflag
&& !check(p
->fts_path
, p
->fts_accpath
,
310 (void)fts_set(fts
, p
, FTS_SKIP
);
311 p
->fts_number
= SKIPPED
;
315 (p
->fts_statp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
316 !(p
->fts_statp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)) &&
317 chflags(p
->fts_accpath
,
318 p
->fts_statp
->st_flags
&= ~(UF_APPEND
|UF_IMMUTABLE
)) < 0)
323 /* Post-order: see if user skipped. */
324 if (p
->fts_number
== SKIPPED
)
329 !check(p
->fts_path
, p
->fts_accpath
, p
->fts_statp
))
334 * Protect against deleting root files and directories.
336 if (kBuildProtectionEnforce(&g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
, p
->fts_accpath
)) {
344 (p
->fts_statp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
345 !(p
->fts_statp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)))
346 rval
= chflags(p
->fts_accpath
,
347 p
->fts_statp
->st_flags
&= ~(UF_APPEND
|UF_IMMUTABLE
));
351 * If we can't read or search the directory, may still be
352 * able to remove it. Don't print out the un{read,search}able
353 * message unless the remove fails.
355 switch (p
->fts_info
) {
358 rval
= rmdir(p
->fts_accpath
);
359 if (rval
== 0 || (fflag
&& errno
== ENOENT
)) {
360 if (rval
== 0 && vflag
)
369 rval
= undelete(p
->fts_accpath
);
370 if (rval
== 0 && (fflag
&& errno
== ENOENT
)) {
381 * Assume that since fts_read() couldn't stat
382 * the file, it can't be unlinked.
389 if (!rm_overwrite(p
->fts_accpath
, NULL
))
391 rval
= unlink(p
->fts_accpath
);
394 chmod(p
->fts_accpath
, 0777);
395 rval
= unlink(p
->fts_accpath
);
399 if (rval
== 0 || (fflag
&& errno
== ENOENT
)) {
400 if (rval
== 0 && vflag
)
410 fprintf(stderr
, "%s: %s: %s\n", argv0
, p
->fts_path
, strerror(errno
));
414 fprintf(stderr
, "%s: fts_read: %s\n", argv0
, strerror(errno
));
429 * Check up front before anything is deleted.
432 for (i
= 0; argv
[i
]; i
++) {
433 if (kBuildProtectionEnforce(&g_ProtData
, KBUILDPROTECTIONTYPE_FULL
, argv
[i
]))
438 * Remove a file. POSIX 1003.2 states that, by default, attempting
439 * to remove a directory is an error, so must always stat the file.
441 while ((f
= *argv
++) != NULL
) {
442 /* Assume if can't stat the file, can't unlink it. */
446 sb
.st_mode
= S_IFWHT
|S_IWUSR
|S_IRUSR
;
451 if (!fflag
|| errno
!= ENOENT
) {
452 fprintf(stderr
, "%s: %s: %s\n", argv0
, f
, strerror(errno
));
459 fprintf(stderr
, "%s: %s: %s\n", argv0
, f
, strerror(EEXIST
));
465 if (S_ISDIR(sb
.st_mode
) && !dflag
) {
466 fprintf(stderr
, "%s: %s: is a directory\n", argv0
, f
);
470 if (!fflag
&& !S_ISWHT(sb
.st_mode
) && !check(f
, f
, &sb
))
475 (sb
.st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
476 !(sb
.st_flags
& (SF_APPEND
|SF_IMMUTABLE
)))
477 rval
= chflags(f
, sb
.st_flags
& ~(UF_APPEND
|UF_IMMUTABLE
));
480 if (S_ISWHT(sb
.st_mode
))
482 else if (S_ISDIR(sb
.st_mode
))
486 if (!rm_overwrite(f
, &sb
))
497 if (rval
&& (!fflag
|| errno
!= ENOENT
)) {
498 fprintf(stderr
, "%s: %s: %s\n", argv0
, f
, strerror(errno
));
501 if (vflag
&& rval
== 0)
502 (void)printf("%s\n", f
);
509 * Overwrite the file 3 times with varying bit patterns.
512 * This is a cheap way to *really* delete files. Note that only regular
513 * files are deleted, directories (and therefore names) will remain.
514 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
515 * System V file system). In a logging file system, you'll have to have
519 rm_overwrite(char *file
, struct stat
*sbp
)
531 if (lstat(file
, &sb
))
535 if (!S_ISREG(sbp
->st_mode
))
537 if ((fd
= open(file
, O_WRONLY
, 0)) == -1)
540 if (fstatfs(fd
, &fsb
) == -1)
542 bsize
= MAX(fsb
.f_iosize
, 1024);
543 #elif defined(HAVE_ST_BLKSIZE)
544 bsize
= MAX(sb
.st_blksize
, 1024);
548 if ((buf
= malloc(bsize
)) == NULL
)
549 exit(err(1, "%s: malloc", file
));
551 #define PASS(byte) { \
552 memset(buf, byte, bsize); \
553 for (len = sbp->st_size; len > 0; len -= wlen) { \
554 wlen = len < bsize ? len : bsize; \
555 if (write(fd, buf, wlen) != wlen) \
560 if (fsync(fd
) || lseek(fd
, (off_t
)0, SEEK_SET
))
563 if (fsync(fd
) || lseek(fd
, (off_t
)0, SEEK_SET
))
566 if (!fsync(fd
) && !close(fd
)) {
576 fprintf(stderr
, "%s: %s: %s\n", argv0
, file
, strerror(errno
));
582 check(char *path
, char *name
, struct stat
*sp
)
585 char modep
[15], *flagsp
;
587 /* Check -i first. */
589 (void)fprintf(stderr
, "remove %s? ", path
);
592 * If it's not a symbolic link and it's unwritable and we're
593 * talking to a terminal, ask. Symbolic links are excluded
594 * because their permissions are meaningless. Check stdin_ok
595 * first because we may not have stat'ed the file.
596 * Also skip this check if the -P option was specified because
597 * we will not be able to overwrite file contents and will
600 if (!stdin_ok
|| S_ISLNK(sp
->st_mode
) || Pflag
||
601 (!access(name
, W_OK
) &&
603 !(sp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)) &&
604 (!(sp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) || !uid
))
610 bsd_strmode(sp
->st_mode
, modep
);
612 if ((flagsp
= fflagstostr(sp
->st_flags
)) == NULL
)
613 exit(err(1, "fflagstostr"));
614 (void)fprintf(stderr
, "override %s%s%s/%s %s%sfor %s? ",
615 modep
+ 1, modep
[9] == ' ' ? "" : " ",
616 user_from_uid(sp
->st_uid
, 0),
617 group_from_gid(sp
->st_gid
, 0),
618 *flagsp
? flagsp
: "", *flagsp
? " " : "",
623 (void)fprintf(stderr
, "override %s%s %d/%d for %s? ",
624 modep
+ 1, modep
[9] == ' ' ? "" : " ",
625 sp
->st_uid
, sp
->st_gid
, path
);
628 (void)fflush(stderr
);
630 first
= ch
= getchar();
631 while (ch
!= '\n' && ch
!= EOF
)
633 return (first
== 'y' || first
== 'Y');
636 #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
638 checkdot(char **argv
)
640 char *p
, **save
, **t
;
644 for (t
= argv
; *t
;) {
645 #ifdef HAVE_DOS_PATHS
646 const char *tmp
= p
= *t
;
658 if ((p
= strrchr(*t
, '/')) != NULL
)
665 fprintf(stderr
, "%s: \".\" and \"..\" may not be removed\n", argv0
);
667 for (save
= t
; (t
[0] = t
[1]) != NULL
; ++t
)
679 "usage: %s [options] file ...\n"
681 " or: %s --version\n"
685 " Attempt to remove files without prompting, regardless of the file\n"
686 " permission. Ignore non-existing files. Overrides previous -i's.\n"
688 " Prompt for each file. Always.\n"
690 " Attempt to remove directories as well as other kinds of files.\n"
692 " Overwrite regular files before deleting; three passes: ff,0,ff\n"
694 " Attempt to remove the file hierachy rooted in each file argument.\n"
695 " This option implies -d and file protection.\n"
697 " Be verbose, show files as they are removed.\n"
699 " Undelete without files.\n"
700 " --disable-protection\n"
701 " Will disable the protection file protection applied with -R.\n"
702 " --enable-protection\n"
703 " Will enable the protection file protection applied with -R.\n"
704 " --enable-full-protection\n"
705 " Will enable the protection file protection for all operations.\n"
706 " --disable-full-protection\n"
707 " Will disable the protection file protection for all operations.\n"
708 " --protection-depth\n"
709 " Number or path indicating the file protection depth. Default: %d\n"
712 " KMK_RM_DISABLE_PROTECTION\n"
713 " Same as --disable-protection. Overrides command line.\n"
714 " KMK_RM_ENABLE_PROTECTION\n"
715 " Same as --enable-protection. Overrides everyone else.\n"
716 " KMK_RM_ENABLE_FULL_PROTECTION\n"
717 " Same as --enable-full-protection. Overrides everyone else.\n"
718 " KMK_RM_DISABLE_FULL_PROTECTION\n"
719 " Same as --disable-full-protection. Overrides command line.\n"
720 " KMK_RM_PROTECTION_DEPTH\n"
721 " Same as --protection-depth. Overrides command line.\n"
723 "The file protection of the top %d layers of the file hierarchy is there\n"
724 "to try prevent makefiles from doing bad things to your system. This\n"
725 "protection is not bulletproof, but should help prevent you from shooting\n"
726 "yourself in the foot.\n"
728 g_progname
, g_progname
, g_progname
,
729 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());