VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/rm.c@ 2856

Last change on this file since 2856 was 2713, checked in by bird, 11 years ago

Some unlink(), rmdir() and kmk_rm optimizations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.4 KB
Line 
1/*-
2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char copyright[] =
33"@(#) Copyright (c) 1990, 1993, 1994\n\
34 The Regents of the University of California. All rights reserved.\n";
35#endif /* not lint */
36
37#ifndef lint
38static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94";
39#endif /* not lint */
40#include <sys/cdefs.h>
41/*__FBSDID("$FreeBSD: src/bin/rm/rm.c,v 1.47 2004/04/06 20:06:50 markm Exp $");*/
42#endif
43
44#include "config.h"
45#include <sys/stat.h>
46#if !defined(_MSC_VER) && !defined(__HAIKU__)
47# include <sys/param.h>
48# include <sys/mount.h>
49#endif
50
51#include "err.h"
52#include <errno.h>
53#include <fcntl.h>
54#include <fts.h>
55#include <grp.h>
56#include <pwd.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#ifndef __HAIKU__
61# include <sysexits.h>
62#endif
63#include <unistd.h>
64#include <ctype.h>
65#include "getopt.h"
66#ifdef __HAIKU__
67# include "haikufakes.h"
68#endif
69#ifdef KBUILD_OS_WINDOWS
70# ifdef _MSC_VER
71# include "mscfakes.h"
72# endif
73# include "nt/ntunlink.h"
74 /* Use the special unlink implementation to do rmdir too. */
75# undef rmdir
76# define rmdir(a_pszPath) birdUnlinkForced(a_pszPath)
77#endif
78#if defined(__OS2__) || defined(_MSC_VER)
79# include <direct.h>
80# include <limits.h>
81#endif
82#include "kmkbuiltin.h"
83#include "kbuild_protection.h"
84
85#if defined(__EMX__) || defined(KBUILD_OS_WINDOWS)
86# define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
87# define HAVE_DOS_PATHS 1
88# define DEFAULT_PROTECTION_DEPTH 1
89#else
90# define IS_SLASH(ch) ( (ch) == '/' )
91# undef HAVE_DOS_PATHS
92# define DEFAULT_PROTECTION_DEPTH 2
93#endif
94
95#ifdef __EMX__
96#undef S_IFWHT
97#undef S_ISWHT
98#endif
99#ifndef S_IFWHT
100#define S_IFWHT 0
101#define S_ISWHT(s) 0
102#define undelete(s) (-1)
103#endif
104
105extern void bsd_strmode(mode_t mode, char *p);
106
107static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
108#ifdef KBUILD_OS_WINDOWS
109static int fUseNtDeleteFile;
110#endif
111static uid_t uid;
112
113static char *argv0;
114static KBUILDPROTECTION g_ProtData;
115
116static struct option long_options[] =
117{
118 { "help", no_argument, 0, 261 },
119 { "version", no_argument, 0, 262 },
120 { "disable-protection", no_argument, 0, 263 },
121 { "enable-protection", no_argument, 0, 264 },
122 { "enable-full-protection", no_argument, 0, 265 },
123 { "disable-full-protection", no_argument, 0, 266 },
124 { "protection-depth", required_argument, 0, 267 },
125#ifdef KBUILD_OS_WINDOWS
126 { "nt-delete-file", no_argument, 0, 268 },
127#endif
128 { 0, 0, 0, 0 },
129};
130
131
132static int check(char *, char *, struct stat *);
133static void checkdot(char **);
134static int rm_file(char **);
135static int rm_overwrite(char *, struct stat *);
136static int rm_tree(char **);
137static int usage(FILE *);
138
139#if 1
140#define CUR_LINE_H2(x) "[line " #x "]"
141#define CUR_LINE_H1(x) CUR_LINE_H2(x)
142#define CUR_LINE() CUR_LINE_H1(__LINE__)
143#else
144# define CUR_LINE()
145#endif
146
147
148/*
149 * rm --
150 * This rm is different from historic rm's, but is expected to match
151 * POSIX 1003.2 behavior. The most visible difference is that -f
152 * has two specific effects now, ignore non-existent files and force
153 * file removal.
154 */
155int
156kmk_builtin_rm(int argc, char *argv[], char **envp)
157{
158 int ch, rflag;
159
160 /* reinitialize globals */
161 argv0 = argv[0];
162 dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
163#ifdef KBUILD_OS_WINDOWS
164 fUseNtDeleteFile = 0;
165#endif
166 uid = 0;
167 kBuildProtectionInit(&g_ProtData);
168
169 /* kmk: reset getopt and set program name. */
170 g_progname = argv[0];
171 opterr = 1;
172 optarg = NULL;
173 optopt = 0;
174 optind = 0; /* init */
175
176 Pflag = rflag = 0;
177 while ((ch = getopt_long(argc, argv, "dfiPRvW", long_options, NULL)) != -1)
178 switch(ch) {
179 case 'd':
180 dflag = 1;
181 break;
182 case 'f':
183 fflag = 1;
184 iflag = 0;
185 break;
186 case 'i':
187 fflag = 0;
188 iflag = 1;
189 break;
190 case 'P':
191 Pflag = 1;
192 break;
193 case 'R':
194#if 0
195 case 'r': /* Compatibility. */
196#endif
197 rflag = 1;
198 break;
199 case 'v':
200 vflag = 1;
201 break;
202#ifdef FTS_WHITEOUT
203 case 'W':
204 Wflag = 1;
205 break;
206#endif
207 case 261:
208 kBuildProtectionTerm(&g_ProtData);
209 usage(stdout);
210 return 0;
211 case 262:
212 kBuildProtectionTerm(&g_ProtData);
213 return kbuild_version(argv[0]);
214 case 263:
215 kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
216 break;
217 case 264:
218 kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
219 break;
220 case 265:
221 kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
222 break;
223 case 266:
224 kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
225 break;
226 case 267:
227 if (kBuildProtectionSetDepth(&g_ProtData, optarg)) {
228 kBuildProtectionTerm(&g_ProtData);
229 return 1;
230 }
231 break;
232#ifdef KBUILD_OS_WINDOWS
233 case 268:
234 fUseNtDeleteFile = 1;
235 break;
236#endif
237 case '?':
238 default:
239 kBuildProtectionTerm(&g_ProtData);
240 return usage(stderr);
241 }
242 argc -= optind;
243 argv += optind;
244
245 if (argc < 1) {
246 kBuildProtectionTerm(&g_ProtData);
247 if (fflag)
248 return (0);
249 return usage(stderr);
250 }
251
252 if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_RM_")) {
253 checkdot(argv);
254 uid = geteuid();
255
256 if (*argv) {
257 stdin_ok = isatty(STDIN_FILENO);
258 if (rflag)
259 eval |= rm_tree(argv);
260 else
261 eval |= rm_file(argv);
262 }
263 } else {
264 eval = 1;
265 }
266
267 kBuildProtectionTerm(&g_ProtData);
268 return eval;
269}
270
271static int
272rm_tree(char **argv)
273{
274 FTS *fts;
275 FTSENT *p;
276 int needstat;
277 int flags;
278 int rval;
279
280 /*
281 * Check up front before anything is deleted. This will not catch
282 * everything, but we'll check the individual items later.
283 */
284 int i;
285 for (i = 0; argv[i]; i++) {
286 if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, argv[i])) {
287 return 1;
288 }
289 }
290
291 /*
292 * Remove a file hierarchy. If forcing removal (-f), or interactive
293 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
294 */
295 needstat = !uid || (!fflag && !iflag && stdin_ok);
296
297 /*
298 * If the -i option is specified, the user can skip on the pre-order
299 * visit. The fts_number field flags skipped directories.
300 */
301#define SKIPPED 1
302
303 flags = FTS_PHYSICAL;
304 if (!needstat)
305 flags |= FTS_NOSTAT;
306#ifdef FTS_WHITEOUT
307 if (Wflag)
308 flags |= FTS_WHITEOUT;
309#endif
310 if (!(fts = fts_open(argv, flags, NULL))) {
311 return err(1, "fts_open");
312 }
313 while ((p = fts_read(fts)) != NULL) {
314 const char *operation = "chflags";
315 switch (p->fts_info) {
316 case FTS_DNR:
317 if (!fflag || p->fts_errno != ENOENT) {
318 fprintf(stderr, "fts: %s: %s: %s" CUR_LINE() "\n",
319 argv0, p->fts_path, strerror(p->fts_errno));
320 eval = 1;
321 }
322 continue;
323 case FTS_ERR:
324 fts_close(fts);
325 return errx(1, "fts: %s: %s " CUR_LINE(), p->fts_path, strerror(p->fts_errno));
326 case FTS_NS:
327 /*
328 * Assume that since fts_read() couldn't stat the
329 * file, it can't be unlinked.
330 */
331 if (!needstat)
332 break;
333 if (!fflag || p->fts_errno != ENOENT) {
334 fprintf(stderr, "fts: %s: %s: %s " CUR_LINE() "\n",
335 argv0, p->fts_path, strerror(p->fts_errno));
336 eval = 1;
337 }
338 continue;
339 case FTS_D:
340 /* Pre-order: give user chance to skip. */
341 if (!fflag && !check(p->fts_path, p->fts_accpath,
342 p->fts_statp)) {
343 (void)fts_set(fts, p, FTS_SKIP);
344 p->fts_number = SKIPPED;
345 }
346#ifdef UF_APPEND
347 else if (!uid &&
348 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
349 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
350 chflags(p->fts_accpath,
351 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
352 goto err;
353#endif
354 continue;
355 case FTS_DP:
356 /* Post-order: see if user skipped. */
357 if (p->fts_number == SKIPPED)
358 continue;
359 break;
360 default:
361 if (!fflag &&
362 !check(p->fts_path, p->fts_accpath, p->fts_statp))
363 continue;
364 }
365
366 /*
367 * Protect against deleting root files and directories.
368 */
369 if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, p->fts_accpath)) {
370 fts_close(fts);
371 return 1;
372 }
373
374 rval = 0;
375#ifdef UF_APPEND
376 if (!uid &&
377 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
378 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
379 rval = chflags(p->fts_accpath,
380 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
381#endif
382 if (rval == 0) {
383 /*
384 * If we can't read or search the directory, may still be
385 * able to remove it. Don't print out the un{read,search}able
386 * message unless the remove fails.
387 */
388 switch (p->fts_info) {
389 case FTS_DP:
390 case FTS_DNR:
391 rval = rmdir(p->fts_accpath);
392 if (rval == 0 || (fflag && errno == ENOENT)) {
393 if (rval == 0 && vflag)
394 (void)printf("%s\n",
395 p->fts_path);
396 continue;
397 }
398 operation = "mkdir";
399 break;
400
401#ifdef FTS_W
402 case FTS_W:
403 rval = undelete(p->fts_accpath);
404 if (rval == 0 && (fflag && errno == ENOENT)) {
405 if (vflag)
406 (void)printf("%s\n",
407 p->fts_path);
408 continue;
409 }
410 operation = "undelete";
411 break;
412#endif
413
414 case FTS_NS:
415 /*
416 * Assume that since fts_read() couldn't stat
417 * the file, it can't be unlinked.
418 */
419 if (fflag)
420 continue;
421 /* FALLTHROUGH */
422 default:
423 if (Pflag)
424 if (!rm_overwrite(p->fts_accpath, NULL))
425 continue;
426#ifdef KBUILD_OS_WINDOWS
427 rval = birdUnlinkForcedFast(p->fts_accpath);
428#else
429 rval = unlink(p->fts_accpath);
430#endif
431
432 if (rval == 0 || (fflag && errno == ENOENT)) {
433 if (rval == 0 && vflag)
434 (void)printf("%s\n",
435 p->fts_path);
436 continue;
437 }
438 operation = "unlink";
439 break;
440 }
441 }
442#ifdef UF_APPEND
443err:
444#endif
445 fprintf(stderr, "%s: %s: %s: %s " CUR_LINE() "\n", operation, argv0, p->fts_path, strerror(errno));
446 eval = 1;
447 }
448 if (errno) {
449 fprintf(stderr, "%s: fts_read: %s " CUR_LINE() "\n", argv0, strerror(errno));
450 eval = 1;
451 }
452 fts_close(fts);
453 return eval;
454}
455
456static int
457rm_file(char **argv)
458{
459 struct stat sb;
460 int rval;
461 char *f;
462
463 /*
464 * Check up front before anything is deleted.
465 */
466 int i;
467 for (i = 0; argv[i]; i++) {
468 if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
469 return 1;
470 }
471
472 /*
473 * Remove a file. POSIX 1003.2 states that, by default, attempting
474 * to remove a directory is an error, so must always stat the file.
475 */
476 while ((f = *argv++) != NULL) {
477 const char *operation = "?";
478 /* Assume if can't stat the file, can't unlink it. */
479 if (lstat(f, &sb)) {
480#ifdef FTS_WHITEOUT
481 if (Wflag) {
482 sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
483 } else {
484#else
485 {
486#endif
487 if (!fflag || errno != ENOENT) {
488 fprintf(stderr, "lstat: %s: %s: %s " CUR_LINE() "\n", argv0, f, strerror(errno));
489 eval = 1;
490 }
491 continue;
492 }
493#ifdef FTS_WHITEOUT
494 } else if (Wflag) {
495 fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(EEXIST));
496 eval = 1;
497 continue;
498#endif
499 }
500
501 if (S_ISDIR(sb.st_mode) && !dflag) {
502 fprintf(stderr, "%s: %s: is a directory\n", argv0, f);
503 eval = 1;
504 continue;
505 }
506 if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
507 continue;
508 rval = 0;
509#ifdef UF_APPEND
510 if (!uid &&
511 (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
512 !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
513 rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
514#endif
515 if (rval == 0) {
516 if (S_ISWHT(sb.st_mode)) {
517 rval = undelete(f);
518 operation = "undelete";
519 } else if (S_ISDIR(sb.st_mode)) {
520 rval = rmdir(f);
521 operation = "rmdir";
522 } else {
523 if (Pflag)
524 if (!rm_overwrite(f, &sb))
525 continue;
526#ifndef KBUILD_OS_WINDOWS
527 rval = unlink(f);
528 operation = "unlink";
529#else
530 if (fUseNtDeleteFile) {
531 rval = birdUnlinkForcedFast(f);
532 operation = "NtDeleteFile";
533 } else {
534 rval = birdUnlinkForced(f);
535 operation = "unlink";
536 }
537#endif
538 }
539 }
540 if (rval && (!fflag || errno != ENOENT)) {
541 fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, f, strerror(errno));
542 eval = 1;
543 }
544 if (vflag && rval == 0)
545 (void)printf("%s\n", f);
546 }
547 return eval;
548}
549
550/*
551 * rm_overwrite --
552 * Overwrite the file 3 times with varying bit patterns.
553 *
554 * XXX
555 * This is a cheap way to *really* delete files. Note that only regular
556 * files are deleted, directories (and therefore names) will remain.
557 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
558 * System V file system). In a logging file system, you'll have to have
559 * kernel support.
560 */
561static int
562rm_overwrite(char *file, struct stat *sbp)
563{
564 struct stat sb;
565#ifdef HAVE_FSTATFS
566 struct statfs fsb;
567#endif
568 off_t len;
569 int bsize, fd, wlen;
570 char *buf = NULL;
571 const char *operation = "lstat";
572
573 fd = -1;
574 if (sbp == NULL) {
575 if (lstat(file, &sb))
576 goto err;
577 sbp = &sb;
578 }
579 if (!S_ISREG(sbp->st_mode))
580 return (1);
581 operation = "open";
582 if ((fd = open(file, O_WRONLY, 0)) == -1)
583 goto err;
584#ifdef HAVE_FSTATFS
585 if (fstatfs(fd, &fsb) == -1)
586 goto err;
587 bsize = MAX(fsb.f_iosize, 1024);
588#elif defined(HAVE_ST_BLKSIZE)
589 bsize = MAX(sb.st_blksize, 1024);
590#else
591 bsize = 1024;
592#endif
593 if ((buf = malloc(bsize)) == NULL)
594 exit(err(1, "%s: malloc", file));
595
596#define PASS(byte) { \
597 operation = "write"; \
598 memset(buf, byte, bsize); \
599 for (len = sbp->st_size; len > 0; len -= wlen) { \
600 wlen = len < bsize ? len : bsize; \
601 if (write(fd, buf, wlen) != wlen) \
602 goto err; \
603 } \
604}
605 PASS(0xff);
606 operation = "fsync/lseek";
607 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
608 goto err;
609 PASS(0x00);
610 operation = "fsync/lseek";
611 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
612 goto err;
613 PASS(0xff);
614 if (!fsync(fd) && !close(fd)) {
615 free(buf);
616 return (1);
617 }
618 operation = "fsync/close";
619
620err: eval = 1;
621 if (buf)
622 free(buf);
623 if (fd != -1)
624 close(fd);
625 fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, file, strerror(errno));
626 return (0);
627}
628
629
630static int
631check(char *path, char *name, struct stat *sp)
632{
633 int ch, first;
634 char modep[15], *flagsp;
635
636 /* Check -i first. */
637 if (iflag)
638 (void)fprintf(stderr, "remove %s? ", path);
639 else {
640 /*
641 * If it's not a symbolic link and it's unwritable and we're
642 * talking to a terminal, ask. Symbolic links are excluded
643 * because their permissions are meaningless. Check stdin_ok
644 * first because we may not have stat'ed the file.
645 * Also skip this check if the -P option was specified because
646 * we will not be able to overwrite file contents and will
647 * barf later.
648 */
649 if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag ||
650 (!access(name, W_OK) &&
651#ifdef SF_APPEND
652 !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
653 (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))
654#else
655 1)
656#endif
657 )
658 return (1);
659 bsd_strmode(sp->st_mode, modep);
660#ifdef SF_APPEND
661 if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
662 exit(err(1, "fflagstostr"));
663 (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
664 modep + 1, modep[9] == ' ' ? "" : " ",
665 user_from_uid(sp->st_uid, 0),
666 group_from_gid(sp->st_gid, 0),
667 *flagsp ? flagsp : "", *flagsp ? " " : "",
668 path);
669 free(flagsp);
670#else
671 (void)flagsp;
672 (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
673 modep + 1, modep[9] == ' ' ? "" : " ",
674 sp->st_uid, sp->st_gid, path);
675#endif
676 }
677 (void)fflush(stderr);
678
679 first = ch = getchar();
680 while (ch != '\n' && ch != EOF)
681 ch = getchar();
682 return (first == 'y' || first == 'Y');
683}
684
685#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
686static void
687checkdot(char **argv)
688{
689 char *p, **save, **t;
690 int complained;
691
692 complained = 0;
693 for (t = argv; *t;) {
694#ifdef HAVE_DOS_PATHS
695 const char *tmp = p = *t;
696 while (*tmp) {
697 switch (*tmp) {
698 case '/':
699 case '\\':
700 case ':':
701 p = (char *)tmp + 1;
702 break;
703 }
704 tmp++;
705 }
706#else
707 if ((p = strrchr(*t, '/')) != NULL)
708 ++p;
709 else
710 p = *t;
711#endif
712 if (ISDOT(p)) {
713 if (!complained++)
714 fprintf(stderr, "%s: \".\" and \"..\" may not be removed\n", argv0);
715 eval = 1;
716 for (save = t; (t[0] = t[1]) != NULL; ++t)
717 continue;
718 t = save;
719 } else
720 ++t;
721 }
722}
723
724static int
725usage(FILE *pf)
726{
727 fprintf(pf,
728 "usage: %s [options] file ...\n"
729 " or: %s --help\n"
730 " or: %s --version\n"
731 "\n"
732 "Options:\n"
733 " -f\n"
734 " Attempt to remove files without prompting, regardless of the file\n"
735 " permission. Ignore non-existing files. Overrides previous -i's.\n"
736 " -i\n"
737 " Prompt for each file. Always.\n"
738 " -d\n"
739 " Attempt to remove directories as well as other kinds of files.\n"
740 " -P\n"
741 " Overwrite regular files before deleting; three passes: ff,0,ff\n"
742 " -R\n"
743 " Attempt to remove the file hierachy rooted in each file argument.\n"
744 " This option implies -d and file protection.\n"
745 " -v\n"
746 " Be verbose, show files as they are removed.\n"
747 " -W\n"
748 " Undelete without files.\n"
749 " --disable-protection\n"
750 " Will disable the protection file protection applied with -R.\n"
751 " --enable-protection\n"
752 " Will enable the protection file protection applied with -R.\n"
753 " --enable-full-protection\n"
754 " Will enable the protection file protection for all operations.\n"
755 " --disable-full-protection\n"
756 " Will disable the protection file protection for all operations.\n"
757 " --protection-depth\n"
758 " Number or path indicating the file protection depth. Default: %d\n"
759 "\n"
760 "Environment:\n"
761 " KMK_RM_DISABLE_PROTECTION\n"
762 " Same as --disable-protection. Overrides command line.\n"
763 " KMK_RM_ENABLE_PROTECTION\n"
764 " Same as --enable-protection. Overrides everyone else.\n"
765 " KMK_RM_ENABLE_FULL_PROTECTION\n"
766 " Same as --enable-full-protection. Overrides everyone else.\n"
767 " KMK_RM_DISABLE_FULL_PROTECTION\n"
768 " Same as --disable-full-protection. Overrides command line.\n"
769 " KMK_RM_PROTECTION_DEPTH\n"
770 " Same as --protection-depth. Overrides command line.\n"
771 "\n"
772 "The file protection of the top %d layers of the file hierarchy is there\n"
773 "to try prevent makefiles from doing bad things to your system. This\n"
774 "protection is not bulletproof, but should help prevent you from shooting\n"
775 "yourself in the foot.\n"
776 ,
777 g_progname, g_progname, g_progname,
778 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
779 return EX_USAGE;
780}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette