VirtualBox

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

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

kmkbuiltin: include config.h

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

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