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