VirtualBox

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

Last change on this file since 3247 was 3247, checked in by bird, 5 years ago

kmkbuiltin: warnings and build fixes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use