source: trunk/src/kmk/kmkbuiltin/rm.c@ 2984

Last change on this file since 2984 was 2912, checked in by bird, 9 years ago

rewrote kmk_redirect to skip the separate process. Added chache invalidation after directory deletion for addressing kmk rebuild and fetching.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.6 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#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
397 if (rval == 0) {
398 extern int dir_cache_deleted_directory(const char *pszDir);
399 dir_cache_deleted_directory(p->fts_accpath);
400 }
401#endif
402 continue;
403 }
404 operation = "rmdir";
405 break;
406
407#ifdef FTS_W
408 case FTS_W:
409 rval = undelete(p->fts_accpath);
410 if (rval == 0 && (fflag && errno == ENOENT)) {
411 if (vflag)
412 (void)printf("%s\n",
413 p->fts_path);
414 continue;
415 }
416 operation = "undelete";
417 break;
418#endif
419
420 case FTS_NS:
421 /*
422 * Assume that since fts_read() couldn't stat
423 * the file, it can't be unlinked.
424 */
425 if (fflag)
426 continue;
427 /* FALLTHROUGH */
428 default:
429 if (Pflag)
430 if (!rm_overwrite(p->fts_accpath, NULL))
431 continue;
432#ifdef KBUILD_OS_WINDOWS
433 rval = birdUnlinkForcedFast(p->fts_accpath);
434#else
435 rval = unlink(p->fts_accpath);
436#endif
437
438 if (rval == 0 || (fflag && errno == ENOENT)) {
439 if (rval == 0 && vflag)
440 (void)printf("%s\n",
441 p->fts_path);
442 continue;
443 }
444 operation = "unlink";
445 break;
446 }
447 }
448#ifdef UF_APPEND
449err:
450#endif
451 fprintf(stderr, "%s: %s: %s: %s " CUR_LINE() "\n", operation, argv0, p->fts_path, strerror(errno));
452 eval = 1;
453 }
454 if (errno) {
455 fprintf(stderr, "%s: fts_read: %s " CUR_LINE() "\n", argv0, strerror(errno));
456 eval = 1;
457 }
458 fts_close(fts);
459 return eval;
460}
461
462static int
463rm_file(char **argv)
464{
465 struct stat sb;
466 int rval;
467 char *f;
468
469 /*
470 * Check up front before anything is deleted.
471 */
472 int i;
473 for (i = 0; argv[i]; i++) {
474 if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
475 return 1;
476 }
477
478 /*
479 * Remove a file. POSIX 1003.2 states that, by default, attempting
480 * to remove a directory is an error, so must always stat the file.
481 */
482 while ((f = *argv++) != NULL) {
483 const char *operation = "?";
484 /* Assume if can't stat the file, can't unlink it. */
485 if (lstat(f, &sb)) {
486#ifdef FTS_WHITEOUT
487 if (Wflag) {
488 sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
489 } else {
490#else
491 {
492#endif
493 if (!fflag || errno != ENOENT) {
494 fprintf(stderr, "lstat: %s: %s: %s " CUR_LINE() "\n", argv0, f, strerror(errno));
495 eval = 1;
496 }
497 continue;
498 }
499#ifdef FTS_WHITEOUT
500 } else if (Wflag) {
501 fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(EEXIST));
502 eval = 1;
503 continue;
504#endif
505 }
506
507 if (S_ISDIR(sb.st_mode) && !dflag) {
508 fprintf(stderr, "%s: %s: is a directory\n", argv0, f);
509 eval = 1;
510 continue;
511 }
512 if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
513 continue;
514 rval = 0;
515#ifdef UF_APPEND
516 if (!uid &&
517 (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
518 !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
519 rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
520#endif
521 if (rval == 0) {
522 if (S_ISWHT(sb.st_mode)) {
523 rval = undelete(f);
524 operation = "undelete";
525 } else if (S_ISDIR(sb.st_mode)) {
526 rval = rmdir(f);
527 operation = "rmdir";
528 } else {
529 if (Pflag)
530 if (!rm_overwrite(f, &sb))
531 continue;
532#ifndef KBUILD_OS_WINDOWS
533 rval = unlink(f);
534 operation = "unlink";
535#else
536 if (fUseNtDeleteFile) {
537 rval = birdUnlinkForcedFast(f);
538 operation = "NtDeleteFile";
539 } else {
540 rval = birdUnlinkForced(f);
541 operation = "unlink";
542 }
543#endif
544 }
545 }
546 if (rval && (!fflag || errno != ENOENT)) {
547 fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, f, strerror(errno));
548 eval = 1;
549 }
550 if (vflag && rval == 0)
551 (void)printf("%s\n", f);
552 }
553 return eval;
554}
555
556/*
557 * rm_overwrite --
558 * Overwrite the file 3 times with varying bit patterns.
559 *
560 * XXX
561 * This is a cheap way to *really* delete files. Note that only regular
562 * files are deleted, directories (and therefore names) will remain.
563 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
564 * System V file system). In a logging file system, you'll have to have
565 * kernel support.
566 */
567static int
568rm_overwrite(char *file, struct stat *sbp)
569{
570 struct stat sb;
571#ifdef HAVE_FSTATFS
572 struct statfs fsb;
573#endif
574 off_t len;
575 int bsize, fd, wlen;
576 char *buf = NULL;
577 const char *operation = "lstat";
578
579 fd = -1;
580 if (sbp == NULL) {
581 if (lstat(file, &sb))
582 goto err;
583 sbp = &sb;
584 }
585 if (!S_ISREG(sbp->st_mode))
586 return (1);
587 operation = "open";
588 if ((fd = open(file, O_WRONLY, 0)) == -1)
589 goto err;
590#ifdef HAVE_FSTATFS
591 if (fstatfs(fd, &fsb) == -1)
592 goto err;
593 bsize = MAX(fsb.f_iosize, 1024);
594#elif defined(HAVE_ST_BLKSIZE)
595 bsize = MAX(sb.st_blksize, 1024);
596#else
597 bsize = 1024;
598#endif
599 if ((buf = malloc(bsize)) == NULL)
600 exit(err(1, "%s: malloc", file));
601
602#define PASS(byte) { \
603 operation = "write"; \
604 memset(buf, byte, bsize); \
605 for (len = sbp->st_size; len > 0; len -= wlen) { \
606 wlen = len < bsize ? len : bsize; \
607 if (write(fd, buf, wlen) != wlen) \
608 goto err; \
609 } \
610}
611 PASS(0xff);
612 operation = "fsync/lseek";
613 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
614 goto err;
615 PASS(0x00);
616 operation = "fsync/lseek";
617 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
618 goto err;
619 PASS(0xff);
620 if (!fsync(fd) && !close(fd)) {
621 free(buf);
622 return (1);
623 }
624 operation = "fsync/close";
625
626err: eval = 1;
627 if (buf)
628 free(buf);
629 if (fd != -1)
630 close(fd);
631 fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, file, strerror(errno));
632 return (0);
633}
634
635
636static int
637check(char *path, char *name, struct stat *sp)
638{
639 int ch, first;
640 char modep[15], *flagsp;
641
642 /* Check -i first. */
643 if (iflag)
644 (void)fprintf(stderr, "remove %s? ", path);
645 else {
646 /*
647 * If it's not a symbolic link and it's unwritable and we're
648 * talking to a terminal, ask. Symbolic links are excluded
649 * because their permissions are meaningless. Check stdin_ok
650 * first because we may not have stat'ed the file.
651 * Also skip this check if the -P option was specified because
652 * we will not be able to overwrite file contents and will
653 * barf later.
654 */
655 if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag ||
656 (!access(name, W_OK) &&
657#ifdef SF_APPEND
658 !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
659 (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))
660#else
661 1)
662#endif
663 )
664 return (1);
665 bsd_strmode(sp->st_mode, modep);
666#ifdef SF_APPEND
667 if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
668 exit(err(1, "fflagstostr"));
669 (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
670 modep + 1, modep[9] == ' ' ? "" : " ",
671 user_from_uid(sp->st_uid, 0),
672 group_from_gid(sp->st_gid, 0),
673 *flagsp ? flagsp : "", *flagsp ? " " : "",
674 path);
675 free(flagsp);
676#else
677 (void)flagsp;
678 (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
679 modep + 1, modep[9] == ' ' ? "" : " ",
680 sp->st_uid, sp->st_gid, path);
681#endif
682 }
683 (void)fflush(stderr);
684
685 first = ch = getchar();
686 while (ch != '\n' && ch != EOF)
687 ch = getchar();
688 return (first == 'y' || first == 'Y');
689}
690
691#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
692static void
693checkdot(char **argv)
694{
695 char *p, **save, **t;
696 int complained;
697
698 complained = 0;
699 for (t = argv; *t;) {
700#ifdef HAVE_DOS_PATHS
701 const char *tmp = p = *t;
702 while (*tmp) {
703 switch (*tmp) {
704 case '/':
705 case '\\':
706 case ':':
707 p = (char *)tmp + 1;
708 break;
709 }
710 tmp++;
711 }
712#else
713 if ((p = strrchr(*t, '/')) != NULL)
714 ++p;
715 else
716 p = *t;
717#endif
718 if (ISDOT(p)) {
719 if (!complained++)
720 fprintf(stderr, "%s: \".\" and \"..\" may not be removed\n", argv0);
721 eval = 1;
722 for (save = t; (t[0] = t[1]) != NULL; ++t)
723 continue;
724 t = save;
725 } else
726 ++t;
727 }
728}
729
730static int
731usage(FILE *pf)
732{
733 fprintf(pf,
734 "usage: %s [options] file ...\n"
735 " or: %s --help\n"
736 " or: %s --version\n"
737 "\n"
738 "Options:\n"
739 " -f\n"
740 " Attempt to remove files without prompting, regardless of the file\n"
741 " permission. Ignore non-existing files. Overrides previous -i's.\n"
742 " -i\n"
743 " Prompt for each file. Always.\n"
744 " -d\n"
745 " Attempt to remove directories as well as other kinds of files.\n"
746 " -P\n"
747 " Overwrite regular files before deleting; three passes: ff,0,ff\n"
748 " -R\n"
749 " Attempt to remove the file hierachy rooted in each file argument.\n"
750 " This option implies -d and file protection.\n"
751 " -v\n"
752 " Be verbose, show files as they are removed.\n"
753 " -W\n"
754 " Undelete without files.\n"
755 " --disable-protection\n"
756 " Will disable the protection file protection applied with -R.\n"
757 " --enable-protection\n"
758 " Will enable the protection file protection applied with -R.\n"
759 " --enable-full-protection\n"
760 " Will enable the protection file protection for all operations.\n"
761 " --disable-full-protection\n"
762 " Will disable the protection file protection for all operations.\n"
763 " --protection-depth\n"
764 " Number or path indicating the file protection depth. Default: %d\n"
765 "\n"
766 "Environment:\n"
767 " KMK_RM_DISABLE_PROTECTION\n"
768 " Same as --disable-protection. Overrides command line.\n"
769 " KMK_RM_ENABLE_PROTECTION\n"
770 " Same as --enable-protection. Overrides everyone else.\n"
771 " KMK_RM_ENABLE_FULL_PROTECTION\n"
772 " Same as --enable-full-protection. Overrides everyone else.\n"
773 " KMK_RM_DISABLE_FULL_PROTECTION\n"
774 " Same as --disable-full-protection. Overrides command line.\n"
775 " KMK_RM_PROTECTION_DEPTH\n"
776 " Same as --protection-depth. Overrides command line.\n"
777 "\n"
778 "The file protection of the top %d layers of the file hierarchy is there\n"
779 "to try prevent makefiles from doing bad things to your system. This\n"
780 "protection is not bulletproof, but should help prevent you from shooting\n"
781 "yourself in the foot.\n"
782 ,
783 g_progname, g_progname, g_progname,
784 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
785 return EX_USAGE;
786}
Note: See TracBrowser for help on using the repository browser.