VirtualBox

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

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

Compile fix and workaround for broken _getdcwd (see libc ticket #194).

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