rm.c (1441B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <fcntl.h> 3 #include <string.h> 4 5 #include "fs.h" 6 #include "util.h" 7 8 static void 9 usage(void) 10 { 11 eprintf("usage: %s [-f] [-iRr] file ...\n", argv0); 12 } 13 14 static int 15 forbidden(char *path, struct stat *root) 16 { 17 char *s, *t; 18 size_t n; 19 struct stat st; 20 static int w1, w2; 21 22 n = strlen(path); 23 for (t = path + n; t > path && t[-1] == '/'; --t) 24 ; 25 for (s = t; s > path && s[-1] != '/'; --s) 26 ; 27 n = t - s; 28 if (n == 1 && *s == '.' || n == 2 && s[0] == '.' && s[1] == '.') { 29 if (!w1) 30 weprintf("\".\" and \"..\" may not be removed\n"); 31 w1 = 1; 32 return 1; 33 } 34 35 if (stat(path, &st) < 0) 36 return 0; 37 if (st.st_dev == root->st_dev && st.st_ino == root->st_ino) { 38 if (!w2) 39 weprintf("\"/\" may not be removed\n"); 40 w2 = 1; 41 return 1; 42 } 43 44 return 0; 45 } 46 47 int 48 main(int argc, char *argv[]) 49 { 50 char *s; 51 struct stat st; 52 struct recursor r = { .fn = rm, .maxdepth = 1, .follow = 'P' }; 53 54 ARGBEGIN { 55 case 'f': 56 r.flags |= SILENT | IGNORE; 57 break; 58 case 'i': 59 r.flags |= CONFIRM; 60 break; 61 case 'R': 62 case 'r': 63 r.maxdepth = 0; 64 break; 65 default: 66 usage(); 67 } ARGEND 68 69 if (!argc) { 70 if (!(r.flags & IGNORE)) 71 usage(); 72 else 73 return 0; 74 } 75 76 if (stat("/", &st) < 0) 77 eprintf("stat root:"); 78 for (; *argv; argc--, argv++) { 79 if (forbidden(*argv, &st)) { 80 rm_status = 1; 81 continue; 82 } 83 recurse(AT_FDCWD, *argv, NULL, &r); 84 } 85 86 return rm_status || recurse_status; 87 }