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

Last change on this file since 3094 was 3062, checked in by bird, 8 years ago

netbsd patches from Uwe. Messing around on arm (arm -> arm32, adding arm64); Adding GNU/kFreeBSD and GNU/kNetBSD to the OS list. Added SuperH to archs. Recognize ppc64le as ppc64 in env.sh. Misc.

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