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 $");*/
45 /*********************************************************************************************************************************
47 *********************************************************************************************************************************/
48 #define FAKES_NO_GETOPT_H /* bird */
51 #if !defined(_MSC_VER) && !defined(__HAIKU__)
52 # include <sys/param.h>
54 # include <sys/mount.h>
68 # include <sysexits.h>
74 # include "haikufakes.h"
78 # define fflagstostr(flags) flags_to_string(flags, "")
80 #ifdef KBUILD_OS_WINDOWS
82 # include "mscfakes.h"
84 # include "nt/ntunlink.h"
85 /* Use the special unlink implementation to do rmdir too. */
87 # define rmdir(a_pszPath) birdUnlinkForced(a_pszPath)
89 #if defined(__OS2__) || defined(_MSC_VER)
93 #include "kmkbuiltin.h"
94 #include "kbuild_protection.h"
95 #include "k/kDefs.h" /* for K_OS */
98 /*********************************************************************************************************************************
99 * Defined Constants And Macros *
100 *********************************************************************************************************************************/
101 #if defined(__EMX__) || defined(KBUILD_OS_WINDOWS)
102 # define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
103 # define HAVE_DOS_PATHS 1
104 # define DEFAULT_PROTECTION_DEPTH 1
106 # define IS_SLASH(ch) ( (ch) == '/' )
107 # undef HAVE_DOS_PATHS
108 # define DEFAULT_PROTECTION_DEPTH 2
118 #define undelete(s) (-1)
122 #define CUR_LINE_H2(x) "[line " #x "]"
123 #define CUR_LINE_H1(x) CUR_LINE_H2(x)
124 #define CUR_LINE() CUR_LINE_H1(__LINE__)
130 /*********************************************************************************************************************************
131 * Structures and Typedefs *
132 *********************************************************************************************************************************/
133 typedef struct RMINSTANCE
136 int dflag
, eval
, fflag
, iflag
, Pflag
, vflag
, Wflag
, stdin_ok
;
137 #ifdef KBUILD_OS_WINDOWS
138 int fUseNtDeleteFile
;
141 KBUILDPROTECTION g_ProtData
;
143 typedef RMINSTANCE
*PRMINSTANCE
;
146 /*********************************************************************************************************************************
148 *********************************************************************************************************************************/
149 static struct option long_options
[] =
151 { "help", no_argument
, 0, 261 },
152 { "version", no_argument
, 0, 262 },
153 { "disable-protection", no_argument
, 0, 263 },
154 { "enable-protection", no_argument
, 0, 264 },
155 { "enable-full-protection", no_argument
, 0, 265 },
156 { "disable-full-protection", no_argument
, 0, 266 },
157 { "protection-depth", required_argument
, 0, 267 },
158 #ifdef KBUILD_OS_WINDOWS
159 { "nt-delete-file", no_argument
, 0, 268 },
165 /*********************************************************************************************************************************
166 * Internal Functions *
167 *********************************************************************************************************************************/
168 extern void bsd_strmode(mode_t mode
, char *p
); /* strmode.c */
170 static int check(PRMINSTANCE
, char *, char *, struct stat
*);
171 static void checkdot(PRMINSTANCE
, char **);
172 static int rm_file(PRMINSTANCE
, char **);
173 static int rm_overwrite(PRMINSTANCE
, char *, struct stat
*);
174 static int rm_tree(PRMINSTANCE
, char **);
175 static int usage(PKMKBUILTINCTX
, int);
181 * This rm is different from historic rm's, but is expected to match
182 * POSIX 1003.2 behavior. The most visible difference is that -f
183 * has two specific effects now, ignore non-existent files and force
187 kmk_builtin_rm(int argc
, char *argv
[], char **envp
, PKMKBUILTINCTX pCtx
)
190 struct getopt_state_r gos
;
193 /* Init global instance data */
203 #ifdef KBUILD_OS_WINDOWS
204 This
.fUseNtDeleteFile
= 0;
207 kBuildProtectionInit(&This
.g_ProtData
, pCtx
);
210 getopt_initialize_r(&gos
, argc
, argv
, "dfiPRvW", long_options
, envp
, pCtx
);
211 while ((ch
= getopt_long_r(&gos
, NULL
)) != -1)
229 case 'r': /* Compatibility. */
242 kBuildProtectionTerm(&This
.g_ProtData
);
246 kBuildProtectionTerm(&This
.g_ProtData
);
247 return kbuild_version(argv
[0]);
249 kBuildProtectionDisable(&This
.g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
);
252 kBuildProtectionEnable(&This
.g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
);
255 kBuildProtectionEnable(&This
.g_ProtData
, KBUILDPROTECTIONTYPE_FULL
);
258 kBuildProtectionDisable(&This
.g_ProtData
, KBUILDPROTECTIONTYPE_FULL
);
261 if (kBuildProtectionSetDepth(&This
.g_ProtData
, gos
.optarg
)) {
262 kBuildProtectionTerm(&This
.g_ProtData
);
266 #ifdef KBUILD_OS_WINDOWS
268 This
.fUseNtDeleteFile
= 1;
273 kBuildProtectionTerm(&This
.g_ProtData
);
274 return usage(pCtx
, 1);
280 kBuildProtectionTerm(&This
.g_ProtData
);
283 return usage(pCtx
, 1);
286 if (!kBuildProtectionScanEnv(&This
.g_ProtData
, envp
, "KMK_RM_")) {
287 checkdot(&This
, argv
);
288 This
.uid
= geteuid();
291 This
.stdin_ok
= isatty(STDIN_FILENO
);
293 This
.eval
|= rm_tree(&This
, argv
);
295 This
.eval
|= rm_file(&This
, argv
);
301 kBuildProtectionTerm(&This
.g_ProtData
);
305 #ifdef KMK_BUILTIN_STANDALONE
306 int main(int argc
, char **argv
, char **envp
)
308 KMKBUILTINCTX Ctx
= { "kmk_rm", NULL
};
309 return kmk_builtin_rm(argc
, argv
, envp
, &Ctx
);
314 rm_tree(PRMINSTANCE pThis
, char **argv
)
323 * Check up front before anything is deleted. This will not catch
324 * everything, but we'll check the individual items later.
327 for (i
= 0; argv
[i
]; i
++) {
328 if (kBuildProtectionEnforce(&pThis
->g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
, argv
[i
])) {
334 * Remove a file hierarchy. If forcing removal (-f), or interactive
335 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
337 needstat
= !pThis
->uid
|| (!pThis
->fflag
&& !pThis
->iflag
&& pThis
->stdin_ok
);
340 * If the -i option is specified, the user can skip on the pre-order
341 * visit. The fts_number field flags skipped directories.
345 flags
= FTS_PHYSICAL
;
346 #ifndef KMK_BUILTIN_STANDALONE
347 flags
|= FTS_NOCHDIR
; /* Must not change the directory from inside kmk! */
353 flags
|= FTS_WHITEOUT
;
355 if (!(fts
= fts_open(argv
, flags
, NULL
))) {
356 return err(pThis
->pCtx
, 1, "fts_open");
358 while ((p
= fts_read(fts
)) != NULL
) {
359 const char *operation
= "chflags";
360 switch (p
->fts_info
) {
362 if (!pThis
->fflag
|| p
->fts_errno
!= ENOENT
)
363 pThis
->eval
= errx(pThis
->pCtx
, 1, "fts: %s: %s" CUR_LINE() "\n",
364 p
->fts_path
, strerror(p
->fts_errno
));
368 return errx(pThis
->pCtx
, 1, "fts: %s: %s " CUR_LINE(), p
->fts_path
, strerror(p
->fts_errno
));
371 * Assume that since fts_read() couldn't stat the
372 * file, it can't be unlinked.
376 if (!pThis
->fflag
|| p
->fts_errno
!= ENOENT
)
377 pThis
->eval
= errx(pThis
->pCtx
, 1, "fts: %s: %s " CUR_LINE() "\n",
378 p
->fts_path
, strerror(p
->fts_errno
));
381 /* Pre-order: give user chance to skip. */
382 if (!pThis
->fflag
&& !check(pThis
, p
->fts_path
, p
->fts_accpath
, p
->fts_statp
)) {
383 (void)fts_set(fts
, p
, FTS_SKIP
);
384 p
->fts_number
= SKIPPED
;
387 else if (!pThis
->uid
&&
388 (p
->fts_statp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
389 !(p
->fts_statp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)) &&
390 chflags(p
->fts_accpath
,
391 p
->fts_statp
->st_flags
&= ~(UF_APPEND
|UF_IMMUTABLE
)) < 0)
396 /* Post-order: see if user skipped. */
397 if (p
->fts_number
== SKIPPED
)
401 if (!pThis
->fflag
&& !check(pThis
, p
->fts_path
, p
->fts_accpath
, p
->fts_statp
))
406 * Protect against deleting root files and directories.
408 if (kBuildProtectionEnforce(&pThis
->g_ProtData
, KBUILDPROTECTIONTYPE_RECURSIVE
, p
->fts_accpath
)) {
416 (p
->fts_statp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
417 !(p
->fts_statp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)))
418 rval
= chflags(p
->fts_accpath
,
419 p
->fts_statp
->st_flags
&= ~(UF_APPEND
|UF_IMMUTABLE
));
423 * If we can't read or search the directory, may still be
424 * able to remove it. Don't print out the un{read,search}able
425 * message unless the remove fails.
427 switch (p
->fts_info
) {
430 #ifdef KBUILD_OS_WINDOWS
431 if (p
->fts_parent
->fts_dirfd
!= NT_FTS_INVALID_HANDLE_VALUE
) {
432 rval
= birdUnlinkForcedEx(p
->fts_parent
->fts_dirfd
, p
->fts_name
);
434 rval
= birdUnlinkForced(p
->fts_accpath
);
437 rval
= rmdir(p
->fts_accpath
);
439 if (rval
== 0 || (pThis
->fflag
&& errno
== ENOENT
)) {
440 if (rval
== 0 && pThis
->vflag
)
441 kmk_builtin_ctx_printf(pThis
->pCtx
, 0, "%s\n", p
->fts_path
);
442 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
444 extern int dir_cache_deleted_directory(const char *pszDir
);
445 dir_cache_deleted_directory(p
->fts_accpath
);
455 rval
= undelete(p
->fts_accpath
);
456 if (rval
== 0 && (pThis
->fflag
&& errno
== ENOENT
)) {
458 kmk_builtin_ctx_printf(pThis
->pCtx
, 0, "%s\n", p
->fts_path
);
461 operation
= "undelete";
467 * Assume that since fts_read() couldn't stat
468 * the file, it can't be unlinked.
475 if (!rm_overwrite(pThis
, p
->fts_accpath
, NULL
))
477 #ifdef KBUILD_OS_WINDOWS
478 if (p
->fts_parent
->fts_dirfd
!= NT_FTS_INVALID_HANDLE_VALUE
) {
479 if (p
->fts_info
!= FTS_SL
&& p
->fts_info
!= FTS_SLNONE
) {
480 rval
= birdUnlinkForcedFastEx(p
->fts_parent
->fts_dirfd
, p
->fts_name
);
481 } else { /* NtDeleteFile doesn't work on directory links, so slow symlink deletion: */
482 rval
= birdUnlinkForcedEx(p
->fts_parent
->fts_dirfd
, p
->fts_name
);
485 if (p
->fts_info
!= FTS_SL
&& p
->fts_info
!= FTS_SLNONE
) {
486 rval
= birdUnlinkForcedFast(p
->fts_accpath
);
487 } else { /* NtDeleteFile doesn't work on directory links, so slow symlink deletion: */
488 rval
= birdUnlinkForced(p
->fts_accpath
);
492 rval
= unlink(p
->fts_accpath
);
495 if (rval
== 0 || (pThis
->fflag
&& errno
== ENOENT
)) {
496 if (rval
== 0 && pThis
->vflag
)
497 kmk_builtin_ctx_printf(pThis
->pCtx
, 0, "%s\n", p
->fts_path
);
500 operation
= "unlink";
507 pThis
->eval
= errx(pThis
->pCtx
, 1, "%s: %s failed: %s " CUR_LINE() "\n", p
->fts_path
, operation
, strerror(errno
));
510 pThis
->eval
= errx(pThis
->pCtx
, 1, "fts_read: %s " CUR_LINE() "\n", strerror(errno
));
517 rm_file(PRMINSTANCE pThis
, char **argv
)
524 * Check up front before anything is deleted.
527 for (i
= 0; argv
[i
]; i
++) {
528 if (kBuildProtectionEnforce(&pThis
->g_ProtData
, KBUILDPROTECTIONTYPE_FULL
, argv
[i
]))
533 * Remove a file. POSIX 1003.2 states that, by default, attempting
534 * to remove a directory is an error, so must always stat the file.
536 while ((f
= *argv
++) != NULL
) {
537 const char *operation
= "?";
538 /* Assume if can't stat the file, can't unlink it. */
542 sb
.st_mode
= S_IFWHT
|S_IWUSR
|S_IRUSR
;
547 if (!pThis
->fflag
|| errno
!= ENOENT
)
548 pThis
->eval
= errx(pThis
->pCtx
, 1, "%s: lstat failed: %s " CUR_LINE() "\n",
553 } else if (pThis
->Wflag
) {
554 errx(pThis
->pCtx
, 1, "%s: %s\n", f
, strerror(EEXIST
));
560 if (S_ISDIR(sb
.st_mode
) && !pThis
->dflag
) {
561 pThis
->eval
= errx(pThis
->pCtx
, 1, "%s: is a directory\n", f
);
564 if (!pThis
->fflag
&& !S_ISWHT(sb
.st_mode
) && !check(pThis
, f
, f
, &sb
))
569 (sb
.st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) &&
570 !(sb
.st_flags
& (SF_APPEND
|SF_IMMUTABLE
)))
571 rval
= chflags(f
, sb
.st_flags
& ~(UF_APPEND
|UF_IMMUTABLE
));
574 if (S_ISWHT(sb
.st_mode
)) {
576 operation
= "undelete";
577 } else if (S_ISDIR(sb
.st_mode
)) {
582 if (!rm_overwrite(pThis
, f
, &sb
))
584 #ifndef KBUILD_OS_WINDOWS
586 operation
= "unlink";
588 if (pThis
->fUseNtDeleteFile
) {
589 rval
= birdUnlinkForcedFast(f
);
590 operation
= "NtDeleteFile";
592 rval
= birdUnlinkForced(f
);
593 operation
= "unlink";
598 if (rval
&& (!pThis
->fflag
|| errno
!= ENOENT
))
599 pThis
->eval
= errx(pThis
->pCtx
, 1, "%s: %s failed: %s" CUR_LINE() "\n", f
, operation
, strerror(errno
));
600 if (pThis
->vflag
&& rval
== 0)
601 kmk_builtin_ctx_printf(pThis
->pCtx
, 0, "%s\n", f
);
608 * Overwrite the file 3 times with varying bit patterns.
611 * This is a cheap way to *really* delete files. Note that only regular
612 * files are deleted, directories (and therefore names) will remain.
613 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
614 * System V file system). In a logging file system, you'll have to have
618 rm_overwrite(PRMINSTANCE pThis
, char *file
, struct stat
*sbp
)
627 const char *operation
= "lstat";
632 if (lstat(file
, &sb
))
636 if (!S_ISREG(sbp
->st_mode
))
639 if ((fd
= open(file
, O_WRONLY
| KMK_OPEN_NO_INHERIT
, 0)) == -1)
642 if (fstatfs(fd
, &fsb
) == -1)
644 bsize
= MAX(fsb
.f_iosize
, 1024);
645 #elif defined(HAVE_ST_BLKSIZE)
646 bsize
= MAX(sb
.st_blksize
, 1024);
650 if ((buf
= malloc(bsize
)) == NULL
) {
651 err(pThis
->pCtx
, 1, "%s: malloc", file
);
656 #define PASS(byte) { \
657 operation = "write"; \
658 memset(buf, byte, bsize); \
659 for (len = sbp->st_size; len > 0; len -= wlen) { \
660 wlen = len < bsize ? len : bsize; \
661 if (write(fd, buf, wlen) != wlen) \
666 operation
= "fsync/lseek";
667 if (fsync(fd
) || lseek(fd
, (off_t
)0, SEEK_SET
))
670 operation
= "fsync/lseek";
671 if (fsync(fd
) || lseek(fd
, (off_t
)0, SEEK_SET
))
674 if (!fsync(fd
) && !close(fd
)) {
678 operation
= "fsync/close";
680 err
: pThis
->eval
= 1;
686 errx(pThis
->pCtx
, 1, "%s: %s: %s: %s" CUR_LINE() "\n", operation
, pThis
->pCtx
->pszProgName
, file
, strerror(error
));
692 check(PRMINSTANCE pThis
, char *path
, char *name
, struct stat
*sp
)
695 char modep
[15], *flagsp
;
697 /* Check -i first. */
699 (void)fprintf(stderr
, "%s: remove %s? ", pThis
->pCtx
->pszProgName
, path
);
702 * If it's not a symbolic link and it's unwritable and we're
703 * talking to a terminal, ask. Symbolic links are excluded
704 * because their permissions are meaningless. Check stdin_ok
705 * first because we may not have stat'ed the file.
706 * Also skip this check if the -P option was specified because
707 * we will not be able to overwrite file contents and will
710 if (!pThis
->stdin_ok
|| S_ISLNK(sp
->st_mode
) || pThis
->Pflag
||
711 (!access(name
, W_OK
) &&
713 !(sp
->st_flags
& (SF_APPEND
|SF_IMMUTABLE
)) &&
714 (!(sp
->st_flags
& (UF_APPEND
|UF_IMMUTABLE
)) || !pThis
->uid
))
720 bsd_strmode(sp
->st_mode
, modep
);
721 #if defined(SF_APPEND) && K_OS != K_OS_GNU_KFBSD && K_OS != K_OS_GNU_HURD
722 if ((flagsp
= fflagstostr(sp
->st_flags
)) == NULL
) {
723 err(pThis
->pCtx
, 1, "fflagstostr");
724 flagsp
= "<bad-fflagstostr>";
726 (void)fprintf(stderr
, "override %s%s%s/%s %s%sfor %s? ",
727 modep
+ 1, modep
[9] == ' ' ? "" : " ",
728 user_from_uid(sp
->st_uid
, 0),
729 group_from_gid(sp
->st_gid
, 0),
730 *flagsp
? flagsp
: "", *flagsp
? " " : "",
735 (void)fprintf(stderr
, "override %s%s %d/%d for %s? ",
736 modep
+ 1, modep
[9] == ' ' ? "" : " ",
737 sp
->st_uid
, sp
->st_gid
, path
);
740 (void)fflush(stderr
);
742 first
= ch
= getchar();
743 while (ch
!= '\n' && ch
!= EOF
)
745 return (first
== 'y' || first
== 'Y');
748 #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
750 checkdot(PRMINSTANCE pThis
, char **argv
)
752 char *p
, **save
, **t
;
756 for (t
= argv
; *t
;) {
757 #ifdef HAVE_DOS_PATHS
758 const char *tmp
= p
= *t
;
770 if ((p
= strrchr(*t
, '/')) != NULL
)
777 warnx(pThis
->pCtx
, "\".\" and \"..\" may not be removed\n");
779 for (save
= t
; (t
[0] = t
[1]) != NULL
; ++t
)
788 usage(PKMKBUILTINCTX pCtx
, int fIsErr
)
790 kmk_builtin_ctx_printf(pCtx
, fIsErr
,
791 "usage: %s [options] file ...\n"
793 " or: %s --version\n"
797 " Attempt to remove files without prompting, regardless of the file\n"
798 " permission. Ignore non-existing files. Overrides previous -i's.\n"
800 " Prompt for each file. Always.\n"
802 " Attempt to remove directories as well as other kinds of files.\n"
804 " Overwrite regular files before deleting; three passes: ff,0,ff\n"
806 " Attempt to remove the file hierachy rooted in each file argument.\n"
807 " This option implies -d and file protection.\n"
809 " Be verbose, show files as they are removed.\n"
811 " Undelete white-out files.\n"
812 " --disable-protection\n"
813 " Will disable the protection file protection applied with -R.\n"
814 " --enable-protection\n"
815 " Will enable the protection file protection applied with -R.\n"
816 " --enable-full-protection\n"
817 " Will enable the protection file protection for all operations.\n"
818 " --disable-full-protection\n"
819 " Will disable the protection file protection for all operations.\n"
820 " --protection-depth\n"
821 " Number or path indicating the file protection depth. Default: %d\n"
824 " KMK_RM_DISABLE_PROTECTION\n"
825 " Same as --disable-protection. Overrides command line.\n"
826 " KMK_RM_ENABLE_PROTECTION\n"
827 " Same as --enable-protection. Overrides everyone else.\n"
828 " KMK_RM_ENABLE_FULL_PROTECTION\n"
829 " Same as --enable-full-protection. Overrides everyone else.\n"
830 " KMK_RM_DISABLE_FULL_PROTECTION\n"
831 " Same as --disable-full-protection. Overrides command line.\n"
832 " KMK_RM_PROTECTION_DEPTH\n"
833 " Same as --protection-depth. Overrides command line.\n"
835 "The file protection of the top %d layers of the file hierarchy is there\n"
836 "to try prevent makefiles from doing bad things to your system. This\n"
837 "protection is not bulletproof, but should help prevent you from shooting\n"
838 "yourself in the foot.\n"
840 pCtx
->pszProgName
, pCtx
->pszProgName
, pCtx
->pszProgName
,
841 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());