Home | History | Annotate | Download | only in toolbox
      1 #include <stdio.h>
      2 #include <unistd.h>
      3 #include <string.h>
      4 #include <errno.h>
      5 #include <dirent.h>
      6 #include <limits.h>
      7 #include <sys/stat.h>
      8 #include <sys/types.h>
      9 
     10 #define OPT_RECURSIVE 1
     11 #define OPT_FORCE     2
     12 
     13 static int usage()
     14 {
     15     fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n");
     16     return -1;
     17 }
     18 
     19 /* return -1 on failure, with errno set to the first error */
     20 static int unlink_recursive(const char* name, int flags)
     21 {
     22     struct stat st;
     23     DIR *dir;
     24     struct dirent *de;
     25     int fail = 0;
     26 
     27     /* is it a file or directory? */
     28     if (lstat(name, &st) < 0)
     29         return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1;
     30 
     31     /* a file, so unlink it */
     32     if (!S_ISDIR(st.st_mode))
     33         return unlink(name);
     34 
     35     /* a directory, so open handle */
     36     dir = opendir(name);
     37     if (dir == NULL)
     38         return -1;
     39 
     40     /* recurse over components */
     41     errno = 0;
     42     while ((de = readdir(dir)) != NULL) {
     43         char dn[PATH_MAX];
     44         if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
     45             continue;
     46         sprintf(dn, "%s/%s", name, de->d_name);
     47         if (unlink_recursive(dn, flags) < 0) {
     48             fail = 1;
     49             break;
     50         }
     51         errno = 0;
     52     }
     53     /* in case readdir or unlink_recursive failed */
     54     if (fail || errno < 0) {
     55         int save = errno;
     56         closedir(dir);
     57         errno = save;
     58         return -1;
     59     }
     60 
     61     /* close directory handle */
     62     if (closedir(dir) < 0)
     63         return -1;
     64 
     65     /* delete target directory */
     66     return rmdir(name);
     67 }
     68 
     69 int rm_main(int argc, char *argv[])
     70 {
     71     int ret;
     72     int i, c;
     73     int flags = 0;
     74 
     75     if (argc < 2)
     76         return usage();
     77 
     78     /* check flags */
     79     do {
     80         c = getopt(argc, argv, "frR");
     81         if (c == EOF)
     82             break;
     83         switch (c) {
     84         case 'f':
     85             flags |= OPT_FORCE;
     86             break;
     87         case 'r':
     88         case 'R':
     89             flags |= OPT_RECURSIVE;
     90             break;
     91         }
     92     } while (1);
     93 
     94     if (optind < 1 || optind >= argc) {
     95         usage();
     96         return -1;
     97     }
     98 
     99     /* loop over the file/directory args */
    100     for (i = optind; i < argc; i++) {
    101 
    102         if (flags & OPT_RECURSIVE) {
    103             ret = unlink_recursive(argv[i], flags);
    104         } else {
    105             ret = unlink(argv[i]);
    106             if (errno == ENOENT && (flags & OPT_FORCE)) {
    107                 return 0;
    108             }
    109         }
    110 
    111         if (ret < 0) {
    112             fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
    113             return -1;
    114         }
    115     }
    116 
    117     return 0;
    118 }
    119 
    120