VirtualBox

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

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

kmk: Make sure we use our fts.h, never the system one (except OS/2).

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

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