diff options
Diffstat (limited to 'src/cmd/rm/rm.c')
| -rwxr-xr-x | src/cmd/rm/rm.c | 119 |
1 files changed, 86 insertions, 33 deletions
diff --git a/src/cmd/rm/rm.c b/src/cmd/rm/rm.c index b034b36..ceff76b 100755 --- a/src/cmd/rm/rm.c +++ b/src/cmd/rm/rm.c @@ -1,21 +1,27 @@ #include <unistd.h> #include <stdio.h> #include <stdbool.h> -#include <stdlib.h> -#include <string.h> +#include <dirent.h> #include <sys/stat.h> #include <errno.h> +#include <err.h> +#include <string.h> +#include <stdlib.h> -bool dflag = false, +int rm(char *); +int removedir(const char * const); + +bool rflag = false, iflag = false, fflag = false; int main(int argc, char *argv[]) { char arg = 0; - while ((arg = getopt(argc, argv, "dfi")) != -1) { + while ((arg = getopt(argc, argv, "Rrfi")) != -1) { switch (arg) { - case 'd': - dflag = true; + case 'r': + case 'R': + rflag = true; break; case 'f': fflag = true; @@ -26,44 +32,91 @@ int main(int argc, char *argv[]) { fflag = false; break; default: - printf("usage: rm [-f | -i] [-d] file ...\n"); + printf("usage: rm [-f | -i] [-r] file ...\n"); break; } } while (--argc > 0) { - if ((*++argv)[0] == '-') { - continue; + if ((*++argv)[0] != '-') { + rm(*argv); } - if (iflag) { - printf("remove %s? [y/N] ", *argv); - char c = getchar(); + } + return 0; +} + +int rm(char *path) { + char c = 0; + if (iflag) { + fprintf(stderr, "remove %s? [y/N] ", path); + c = getchar(); + if (c != 'Y' && c != 'y') { + return -1; + } + } + struct stat sbuf; + if (lstat(path, &sbuf) != 0 && !fflag) { + perror("rm"); + return -1; + } + if (!fflag) { + uid_t uid = getuid(); + if (sbuf.st_uid != uid) { + fprintf(stderr, "remove %s? [y/N] ", path); + c = getchar(); if (c != 'Y' && c != 'y') { - continue; + return -1; } } - struct stat sbuf; - if (stat(*argv, &sbuf) != 0) { + } + if (S_ISDIR(sbuf.st_mode) && rflag) { + if (removedir(path) != 0) { + return -1; + } + if (rmdir(path) != 0) { perror("rm"); - continue; + return -1; } - if (S_ISDIR(sbuf.st_mode) && dflag) { - if (rmdir(*argv) != 0) { - perror("rm"); - } - } else if (S_ISDIR(sbuf.st_mode)) { - errno = EISDIR; - char s[] = "rm: "; - char *sp = (char *)malloc(sizeof(s) + sizeof(*argv) + 1); - strncat(sp, s, strlen(sp) - 1); - strncat(sp, *argv, strlen(sp)); - perror(sp); - free((void *)sp); - sp = NULL; - } else { - if (unlink(*argv) != 0) { - perror("rm"); - } + } else if (S_ISDIR(sbuf.st_mode)) { + warnc(EISDIR, "%s", path); + return -1; + } else { + if (unlink(path) != 0) { + perror("rm"); } } return 0; } + +int removedir(const char * const path) { + DIR *dir; + int status = 0; + if ((dir = opendir(path)) == NULL) { + perror("rm"); + return -1; + } + struct dirent *entry = NULL; + while ((entry = readdir(dir)) != NULL) { + char *name = entry->d_name; + if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { + size_t len = strlen(path) + strlen(name) + 3; + char *newpath = (char *)malloc(len); + if (newpath == NULL) { + exit(EXIT_FAILURE); + } + strncat(newpath, path, len); + strncat(newpath, "/", (len -= strlen(path))); + strncat(newpath, name, --len); + status = rm(newpath); + free((void *)newpath); + } + if (status != 0) { + break; + } + } + if (closedir(dir) != 0) { + perror("rm"); + return -1; + } + return status; +} + |
