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

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

minor cleanup.

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