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

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

Fixed warning.

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