VirtualBox

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

Last change on this file since 1598 was 1598, checked in by bird, 17 years ago

split out the path protection code from rm.

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

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