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

Last change on this file since 3101 was 3101, checked in by bird, 7 years ago

rm.c,install.c: GNU/kFreeBSD build fixes (no fflags conversion functions).

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