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
13static 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 */
20static 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
69int 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