VirtualBox

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

最後變更 在這個檔案從2466是 2466,由 bird 提交於 14 年 前

kmkbuiltins: More specific error messages (solaris EINTR).

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

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