File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #ifdef HAVE_CONFIG_H
0031 #include "config.h"
0032 #endif
0033
0034 #if 0
0035 #ifndef lint
0036 static const char copyright[] =
0037 "@(#) Copyright (c) 1990, 1993, 1994\n\
0038 The Regents of the University of California. All rights reserved.\n";
0039 #endif
0040
0041 #ifndef lint
0042 static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94";
0043 #endif
0044 #endif
0045 #if 0
0046 #include <sys/cdefs.h>
0047 __FBSDID("$FreeBSD: src/bin/rm/rm.c,v 1.58 2006/10/31 02:22:36 delphij Exp $");
0048 #endif
0049
0050 #include <rtems.h>
0051 #include <rtems/inttypes.h>
0052 #include <rtems/shell.h>
0053 #include <rtems/shellconfig.h>
0054 #define __need_getopt_newlib
0055 #include <getopt.h>
0056
0057 #include <sys/stat.h>
0058 #include <sys/param.h>
0059
0060 #include "err.h"
0061 #include <errno.h>
0062 #include <fcntl.h>
0063 #include "fts.h"
0064 #include <grp.h>
0065 #include <pwd.h>
0066 #include <stdio.h>
0067 #include <stdlib.h>
0068 #include <string.h>
0069 #include <unistd.h>
0070
0071 #include "internal.h"
0072
0073 #define rindex(s,c) strrchr(s,c)
0074
0075
0076 typedef struct {
0077 int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
0078 int rflag, Iflag;
0079 uid_t uid;
0080 int exit_code;
0081 jmp_buf exit_jmp;
0082 } rtems_shell_rm_globals;
0083
0084 #define dflag globals->dflag
0085 #define eval globals->eval
0086 #define fflag globals->fflag
0087 #define iflag globals->iflag
0088 #define Pflag globals->Pflag
0089 #define vflag globals->vflag
0090 #define Wflag globals->Wflag
0091 #define stdin_ok globals->stdin_ok
0092 #define rflag globals->rflag
0093 #define Iflag globals->Iflag
0094 #define xuid globals->uid
0095 #define exit_jump &(globals->exit_jmp)
0096
0097 #include <setjmp.h>
0098
0099 #define exit(ec) rtems_shell_rm_exit(globals, ec)
0100 static void
0101 rtems_shell_rm_exit (rtems_shell_rm_globals* globals, int code)
0102 {
0103 globals->exit_code = code;
0104 longjmp (globals->exit_jmp, 1);
0105 }
0106
0107 static int main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[]);
0108
0109 int
0110 rtems_shell_main_rm(int argc, char *argv[])
0111 {
0112 rtems_shell_rm_globals rm_globals;
0113 memset (&rm_globals, 0, sizeof (rm_globals));
0114 rm_globals.exit_code = 1;
0115 if (setjmp (rm_globals.exit_jmp) == 0)
0116 return main_rm (&rm_globals, argc, argv);
0117 return rm_globals.exit_code;
0118 }
0119
0120 #define check(a1, a2, a3) check_rm(globals, a1, a2, a3)
0121 #define check2(a1) check2_rm(globals, a1)
0122 #define checkdot(a1) checkdot_rm(globals, a1)
0123 #define checkslash(a1) checkslash_rm(globals, a1)
0124 #define rm_file(a1) rm_file_rm(globals, a1)
0125 #define rm_overwrite(a1, a2) rm_overwrite_rm(globals, a1, a2)
0126 #define rm_tree(a1) rm_tree_rm(globals, a1)
0127 #define usage() usage_rm(globals)
0128
0129
0130
0131
0132 static int check_rm(rtems_shell_rm_globals* globals, char *, char *, struct stat *);
0133 static int check2_rm(rtems_shell_rm_globals* globals, char **);
0134 static void checkdot_rm(rtems_shell_rm_globals* globals, char **);
0135 static void checkslash_rm(rtems_shell_rm_globals* globals, char **);
0136 static void rm_file_rm(rtems_shell_rm_globals* globals, char **);
0137 static int rm_overwrite_rm(rtems_shell_rm_globals* globals, char *, struct stat *);
0138 static void rm_tree_rm(rtems_shell_rm_globals* globals, char **);
0139 static void usage_rm(rtems_shell_rm_globals* globals);
0140
0141
0142
0143
0144
0145
0146
0147
0148 int
0149 main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[])
0150 {
0151 int ch;
0152 char *p;
0153
0154 struct getopt_data getopt_reent;
0155 memset(&getopt_reent, 0, sizeof(getopt_data));
0156
0157
0158
0159
0160
0161
0162 if ((p = rindex(argv[0], '/')) == NULL)
0163 p = argv[0];
0164 else
0165 ++p;
0166 if (strcmp(p, "unlink") == 0) {
0167 while (getopt_r(argc, argv, "", &getopt_reent) != -1)
0168 usage();
0169 argc -= getopt_reent.optind;
0170 argv += getopt_reent.optind;
0171 if (argc != 1)
0172 usage();
0173 rm_file(&argv[0]);
0174 exit(eval);
0175 }
0176
0177 Pflag = rflag = 0;
0178 while ((ch = getopt_r(argc, argv, "dfiIPRrvW", &getopt_reent)) != -1)
0179 switch(ch) {
0180 case 'd':
0181 dflag = 1;
0182 break;
0183 case 'f':
0184 fflag = 1;
0185 iflag = 0;
0186 break;
0187 case 'i':
0188 fflag = 0;
0189 iflag = 1;
0190 break;
0191 case 'I':
0192 Iflag = 1;
0193 break;
0194 case 'P':
0195 Pflag = 1;
0196 break;
0197 case 'R':
0198 case 'r':
0199 rflag = 1;
0200 break;
0201 case 'v':
0202 vflag = 1;
0203 break;
0204 case 'W':
0205 Wflag = 1;
0206 break;
0207 default:
0208 usage();
0209 }
0210 argc -= getopt_reent.optind;
0211 argv += getopt_reent.optind;
0212
0213 if (argc < 1) {
0214 if (fflag)
0215 return (0);
0216 usage();
0217 }
0218
0219 checkdot(argv);
0220 if (getenv("POSIXLY_CORRECT") == NULL)
0221 checkslash(argv);
0222 xuid = geteuid();
0223
0224 if (*argv) {
0225 stdin_ok = isatty(STDIN_FILENO);
0226
0227 if (Iflag) {
0228 if (check2(argv) == 0)
0229 exit (1);
0230 }
0231 if (rflag)
0232 rm_tree(argv);
0233 else
0234 rm_file(argv);
0235 }
0236
0237 exit (eval);
0238 return 0;
0239 }
0240
0241 void
0242 rm_tree_rm(rtems_shell_rm_globals* globals, char **argv)
0243 {
0244 FTS *fts;
0245 FTSENT *p;
0246 int needstat;
0247 int flags;
0248 int rval;
0249
0250
0251
0252
0253
0254 needstat = !xuid || (!fflag && !iflag && stdin_ok);
0255
0256
0257
0258
0259
0260 #define SKIPPED 1
0261
0262 flags = FTS_PHYSICAL;
0263 if (!needstat)
0264 flags |= FTS_NOSTAT;
0265 if (Wflag)
0266 flags |= FTS_WHITEOUT;
0267 if (!(fts = fts_open(argv, flags, NULL))) {
0268 if (fflag && errno == ENOENT)
0269 return;
0270 err(exit_jump, 1, "fts_open");
0271 }
0272 while ((p = fts_read(fts)) != NULL) {
0273 switch (p->fts_info) {
0274 case FTS_DNR:
0275 if (!fflag || p->fts_errno != ENOENT) {
0276 warnx("%s: %s",
0277 p->fts_path, strerror(p->fts_errno));
0278 eval = 1;
0279 }
0280 continue;
0281 case FTS_ERR:
0282 errx(exit_jump, 1, "%s: %s", p->fts_path, strerror(p->fts_errno));
0283 case FTS_NS:
0284
0285
0286
0287
0288 if (!needstat)
0289 break;
0290 if (!fflag || p->fts_errno != ENOENT) {
0291 warnx("%s: %s",
0292 p->fts_path, strerror(p->fts_errno));
0293 eval = 1;
0294 }
0295 continue;
0296 case FTS_D:
0297
0298 if (!fflag && !check(p->fts_path, p->fts_accpath,
0299 p->fts_statp)) {
0300 (void)fts_set(fts, p, FTS_SKIP);
0301 p->fts_number = SKIPPED;
0302 }
0303 #if RTEMS_REMOVED
0304 else if (!xuid &&
0305 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
0306 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
0307 chflags(p->fts_accpath,
0308 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
0309 goto err;
0310 #endif
0311 continue;
0312 case FTS_DP:
0313
0314 if (p->fts_number == SKIPPED)
0315 continue;
0316 break;
0317 default:
0318 if (!fflag &&
0319 !check(p->fts_path, p->fts_accpath, p->fts_statp))
0320 continue;
0321 }
0322
0323 rval = 0;
0324 #if RTEMS_REMOVED
0325 if (!xuid &&
0326 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
0327 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
0328 rval = chflags(p->fts_accpath,
0329 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
0330 #endif
0331 if (rval == 0) {
0332
0333
0334
0335
0336
0337 switch (p->fts_info) {
0338 case FTS_DP:
0339 case FTS_DNR:
0340 rval = rmdir(p->fts_accpath);
0341 if (rval == 0 || (fflag && errno == ENOENT)) {
0342 if (rval == 0 && vflag)
0343 (void)printf("%s\n",
0344 p->fts_path);
0345 continue;
0346 }
0347 break;
0348
0349 #if RTEMS_REMOVED
0350 case FTS_W:
0351 rval = undelete(p->fts_accpath);
0352 if (rval == 0 && (fflag && errno == ENOENT)) {
0353 if (vflag)
0354 (void)printf("%s\n",
0355 p->fts_path);
0356 continue;
0357 }
0358 break;
0359 #endif
0360
0361 case FTS_NS:
0362
0363
0364
0365
0366 if (fflag)
0367 continue;
0368
0369 default:
0370 if (Pflag)
0371 if (!rm_overwrite(p->fts_accpath, NULL))
0372 continue;
0373 rval = unlink(p->fts_accpath);
0374 if (rval == 0 || (fflag && errno == ENOENT)) {
0375 if (rval == 0 && vflag)
0376 (void)printf("%s\n",
0377 p->fts_path);
0378 continue;
0379 }
0380 }
0381 }
0382 #if RTEMS_REMOVED
0383 err:
0384 #endif
0385 warn("%s", p->fts_path);
0386 eval = 1;
0387 }
0388 if (errno)
0389 err(exit_jump, 1, "fts_read");
0390 fts_close(fts);
0391 }
0392
0393 #define S_ISWHT(m) (0)
0394
0395 void
0396 rm_file_rm(rtems_shell_rm_globals* globals, char **argv)
0397 {
0398 struct stat sb;
0399 int rval;
0400 char *f;
0401
0402
0403
0404
0405
0406 while ((f = *argv++) != NULL) {
0407
0408 if (lstat(f, &sb)) {
0409 #if RTEMS_REMOVED
0410 if (Wflag) {
0411 sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
0412 } else {
0413 #endif
0414 if (!fflag || errno != ENOENT) {
0415 warn("%s", f);
0416 eval = 1;
0417 }
0418 continue;
0419 #if RTEMS_REMOVED
0420 }
0421 #endif
0422 } else if (Wflag) {
0423 warnx("%s: %s", f, strerror(EEXIST));
0424 eval = 1;
0425 continue;
0426 }
0427
0428 if (S_ISDIR(sb.st_mode) && !dflag) {
0429 warnx("%s: is a directory", f);
0430 eval = 1;
0431 continue;
0432 }
0433 if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
0434 continue;
0435 rval = 0;
0436 #if RTEMS_REMOVED
0437 if (!xuid && !S_ISWHT(sb.st_mode) &&
0438 (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
0439 !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
0440 rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
0441 #endif
0442 if (rval == 0) {
0443 if (S_ISWHT(sb.st_mode))
0444 #if RTEMS_REMOVED
0445 rval = undelete(f);
0446 #endif
0447 ;
0448 else if (S_ISDIR(sb.st_mode))
0449 rval = rmdir(f);
0450 else {
0451 if (Pflag)
0452 if (!rm_overwrite(f, &sb))
0453 continue;
0454 rval = unlink(f);
0455 }
0456 }
0457 if (rval && (!fflag || errno != ENOENT)) {
0458 warn("%s", f);
0459 eval = 1;
0460 }
0461 if (vflag && rval == 0)
0462 (void)printf("%s\n", f);
0463 }
0464 }
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477 int
0478 rm_overwrite_rm(rtems_shell_rm_globals* globals, char *file, struct stat *sbp)
0479 {
0480 struct stat sb;
0481 #if RTEMS_REMOVED
0482 struct statfs fsb;
0483 #endif
0484 off_t len;
0485 int bsize, fd, wlen;
0486 char *buf = NULL;
0487
0488 fd = -1;
0489 if (sbp == NULL) {
0490 if (lstat(file, &sb))
0491 goto err;
0492 sbp = &sb;
0493 }
0494 if (!S_ISREG(sbp->st_mode))
0495 return (1);
0496 if (sbp->st_nlink > 1 && !fflag) {
0497 warnx("%s (inode %" PRIuino_t
0498 "): not overwritten due to multiple links", file,
0499 sbp->st_ino);
0500 return (0);
0501 }
0502 if ((fd = open(file, O_WRONLY, 0)) == -1)
0503 goto err;
0504 #if RTEMS_REMOVED
0505 if (fstatfs(fd, &fsb) == -1)
0506 goto err;
0507 bsize = MAX(fsb.f_iosize, 1024);
0508 #endif
0509 bsize = 1024;
0510 if ((buf = malloc(bsize)) == NULL)
0511 err(exit_jump, 1, "%s: malloc", file);
0512
0513 #define PASS(byte) { \
0514 memset(buf, byte, bsize); \
0515 for (len = sbp->st_size; len > 0; len -= wlen) { \
0516 wlen = len < bsize ? len : bsize; \
0517 if (write(fd, buf, wlen) != wlen) \
0518 goto err; \
0519 } \
0520 }
0521 PASS(0xff);
0522 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
0523 goto err;
0524 PASS(0x00);
0525 if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
0526 goto err;
0527 PASS(0xff);
0528 if (!fsync(fd) && !close(fd)) {
0529 free(buf);
0530 return (1);
0531 }
0532
0533 err: eval = 1;
0534 if (buf)
0535 free(buf);
0536 if (fd != -1)
0537 close(fd);
0538 warn("%s", file);
0539 return (0);
0540 }
0541
0542 #if RTEMS_REMOVED
0543 char *fflagstostr(u_long flags);
0544 #endif
0545
0546 int
0547 check_rm(rtems_shell_rm_globals* globals, char *path, char *name, struct stat *sp)
0548 {
0549 int ch, first;
0550 char modep[15], *flagsp;
0551
0552
0553 if (iflag)
0554 (void)fprintf(stderr, "remove %s? ", path);
0555 else {
0556
0557
0558
0559
0560
0561
0562 #if RTEMS_REMOVED
0563 if (!stdin_ok || S_ISLNK(sp->st_mode) ||
0564 (!access(name, W_OK) &&
0565 !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
0566 (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !xuid)))
0567 #endif
0568 if (!stdin_ok || S_ISLNK(sp->st_mode) ||
0569 (!access(name, W_OK)))
0570 return (1);
0571 strmode(sp->st_mode, modep);
0572 #if RTEMS_REMOVED
0573 if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
0574 err(exit_jump, 1, "fflagstostr");
0575 #else
0576 flagsp = "no supported";
0577 #endif
0578 if (Pflag)
0579 errx(exit_jump, 1,
0580 "%s: -P was specified, but file is not writable",
0581 path);
0582 (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
0583 modep + 1, modep[9] == ' ' ? "" : " ",
0584 user_from_uid(sp->st_uid, 0),
0585 group_from_gid(sp->st_gid, 0),
0586 *flagsp ? flagsp : "", *flagsp ? " " : "",
0587 path);
0588 #if RTEMS_REMOVED
0589 free(flagsp);
0590 #endif
0591 }
0592 (void)fflush(stderr);
0593
0594 first = ch = getchar();
0595 while (ch != '\n' && ch != EOF)
0596 ch = getchar();
0597 return (first == 'y' || first == 'Y');
0598 }
0599
0600 #define ISSLASH(a) ((a)[0] == '/' && (a)[1] == '\0')
0601 void
0602 checkslash_rm(rtems_shell_rm_globals* globals, char **argv)
0603 {
0604 char **t, **u;
0605 int complained;
0606
0607 complained = 0;
0608 for (t = argv; *t;) {
0609 if (ISSLASH(*t)) {
0610 if (!complained++)
0611 warnx("\"/\" may not be removed");
0612 eval = 1;
0613 for (u = t; u[0] != NULL; ++u)
0614 u[0] = u[1];
0615 } else {
0616 ++t;
0617 }
0618 }
0619 }
0620
0621 int
0622 check2_rm(rtems_shell_rm_globals* globals, char **argv)
0623 {
0624 struct stat st;
0625 int first;
0626 int ch;
0627 int fcount = 0;
0628 int dcount = 0;
0629 int i;
0630 const char *dname = NULL;
0631
0632 for (i = 0; argv[i]; ++i) {
0633 if (lstat(argv[i], &st) == 0) {
0634 if (S_ISDIR(st.st_mode)) {
0635 ++dcount;
0636 dname = argv[i];
0637 } else {
0638 ++fcount;
0639 }
0640 }
0641 }
0642 first = 0;
0643 while (first != 'n' && first != 'N' && first != 'y' && first != 'Y') {
0644 if (dcount && rflag) {
0645 fprintf(stderr, "recursively remove");
0646 if (dcount == 1)
0647 fprintf(stderr, " %s", dname);
0648 else
0649 fprintf(stderr, " %d dirs", dcount);
0650 if (fcount == 1)
0651 fprintf(stderr, " and 1 file");
0652 else if (fcount > 1)
0653 fprintf(stderr, " and %d files", fcount);
0654 } else if (dcount + fcount > 3) {
0655 fprintf(stderr, "remove %d files", dcount + fcount);
0656 } else {
0657 return(1);
0658 }
0659 fprintf(stderr, "? ");
0660 fflush(stderr);
0661
0662 first = ch = getchar();
0663 while (ch != '\n' && ch != EOF)
0664 ch = getchar();
0665 if (ch == EOF)
0666 break;
0667 }
0668 return (first == 'y' || first == 'Y');
0669 }
0670
0671 #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
0672 void
0673 checkdot_rm(rtems_shell_rm_globals* globals, char **argv)
0674 {
0675 char *p, **save, **t;
0676 int complained;
0677
0678 complained = 0;
0679 for (t = argv; *t;) {
0680 if ((p = strrchr(*t, '/')) != NULL)
0681 ++p;
0682 else
0683 p = *t;
0684 if (ISDOT(p)) {
0685 if (!complained++)
0686 warnx("\".\" and \"..\" may not be removed");
0687 eval = 1;
0688 for (save = t; (t[0] = t[1]) != NULL; ++t)
0689 continue;
0690 t = save;
0691 } else
0692 ++t;
0693 }
0694 }
0695
0696 void
0697 usage_rm(rtems_shell_rm_globals* globals)
0698 {
0699
0700 (void)fprintf(stderr, "%s\n%s\n",
0701 "usage: rm [-f | -i] [-dIPRrvW] file ...",
0702 " unlink file");
0703 exit(1);
0704 }
0705
0706 rtems_shell_cmd_t rtems_shell_RM_Command = {
0707 "rm",
0708 "[-f | -i] [-dIPRrvW] file ...",
0709 "files",
0710 rtems_shell_main_rm,
0711 NULL,
0712 NULL
0713 };