VirtualBox

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

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

MSC build fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.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 <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#include "kmkbuiltin.h"
67
68#if defined(__EMX__) || defined(_MSC_VER)
69# define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
70# define HAVE_DOS_PATHS 1
71# define DEFAULT_PROTECTION_DEPTH 1
72#else
73# define IS_SLASH(ch) ( (ch) == '/' )
74# undef HAVE_DOS_PATHS
75# define DEFAULT_PROTECTION_DEPTH 2
76#endif
77
78#ifdef __EMX__
79#undef S_IFWHT
80#undef S_ISWHT
81#endif
82#ifndef S_IFWHT
83#define S_IFWHT 0
84#define S_ISWHT(s) 0
85#define undelete(s) (-1)
86#endif
87
88#if !defined(__FreeBSD__) && !defined(__APPLE__)
89extern void strmode(mode_t mode, char *p);
90#endif
91
92static int protectionflag, fullprotectionflag, protectiondepth;
93static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
94static uid_t uid;
95
96static char *argv0;
97
98static struct option long_options[] =
99{
100 { "help", no_argument, 0, 261 },
101 { "version", no_argument, 0, 262 },
102 { "disable-protection", no_argument, 0, 263 },
103 { "enable-protection", no_argument, 0, 264 },
104 { "enable-full-protection", no_argument, 0, 265 },
105 { "disable-full-protection", no_argument, 0, 266 },
106 { "protection-depth", required_argument, 0, 267 },
107 { 0, 0, 0, 0 },
108};
109
110
111static int check(char *, char *, struct stat *);
112static void checkdot(char **);
113static void rm_file(char **);
114static int rm_overwrite(char *, struct stat *);
115static void rm_tree(char **);
116static int count_path_components(const char *);
117static int set_protection_depth(const char *);
118static int usage(FILE *);
119
120
121
122/*
123 * rm --
124 * This rm is different from historic rm's, but is expected to match
125 * POSIX 1003.2 behavior. The most visible difference is that -f
126 * has two specific effects now, ignore non-existent files and force
127 * file removal.
128 */
129int
130kmk_builtin_rm(int argc, char *argv[], char **envp)
131{
132 int ch, rflag;
133 int i;
134
135 /* reinitialize globals */
136 argv0 = argv[0];
137 dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
138 fullprotectionflag = 0;
139 protectionflag = 1;
140 protectiondepth = DEFAULT_PROTECTION_DEPTH;
141 uid = 0;
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 usage(stdout);
183 return 0;
184 case 262:
185 return kbuild_version(argv[0]);
186 case 263:
187 protectionflag = 0;
188 break;
189 case 264:
190 protectionflag = 1;
191 break;
192 case 265:
193 fullprotectionflag = 1;
194 break;
195 case 266:
196 fullprotectionflag = 0;
197 break;
198 case 267:
199 set_protection_depth(optarg);
200 break;
201 case '?':
202 default:
203 return usage(stderr);
204 }
205 argc -= optind;
206 argv += optind;
207
208 if (argc < 1) {
209 if (fflag)
210 return (0);
211 return usage(stderr);
212 }
213
214 /* Search the environment for option overrides (protection). */
215#define STR_SIZE_PAIR(str) str, sizeof(str) - 1
216 for (i = 0; envp[i]; i++) {
217 if (!strncmp(envp[i], "KMK_RM_", sizeof("KMK_RM_") - 1)) {
218 if (!strncmp(envp[i], STR_SIZE_PAIR("KMK_RM_PROTECTION_DEPTH="))) {
219 const char *val = envp[i] + sizeof("KMK_RM_PROTECTION_DEPTH=") - 1;
220 if (set_protection_depth(val))
221 return eval;
222 } else if (!strncmp(envp[i], STR_SIZE_PAIR("KMK_RM_DISABLE_PROTECTION="))) {
223 if (protectionflag >= 0)
224 protectionflag = 0;
225 } else if (!strncmp(envp[i], STR_SIZE_PAIR("KMK_RM_ENABLE_PROTECTION="))) {
226 protectionflag = -1;
227 } else if (!strncmp(envp[i], STR_SIZE_PAIR("KMK_RM_DISABLE_FULL_PROTECTION="))) {
228 if (fullprotectionflag >= 0)
229 fullprotectionflag = 0;
230 } else if (!strncmp(envp[i], STR_SIZE_PAIR("KMK_RM_ENABLE_FULL_PROTECTION="))) {
231 fullprotectionflag = protectionflag = -1;
232 }
233 }
234 }
235 if (fullprotectionflag)
236 protectionflag = 1;
237#undef STR_SIZE_PAIR
238
239 checkdot(argv);
240 uid = geteuid();
241
242 if (*argv) {
243 stdin_ok = isatty(STDIN_FILENO);
244 if (rflag)
245 rm_tree(argv);
246 else
247 rm_file(argv);
248 }
249
250 return eval;
251}
252
253/**
254 * Sets protectiondepth according to the option argument.
255 *
256 * @returns eval, that is 0 on success and non-zero on failure
257 *
258 * @param val The value.
259 */
260static int
261set_protection_depth(const char *val)
262{
263 /* skip leading blanks, they don't count either way. */
264 while (isspace(*val))
265 val++;
266
267 /* number or path? */
268 if (!isdigit(*val) || strpbrk(val, ":/\\")) {
269 protectiondepth = count_path_components(val);
270 } else {
271 char *more = 0;
272 protectiondepth = strtol(val, &more, 0);
273 if (protectiondepth != 0 && more) {
274 /* trailing space is harmless. */
275 while (isspace(*more))
276 more++;
277 }
278 if (!protectiondepth || val == more || *more)
279 return eval = errx(1, "bogus protection depth: %s", val);
280 }
281
282 if (protectiondepth < 1)
283 return eval = errx(1, "bogus protection depth: %s", val);
284 return eval;
285}
286
287/**
288 * Counts the components in the specified sub path.
289 * This is a helper for count_path_components.
290 *
291 * etc = 1
292 * etc/ = 1
293 * etc/x11 = 2
294 * and so and and so forth.
295 */
296static int
297count_sub_path_components(const char *path, int depth)
298{
299 for (;;) {
300 const char *end;
301 size_t len;
302
303 /* skip slashes. */
304 while (IS_SLASH(*path))
305 path++;
306 if (!*path)
307 break;
308
309 /* find end of component. */
310 end = path;
311 while (!IS_SLASH(*end) && *end)
312 end++;
313
314 /* count it, checking for '..' and '.'. */
315 len = end - path;
316 if (len == 2 && path[0] == '.' && path[1] == '.') {
317 if (depth > 0)
318 depth--;
319 } else if (len != 1 || path[0] != '.') {
320 depth++;
321 }
322
323 /* advance */
324 if (!*end)
325 break;
326 path = end + 1;
327 }
328 return depth;
329}
330
331/**
332 * Parses the specified path counting the number of components
333 * relative to root.
334 *
335 * We don't check symbolic links and such, just some simple and cheap
336 * path parsing.
337 *
338 * @param path The path to process.
339 *
340 * @returns 0 or higher on success.
341 * On failure an error is printed, eval is set and -1 is returned.
342 */
343static int
344count_path_components(const char *path)
345{
346 int components = 0;
347
348 /*
349 * Deal with root, UNC, drive letter.
350 */
351#if defined(_MSC_VER) || defined(__OS2__)
352 if (IS_SLASH(path[0]) && IS_SLASH(path[1]) && !IS_SLASH(path[2])) {
353 /* skip the root - UNC */
354 path += 3;
355 while (!IS_SLASH(*path) && *path) /* server name */
356 path++;
357 while (IS_SLASH(*path))
358 path++;
359 while (!IS_SLASH(*path) && *path) /* share name */
360 path++;
361 while (IS_SLASH(*path))
362 path++;
363 } else {
364 unsigned drive_letter = (unsigned)toupper(path[0]) - (unsigned)'A';
365 if (drive_letter <= (unsigned)('Z' - 'A') && path[1] == ':') {
366 drive_letter++; /* A == 1 */
367 } else {
368 drive_letter = 0; /* 0 == default */
369 }
370
371 if (IS_SLASH(path[drive_letter ? 2 : 0])) {
372 /*
373 * Relative path, must count cwd depth first.
374 */
375 char *tmp = _getdcwd(drive_letter, NULL, 32);
376 if (!tmp) {
377 eval = err(1, "_getdcwd");
378 return -1;
379 }
380
381 if (IS_SLASH(tmp[0]) && IS_SLASH(tmp[1])) {
382 /* skip the root - UNC */
383 tmp += 2;
384 while (!IS_SLASH(*tmp) && *tmp) /* server name */
385 tmp++;
386 while (IS_SLASH(*tmp))
387 tmp++;
388 while (!IS_SLASH(*tmp) && *tmp) /* share name */
389 tmp++;
390 } else {
391 /* skip the drive letter and while we're at it, the root slash too. */
392 tmp += 1 + (tmp[1] == ':');
393 }
394 components = count_sub_path_components(tmp, 0);
395 free(tmp);
396 } else {
397 /* skip the drive letter and while we're at it, the root slash too. */
398 path += drive_letter ? 3 : 1;
399 }
400 }
401#else
402 if (!IS_SLASH(path[0])) {
403 /*
404 * Relative path, must count cwd depth first.
405 */
406 char cwd[4096];
407 if (!getcwd(cwd, sizeof(cwd))) {
408 eval = err(1, "getcwd");
409 return -1;
410 }
411 components = count_sub_path_components(cwd, 0);
412 }
413#endif
414
415 /*
416 * We're now past any UNC or drive letter crap, possibly positioned
417 * at the root slash or at the start of a path component at the
418 * given depth. Count the remainder.
419 */
420 return count_sub_path_components(path, components);
421}
422
423
424/**
425 * Protect the upper layers of the file system against accidental
426 * or malicious deletetion attempt from within a makefile.
427 *
428 * @param path The path to check.
429 * @param required_depth The minimum number of components in the
430 * path counting from the root.
431 *
432 * @returns 0 on success.
433 * On failure an error is printed, eval is set and -1 is returned.
434 */
435static int
436enforce_protection(const char *path, int required_depth)
437{
438 int components;
439
440 /*
441 * Count the path and compare it with the required depth.
442 */
443 components = count_path_components(path);
444 if (components < 0)
445 return -1;
446 if (components < required_depth) {
447 eval = errx(1, "%s: protected", path);
448 return -1;
449 }
450 return 0;
451}
452
453static void
454rm_tree(char **argv)
455{
456 FTS *fts;
457 FTSENT *p;
458 int needstat;
459 int flags;
460 int rval;
461
462 /*
463 * Check up front before anything is deleted. This will not catch
464 * everything, but we'll check the individual items later.
465 */
466 if (protectionflag) {
467 int i;
468 for (i = 0; argv[i]; i++) {
469 if (enforce_protection(argv[i], protectiondepth + 1))
470 return;
471 }
472 }
473
474 /*
475 * Remove a file hierarchy. If forcing removal (-f), or interactive
476 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
477 */
478 needstat = !uid || (!fflag && !iflag && stdin_ok);
479
480 /*
481 * If the -i option is specified, the user can skip on the pre-order
482 * visit. The fts_number field flags skipped directories.
483 */
484#define SKIPPED 1
485
486 flags = FTS_PHYSICAL;
487 if (!needstat)
488 flags |= FTS_NOSTAT;
489#ifdef FTS_WHITEOUT
490 if (Wflag)
491 flags |= FTS_WHITEOUT;
492#endif
493 if (!(fts = fts_open(argv, flags, NULL))) {
494 eval = err(1, "fts_open");
495 return;
496 }
497 while ((p = fts_read(fts)) != NULL) {
498 switch (p->fts_info) {
499 case FTS_DNR:
500 if (!fflag || p->fts_errno != ENOENT) {
501 fprintf(stderr, "%s: %s: %s\n",
502 argv0, p->fts_path, strerror(p->fts_errno));
503 eval = 1;
504 }
505 continue;
506 case FTS_ERR:
507 eval = errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
508 fts_close(fts);
509 return;
510 case FTS_NS:
511 /*
512 * Assume that since fts_read() couldn't stat the
513 * file, it can't be unlinked.
514 */
515 if (!needstat)
516 break;
517 if (!fflag || p->fts_errno != ENOENT) {
518 fprintf(stderr, "%s: %s: %s\n",
519 argv0, p->fts_path, strerror(p->fts_errno));
520 eval = 1;
521 }
522 continue;
523 case FTS_D:
524 /* Pre-order: give user chance to skip. */
525 if (!fflag && !check(p->fts_path, p->fts_accpath,
526 p->fts_statp)) {
527 (void)fts_set(fts, p, FTS_SKIP);
528 p->fts_number = SKIPPED;
529 }
530#ifdef UF_APPEND
531 else if (!uid &&
532 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
533 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
534 chflags(p->fts_accpath,
535 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
536 goto err;
537#endif
538 continue;
539 case FTS_DP:
540 /* Post-order: see if user skipped. */
541 if (p->fts_number == SKIPPED)
542 continue;
543 break;
544 default:
545 if (!fflag &&
546 !check(p->fts_path, p->fts_accpath, p->fts_statp))
547 continue;
548 }
549
550 /*
551 * Protect against deleting root files and directories.
552 */
553 if (protectionflag && enforce_protection(p->fts_accpath, protectiondepth + 1)) {
554 fts_close(fts);
555 return;
556 }
557
558 rval = 0;
559#ifdef UF_APPEND
560 if (!uid &&
561 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
562 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
563 rval = chflags(p->fts_accpath,
564 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
565#endif
566 if (rval == 0) {
567 /*
568 * If we can't read or search the directory, may still be
569 * able to remove it. Don't print out the un{read,search}able
570 * message unless the remove fails.
571 */
572 switch (p->fts_info) {
573 case FTS_DP:
574 case FTS_DNR:
575 rval = rmdir(p->fts_accpath);
576 if (rval == 0 || (fflag && errno == ENOENT)) {
577 if (rval == 0 && vflag)
578 (void)printf("%s\n",
579 p->fts_path);
580 continue;
581 }
582 break;
583
584#ifdef FTS_W
585 case FTS_W:
586 rval = undelete(p->fts_accpath);
587 if (rval == 0 && (fflag && errno == ENOENT)) {
588 if (vflag)
589 (void)printf("%s\n",
590 p->fts_path);
591 continue;
592 }
593 break;
594#endif
595
596 case FTS_NS:
597 /*
598 * Assume that since fts_read() couldn't stat
599 * the file, it can't be unlinked.
600 */
601 if (fflag)
602 continue;
603 /* FALLTHROUGH */
604 default:
605 if (Pflag)
606 if (!rm_overwrite(p->fts_accpath, NULL))
607 continue;
608 rval = unlink(p->fts_accpath);
609#ifdef _MSC_VER
610 if (rval != 0) {
611 chmod(p->fts_accpath, 0777);
612 rval = unlink(p->fts_accpath);
613 }
614#endif
615
616 if (rval == 0 || (fflag && errno == ENOENT)) {
617 if (rval == 0 && vflag)
618 (void)printf("%s\n",
619 p->fts_path);
620 continue;
621 }
622 }
623 }
624#ifdef UF_APPEND
625err:
626#endif
627 fprintf(stderr, "%s: %s: %s\n", argv0, p->fts_path, strerror(errno));
628 eval = 1;
629 }
630 if (errno) {
631 fprintf(stderr, "%s: fts_read: %s\n", argv0, strerror(errno));
632 eval = 1;
633 }
634 fts_close(fts);
635}
636
637static void
638rm_file(char **argv)
639{
640 struct stat sb;
641 int rval;
642 char *f;
643
644 /*
645 * Check up front before anything is deleted.
646 */
647 if (fullprotectionflag) {
648 int i;
649 for (i = 0; argv[i]; i++) {
650 if (enforce_protection(argv[i], protectiondepth + 1))
651 return;
652 }
653 }
654
655 /*
656 * Remove a file. POSIX 1003.2 states that, by default, attempting
657 * to remove a directory is an error, so must always stat the file.
658 */
659 while ((f = *argv++) != NULL) {
660 /* Assume if can't stat the file, can't unlink it. */
661 if (lstat(f, &sb)) {
662#ifdef FTS_WHITEOUT
663 if (Wflag) {
664 sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
665 } else {
666#else
667 {
668#endif
669 if (!fflag || errno != ENOENT) {
670 fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(errno));
671 eval = 1;
672 }
673 continue;
674 }
675#ifdef FTS_WHITEOUT
676 } else if (Wflag) {
677 fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(EEXIST));
678 eval = 1;
679 continue;
680#endif
681 }
682
683 if (S_ISDIR(sb.st_mode) && !dflag) {
684 fprintf(stderr, "%s: %s: is a directory\n", argv0, f);
685 eval = 1;
686 continue;
687 }
688 if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
689 continue;
690 rval = 0;
691#ifdef UF_APPEND
692 if (!uid &&
693 (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
694 !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
695 rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
696#endif
697 if (rval == 0) {
698 if (S_ISWHT(sb.st_mode))
699 rval = undelete(f);
700 else if (S_ISDIR(sb.st_mode))
701 rval = rmdir(f);
702 else {
703 if (Pflag)
704 if (!rm_overwrite(f, &sb))
705 continue;
706 rval = unlink(f);
707#ifdef _MSC_VER
708 if (rval != 0) {
709 chmod(f, 0777);
710 rval = unlink(f);
711 }
712#endif
713 }
714 }
715 if (rval && (!fflag || errno != ENOENT)) {
716 fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(errno));
717 eval = 1;
718 }
719 if (vflag && rval == 0)
720 (void)printf("%s\n", f);
721 }
722}
723
724/*
725 * rm_overwrite --
726 * Overwrite the file 3 times with varying bit patterns.
727 *
728 * XXX
729 * This is a cheap way to *really* delete files. Note that only regular
730 * files are deleted, directories (and therefore names) will remain.
731 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
732 * System V file system). In a logging file system, you'll have to have
733 * kernel support.
734 */
735static int
736rm_overwrite(char *file, struct stat *sbp)
737{
738 struct stat sb;
739#ifdef HAVE_FSTATFS
740 struct statfs fsb;
741#endif
742 off_t len;
743 int bsize, fd, wlen;
744 char *buf = NULL;
745
746 fd = -1;
747 if (sbp == NULL) {
748 if (lstat(file, &sb))
749 goto err;
750 sbp = &sb;
751 }
752 if (!S_ISREG(sbp->st_mode))
753 return (1);
754 if ((fd = open(file, O_WRONLY, 0)) == -1)
755 goto err;
756#ifdef HAVE_FSTATFS
757 if (fstatfs(fd, &fsb) == -1)
758 goto err;
759 bsize = MAX(fsb.f_iosize, 1024);
760#elif defined(HAVE_ST_BLKSIZE)
761 bsize = MAX(sb.st_blksize, 1024);
762#else
763 bsize = 1024;
764#endif
765 if ((buf = malloc(bsize)) == NULL)
766 exit(err(1, "%s: malloc", file));
767
768#define PASS(byte) { \
769 memset(buf, byte, bsize); \
770 for (len = sbp->st_size; len > 0; len -= wlen) { \
771 wlen = len < bsize ? len : bsize; \
772 if (write(fd, buf, wlen) != wlen) \
773 goto err; \
774 } \
775}
776 PASS(0xff);
777 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
778 goto err;
779 PASS(0x00);
780 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
781 goto err;
782 PASS(0xff);
783 if (!fsync(fd) && !close(fd)) {
784 free(buf);
785 return (1);
786 }
787
788err: eval = 1;
789 if (buf)
790 free(buf);
791 if (fd != -1)
792 close(fd);
793 fprintf(stderr, "%s: %s: %s\n", argv0, file, strerror(errno));
794 return (0);
795}
796
797
798static int
799check(char *path, char *name, struct stat *sp)
800{
801 int ch, first;
802 char modep[15], *flagsp;
803
804 /* Check -i first. */
805 if (iflag)
806 (void)fprintf(stderr, "remove %s? ", path);
807 else {
808 /*
809 * If it's not a symbolic link and it's unwritable and we're
810 * talking to a terminal, ask. Symbolic links are excluded
811 * because their permissions are meaningless. Check stdin_ok
812 * first because we may not have stat'ed the file.
813 * Also skip this check if the -P option was specified because
814 * we will not be able to overwrite file contents and will
815 * barf later.
816 */
817 if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag ||
818 (!access(name, W_OK) &&
819#ifdef SF_APPEND
820 !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
821 (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))
822#else
823 1)
824#endif
825 )
826 return (1);
827 strmode(sp->st_mode, modep);
828#ifdef SF_APPEND
829 if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
830 exit(err(1, "fflagstostr"));
831 (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
832 modep + 1, modep[9] == ' ' ? "" : " ",
833 user_from_uid(sp->st_uid, 0),
834 group_from_gid(sp->st_gid, 0),
835 *flagsp ? flagsp : "", *flagsp ? " " : "",
836 path);
837 free(flagsp);
838#else
839 (void)flagsp;
840 (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
841 modep + 1, modep[9] == ' ' ? "" : " ",
842 sp->st_uid, sp->st_gid, path);
843#endif
844 }
845 (void)fflush(stderr);
846
847 first = ch = getchar();
848 while (ch != '\n' && ch != EOF)
849 ch = getchar();
850 return (first == 'y' || first == 'Y');
851}
852
853#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
854static void
855checkdot(char **argv)
856{
857 char *p, **save, **t;
858 int complained;
859
860 complained = 0;
861 for (t = argv; *t;) {
862#ifdef HAVE_DOS_PATHS
863 const char *tmp = p = *t;
864 while (*tmp) {
865 switch (*tmp) {
866 case '/':
867 case '\\':
868 case ':':
869 p = (char *)tmp + 1;
870 break;
871 }
872 tmp++;
873 }
874#else
875 if ((p = strrchr(*t, '/')) != NULL)
876 ++p;
877 else
878 p = *t;
879#endif
880 if (ISDOT(p)) {
881 if (!complained++)
882 fprintf(stderr, "%s: \".\" and \"..\" may not be removed\n", argv0);
883 eval = 1;
884 for (save = t; (t[0] = t[1]) != NULL; ++t)
885 continue;
886 t = save;
887 } else
888 ++t;
889 }
890}
891
892static int
893usage(FILE *pf)
894{
895 fprintf(pf,
896 "usage: %s [options] file ...\n"
897 " or: %s --help\n"
898 " or: %s --version\n"
899 "\n"
900 "Options:\n"
901 " -f\n"
902 " Attempt to remove files without prompting, regardless of the file\n"
903 " permission. Ignore non-existing files. Overrides previous -i's.\n"
904 " -i\n"
905 " Prompt for each file. Always.\n"
906 " -d\n"
907 " Attempt to remove directories as well as other kinds of files.\n"
908 " -P\n"
909 " Overwrite regular files before deleting; three passes: ff,0,ff\n"
910 " -R\n"
911 " Attempt to remove the file hierachy rooted in each file argument.\n"
912 " This option implies -d and file protection.\n"
913 " -v\n"
914 " Be verbose, show files as they are removed.\n"
915 " -W\n"
916 " Undelete without files.\n"
917 " --disable-protection\n"
918 " Will disable the protection file protection applied with -R.\n"
919 " --enable-protection\n"
920 " Will enable the protection file protection applied with -R.\n"
921 " --enable-full-protection\n"
922 " Will enable the protection file protection for all operations.\n"
923 " --disable-full-protection\n"
924 " Will disable the protection file protection for all operations.\n"
925 " --protection-depth\n"
926 " Number or path indicating the file protection depth. Default: %d\n"
927 "\n"
928 "Environment:\n"
929 " KMK_RM_DISABLE_PROTECTION\n"
930 " Same as --disable-protection. Overrides command line.\n"
931 " KMK_RM_ENABLE_PROTECTION\n"
932 " Same as --enable-protection. Overrides everyone else.\n"
933 " KMK_RM_ENABLE_FULL_PROTECTION\n"
934 " Same as --enable-full-protection. Overrides everyone else.\n"
935 " KMK_RM_DISABLE_FULL_PROTECTION\n"
936 " Same as --disable-full-protection. Overrides command line.\n"
937 " KMK_RM_PROTECTION_DEPTH\n"
938 " Same as --protection-depth. Overrides command line.\n"
939 "\n"
940 "The file protection of the top %d layers of the file hierarchy is there\n"
941 "to try prevent makefiles from doing bad things to your system. This\n"
942 "protection is not bulletproof, but should help prevent you from shooting\n"
943 "yourself in the foot.\n"
944 ,
945 g_progname, g_progname, g_progname,
946 DEFAULT_PROTECTION_DEPTH, DEFAULT_PROTECTION_DEPTH);
947 return EX_USAGE;
948}
Note: See TracBrowser for help on using the repository browser.

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