sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

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 }