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