summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob McDonnell <jacob@jacobmcdonnell.com>2024-03-11 20:13:20 -0400
committerJacob McDonnell <jacob@jacobmcdonnell.com>2024-03-11 20:13:20 -0400
commit5e32f9d376222f20a695636e600aec765e24c44a (patch)
tree6e89530d6744801e0023eb871a0782d62c34ad7c /src
parent4a76a5825c04e9872bddfc23e3e8ade2fa6c0160 (diff)
Checking for memory leak in rm
Diffstat (limited to 'src')
-rwxr-xr-xsrc/cmd/rm/rmbin34016 -> 34912 bytes
-rwxr-xr-xsrc/cmd/rm/rm.c119
2 files changed, 86 insertions, 33 deletions
diff --git a/src/cmd/rm/rm b/src/cmd/rm/rm
index 886e88d..e2c59a6 100755
--- a/src/cmd/rm/rm
+++ b/src/cmd/rm/rm
Binary files differ
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;
+}
+