xref: /inferno-os/appl/cmd/rm.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Rm;
2
3include "sys.m";
4	sys: Sys;
5include "draw.m";
6
7include "readdir.m";
8	readdir: Readdir;
9
10include "arg.m";
11
12Rm: module
13{
14	init:	fn(ctxt: ref Draw->Context, argv: list of string);
15};
16
17stderr: ref Sys->FD;
18quiet := 0;
19force := 0;
20errcount := 0;
21
22usage()
23{
24	sys->fprint(stderr, "Usage: rm [-fr] file ...\n");
25	raise "fail: usage";
26}
27allwrite := Sys->nulldir;
28
29init(nil: ref Draw->Context, args: list of string)
30{
31	sys = load Sys Sys->PATH;
32	stderr = sys->fildes(2);
33	allwrite.mode = 8r777 | Sys->DMDIR;
34
35	arg := load Arg Arg->PATH;
36	if(arg == nil){
37		sys->fprint(stderr, "rm: can't load %s: %r\n", Arg->PATH);
38		raise "fail:load";
39	}
40	arg->init(args);
41	while((o := arg->opt()) != 0)
42		case o {
43		'r' =>
44			readdir = load Readdir Readdir->PATH;
45			if(readdir == nil)
46				sys->fprint(stderr, "rm: can't load Readdir: %r\n");	# -r is regarded as optional
47		'f' =>
48			quiet = 1;
49		'F' =>
50			force = 1;
51		* =>
52			usage();
53		}
54	args = arg->argv();
55	arg = nil;
56	sys->pctl(Sys->FORKNS, nil);
57	for(; args != nil; args = tl args) {
58		name := hd args;
59		if(sys->remove(name) < 0) {
60			e := sys->sprint("%r");
61			(ok, d) := sys->stat(name);
62			if(readdir != nil && ok >= 0 && (d.mode & Sys->DMDIR) != 0)
63				rmdir(name);
64			else
65				err(name, e);
66		}
67	}
68	if(errcount > 0)
69		raise "fail:errors";
70}
71
72rmdir(name: string)
73{
74	if(force)
75		sys->wstat(name, allwrite);
76	(d, n) := readdir->init(name, Readdir->NONE|Readdir->COMPACT);
77	for(i := 0; i < n; i++){
78		path := name+"/"+d[i].name;
79		if(d[i].mode & Sys->DMDIR)
80			rmdir(path);
81		else
82			remove(path);
83	}
84	remove(name);
85}
86
87remove(name: string)
88{
89	if(sys->remove(name) < 0)
90		err(name, sys->sprint("%r"));
91}
92
93err(name, e: string)
94{
95	if(!quiet) {
96		sys->fprint(stderr, "rm: %s: %s\n", name, e);
97		errcount++;
98	}
99}
100