Print this page
4815 Want rm support for -v option
4816 rm does not print error messages when -f is used

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/rm/rm.c
          +++ new/usr/src/cmd/rm/rm.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
       23 + * Copyright 2014 Andrew Stormont.
       24 + */
       25 +
       26 +/*
  23   27   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   28   * Use is subject to license terms.
  25   29   */
  26   30  
  27   31  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  28   32  /*      All Rights Reserved   */
  29   33  
  30   34  /*
  31      - * rm [-fiRr] file ...
       35 + * rm [-fiRrv] file ...
  32   36   */
  33   37  
  34   38  #include <sys/param.h>
  35   39  #include <sys/stat.h>
  36   40  #include <dirent.h>
  37   41  #include <errno.h>
  38   42  #include <fcntl.h>
  39   43  #include <langinfo.h>
  40   44  #include <limits.h>
  41   45  #include <locale.h>
↓ open down ↓ 25 lines elided ↑ open up ↑
  67   71          (int)AT_FDCWD,
  68   72          DIR_CANTCLOSE,
  69   73  };
  70   74  
  71   75  static struct dlist *cur, *rec;
  72   76  
  73   77  static int rm(const char *, struct dlist *);
  74   78  static int confirm(FILE *, const char *, ...);
  75   79  static void memerror(void);
  76   80  static int checkdir(struct dlist *, struct dlist *);
  77      -static int errcnt;
  78      -static boolean_t silent, interactive, recursive, ontty;
       81 +static int errcnt = 0;
       82 +
       83 +static boolean_t force = B_FALSE;
       84 +static boolean_t interactive = B_FALSE;
       85 +static boolean_t recursive = B_FALSE;
       86 +static boolean_t ontty = B_FALSE;
       87 +static boolean_t verbose = B_FALSE;
  79   88  
  80   89  static char *pathbuf;
  81   90  static size_t pathbuflen = MAXPATHLEN;
  82   91  
  83   92  static int maxfds = MAXINT;
  84   93  static int nfds;
  85   94  
  86   95  int
  87   96  main(int argc, char **argv)
  88   97  {
  89   98          int errflg = 0;
  90   99          int c;
  91  100  
  92  101          (void) setlocale(LC_ALL, "");
  93  102  #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
  94  103  #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
  95  104  #endif
  96  105          (void) textdomain(TEXT_DOMAIN);
  97  106  
  98      -        while ((c = getopt(argc, argv, "frRi")) != EOF)
      107 +        while ((c = getopt(argc, argv, "frRiv")) != EOF)
  99  108                  switch (c) {
 100  109                  case 'f':
 101      -                        silent = B_TRUE;
 102      -#ifdef XPG4
      110 +                        force = B_TRUE;
 103  111                          interactive = B_FALSE;
 104      -#endif
 105  112                          break;
 106  113                  case 'i':
 107  114                          interactive = B_TRUE;
 108      -#ifdef XPG4
 109      -                        silent = B_FALSE;
 110      -#endif
      115 +                        force = B_FALSE;
 111  116                          break;
 112  117                  case 'r':
 113  118                  case 'R':
 114  119                          recursive = B_TRUE;
 115  120                          break;
      121 +                case 'v':
      122 +                        verbose = B_TRUE;
      123 +                        break;
 116  124                  case '?':
 117  125                          errflg = 1;
 118  126                          break;
 119  127                  }
 120  128  
 121  129          /*
 122  130           * For BSD compatibility allow '-' to delimit the end
 123  131           * of options.  However, if options were already explicitly
 124  132           * terminated with '--', then treat '-' literally: otherwise,
 125  133           * "rm -- -" won't remove '-'.
 126  134           */
 127  135          if (optind < argc &&
 128  136              strcmp(argv[optind], "-") == 0 &&
 129  137              strcmp(argv[optind - 1], "--") != 0)
 130  138                  optind++;
 131  139  
 132  140          argc -= optind;
 133  141          argv = &argv[optind];
 134  142  
 135      -        if ((argc < 1 && !silent) || errflg) {
 136      -                (void) fprintf(stderr, gettext("usage: rm [-fiRr] file ...\n"));
      143 +        if ((argc < 1 && !force) || errflg) {
      144 +                (void) fprintf(stderr,
      145 +                    gettext("usage: rm [-fiRrv] file ...\n"));
 137  146                  exit(2);
 138  147          }
 139  148  
 140  149          ontty = isatty(STDIN_FILENO) != 0;
 141  150  
 142  151          if (recursive && stat("/", &rootdir) != 0) {
 143  152                  (void) fprintf(stderr,
 144  153                      gettext("rm: cannot stat root directory: %s\n"),
 145  154                      strerror(errno));
 146  155                  exit(2);
↓ open down ↓ 174 lines elided ↑ open up ↑
 321  330  
 322  331          /*
 323  332           * Construct the pathname: note that the entry may live in memory
 324  333           * allocated by readdir and that after return from recursion
 325  334           * the memory is no longer valid.  So after the recursive rm()
 326  335           * call, we use the global pathbuf instead of the entry argument.
 327  336           */
 328  337          pushfilename(entry);
 329  338  
 330  339          if (fstatat(caller->fd, entry, &temp, AT_SYMLINK_NOFOLLOW) != 0) {
 331      -                if (!silent) {
 332      -                        (void) fprintf(stderr, "rm: %s: %s\n", pathbuf,
 333      -                            strerror(errno));
 334      -                        errcnt++;
 335      -                }
      340 +                (void) fprintf(stderr, "rm: %s: %s\n", pathbuf,
      341 +                    strerror(errno));
      342 +                errcnt++;
 336  343                  return (0);
 337  344          }
 338  345  
 339  346          if (S_ISDIR(temp.st_mode)) {
 340  347                  /*
 341  348                   * If "-r" wasn't specified, trying to remove directories
 342  349                   * is an error.
 343  350                   */
 344  351                  if (!recursive) {
 345  352                          (void) fprintf(stderr,
↓ open down ↓ 22 lines elided ↑ open up ↑
 368  375                      gettext("rm: examine files in directory %s (%s/%s)? "),
 369  376                      pathbuf, yesstr, nostr)) {
 370  377                          return (0);
 371  378                  }
 372  379  
 373  380                  frame.dev = temp.st_dev;
 374  381                  frame.ino = temp.st_ino;
 375  382                  frame.flags = 0;
 376  383                  flag = AT_REMOVEDIR;
 377  384  
 378      -#ifdef XPG4
      385 +#ifndef SUS
 379  386                  /*
 380  387                   * XCU4 and POSIX.2: If not interactive, check to see whether
 381  388                   * or not directory is readable or writable and if not,
 382  389                   * prompt user for response.
 383  390                   */
 384      -                if (ontty && !interactive && !silent &&
      391 +                if (ontty && !interactive && !force &&
 385  392                      faccessat(caller->fd, entry, W_OK|X_OK, AT_EACCESS) != 0 &&
 386  393                      !confirm(stderr,
 387  394                      gettext("rm: examine files in directory %s (%s/%s)? "),
 388  395                      pathbuf, yesstr, nostr)) {
 389  396                          return (0);
 390  397                  }
 391  398  #endif
      399 +
 392  400                  if (opendirat(caller->fd, entry, &frame) == -1) {
 393  401                          err = errno;
 394  402  
 395  403                          if (interactive) {
 396  404                                  /*
 397  405                                   * Print an error message that
 398  406                                   * we could not read the directory
 399  407                                   * as the user wanted to examine
 400  408                                   * files in the directory.  Only
 401  409                                   * affect the error status if
↓ open down ↓ 16 lines elided ↑ open up ↑
 418  426   * where j=ja, n=nein, <filename>=the file to be removed
 419  427   */
 420  428                                  if (!confirm(stderr,
 421  429                                      gettext("rm: remove %s (%s/%s)? "),
 422  430                                      pathbuf, yesstr, nostr)) {
 423  431                                          errcnt++;
 424  432                                          return (0);
 425  433                                  }
 426  434                          }
 427  435                          /* If it's empty we may still be able to rm it */
 428      -                        if (unlinkat(caller->fd, entry, flag) == 0)
      436 +                        if (unlinkat(caller->fd, entry, flag) == 0) {
      437 +                                if (verbose)
      438 +                                        (void) printf(gettext("removed "
      439 +                                            "directory: `%s'\n"), pathbuf);
 429  440                                  return (0);
      441 +                        }
 430  442                          if (interactive)
 431  443                                  err = errno;
 432  444                          (void) fprintf(stderr,
 433  445                              interactive ?
 434  446                              gettext("rm: Unable to remove directory %s: %s\n") :
 435  447                              gettext("rm: cannot read directory %s: %s\n"),
 436  448                              pathbuf, strerror(err));
 437  449                          errcnt++;
 438  450                          return (0);
 439  451                  }
↓ open down ↓ 51 lines elided ↑ open up ↑
 491  503          }
 492  504  unlinkit:
 493  505          /*
 494  506           * If interactive, ask for acknowledgement.
 495  507           */
 496  508          if (interactive) {
 497  509                  if (!confirm(stderr, gettext("rm: remove %s (%s/%s)? "),
 498  510                      pathbuf, yesstr, nostr)) {
 499  511                          return (0);
 500  512                  }
 501      -        } else if (!silent && flag == 0) {
      513 +        } else if (!force && flag == 0) {
 502  514                  /*
 503      -                 * If not silent, and stdin is a terminal, and there's
      515 +                 * If not force, and stdin is a terminal, and there's
 504  516                   * no write access, and the file isn't a symbolic link,
 505  517                   * ask for permission.  If flag is set, then we know it's
 506  518                   * a directory so we skip this test as it was done above.
 507  519                   *
 508  520                   * TRANSLATION_NOTE - The following message will contain the
 509  521                   * first character of the strings for "yes" and "no" defined
 510  522                   * in the file "nl_langinfo.po".  After substitution, the
 511  523                   * message will appear as follows:
 512  524                   *      rm: <filename>: override protection XXX (y/n)?
 513  525                   * where XXX is the permission mode bits of the file in octal
↓ open down ↓ 2 lines elided ↑ open up ↑
 516  528                   */
 517  529                  if (ontty && !S_ISLNK(temp.st_mode) &&
 518  530                      faccessat(caller->fd, entry, W_OK, AT_EACCESS) != 0 &&
 519  531                      !confirm(stdout,
 520  532                      gettext("rm: %s: override protection %o (%s/%s)? "),
 521  533                      pathbuf, temp.st_mode & 0777, yesstr, nostr)) {
 522  534                          return (0);
 523  535                  }
 524  536          }
 525  537  
 526      -        if (unlinkat(caller->fd, entry, flag) != 0) {
      538 +        if (unlinkat(caller->fd, entry, flag) == 0) {
      539 +                if (verbose)
      540 +                        (void) printf(S_ISDIR(temp.st_mode) ?
      541 +                            gettext("removed directory: `%s'\n") :
      542 +                            gettext("removed `%s'\n"), pathbuf);
      543 +                return (0);
      544 +        } else {
 527  545                  err = errno;
 528  546                  if (err == ENOENT)
 529  547                          return (0);
 530  548  
 531  549                  if (flag != 0) {
 532  550                          if (err == EINVAL) {
 533  551                                  (void) fprintf(stderr, gettext(
 534  552                                      "rm: Cannot remove any directory in the "
 535  553                                      "path of the current working directory\n"
 536  554                                      "%s\n"), pathbuf);
 537  555                          } else {
 538  556                                  if (err == EEXIST)
 539  557                                          err = ENOTEMPTY;
 540  558                                  (void) fprintf(stderr,
 541  559                                      gettext("rm: Unable to remove directory %s:"
 542  560                                      " %s\n"), pathbuf, strerror(err));
 543  561                          }
      562 +#ifndef SUS
 544  563                  } else {
 545      -#ifndef XPG4
 546      -                        if (!silent || interactive) {
 547      -#endif
 548      -
 549      -                                (void) fprintf(stderr,
 550      -                                    gettext("rm: %s not removed: %s\n"),
 551      -                                    pathbuf, strerror(err));
 552      -#ifndef XPG4
 553      -                        }
      564 +                        (void) fprintf(stderr,
      565 +                            gettext("rm: %s not removed: %s\n"),
      566 +                            pathbuf, strerror(err));
 554  567  #endif
 555  568                  }
 556  569                  errcnt++;
 557  570          }
 558  571          return (0);
 559  572  }
 560  573  
 561  574  static int
 562  575  confirm(FILE *fp, const char *q, ...)
 563  576  {
↓ open down ↓ 48 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX