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 if (!(flags & OPT_FORCE)) { 49 fail = 1; 50 break; 51 } 52 } 53 errno = 0; 54 } 55 /* in case readdir or unlink_recursive failed */ 56 if (fail || errno < 0) { 57 int save = errno; 58 closedir(dir); 59 errno = save; 60 return -1; 61 } 62 63 /* close directory handle */ 64 if (closedir(dir) < 0) 65 return -1; 66 67 /* delete target directory */ 68 return rmdir(name); 69} 70 71int rm_main(int argc, char *argv[]) 72{ 73 int ret; 74 int i, c; 75 int flags = 0; 76 int something_failed = 0; 77 78 if (argc < 2) 79 return usage(); 80 81 /* check flags */ 82 do { 83 c = getopt(argc, argv, "frR"); 84 if (c == EOF) 85 break; 86 switch (c) { 87 case 'f': 88 flags |= OPT_FORCE; 89 break; 90 case 'r': 91 case 'R': 92 flags |= OPT_RECURSIVE; 93 break; 94 } 95 } while (1); 96 97 if (optind < 1 || optind >= argc) { 98 usage(); 99 return -1; 100 } 101 102 /* loop over the file/directory args */ 103 for (i = optind; i < argc; i++) { 104 105 if (flags & OPT_RECURSIVE) { 106 ret = unlink_recursive(argv[i], flags); 107 } else { 108 ret = unlink(argv[i]); 109 if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) { 110 continue; 111 } 112 } 113 114 if (ret < 0) { 115 fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno)); 116 if (!(flags & OPT_FORCE)) { 117 return -1; 118 } else { 119 something_failed = 1; 120 } 121 } 122 } 123 124 return something_failed; 125} 126 127