VirtualBox

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

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

removed a leftover prototype.

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