xref: /inferno-os/appl/cmd/chmod.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Chmod;
2
3include "sys.m";
4include "draw.m";
5include "string.m";
6
7Chmod: module
8{
9	init:	fn(ctxt: ref Draw->Context, argv: list of string);
10};
11
12sys:	Sys;
13stderr: ref Sys->FD;
14
15str:	String;
16
17User:	con 8r700;
18Group:	con 8r070;
19Other:	con 8r007;
20All:	con User | Group | Other;
21
22Read:	con 8r444;
23Write:	con 8r222;
24Exec:	con 8r111;
25
26usage()
27{
28	sys->fprint(stderr, "usage: chmod [8r]777 file ... or chmod [augo][+-=][rwxal] file ...\n");
29	raise "fail:usage";
30}
31
32init(nil: ref Draw->Context, argv: list of string)
33{
34	sys = load Sys Sys->PATH;
35	stderr = sys->fildes(2);
36
37	str = load String String->PATH;
38	if(str == nil){
39		sys->fprint(stderr, "chmod: cannot load %s: %r\n", String->PATH);
40		raise "fail:bad module";
41	}
42
43	if(len argv < 3)
44		usage();
45	argv = tl argv;
46	m := hd argv;
47	argv = tl argv;
48
49	mask := All;
50	if (str->prefix("8r", m))
51		m = m[2:];
52	(mode, s) := str->toint(m, 8);
53	if(s != "" || m == ""){
54		ok := 0;
55		(ok, mask, mode) = parsemode(m);
56		if(!ok){
57			sys->fprint(stderr, "chmod: bad mode '%s'\n", m);
58			usage();
59		}
60	}
61	ndir := sys->nulldir;
62	for(; argv != nil; argv = tl argv){
63		f := hd argv;
64		(ok, dir) := sys->stat(f);
65		if(ok < 0){
66			sys->fprint(stderr, "chmod: cannot stat %s: %r\n", f);
67			continue;
68		}
69		ndir.mode = (dir.mode & ~mask) | (mode & mask);
70		if(sys->wstat(f, ndir) < 0)
71			sys->fprint(stderr, "chmod: cannot wstat %s: %r\n", f);
72	}
73}
74
75parsemode(spec: string): (int, int, int)
76{
77	mask := Sys->DMAPPEND | Sys->DMEXCL | Sys->DMTMP;
78loop:	for(i := 0; i < len spec; i++){
79		case spec[i] {
80		'u' =>
81			mask |= User;
82		'g' =>
83			mask |= Group;
84		'o' =>
85			mask |= Other;
86		'a' =>
87			mask |= All;
88		* =>
89			break loop;
90		}
91	}
92	if(i == len spec)
93		return (0, 0, 0);
94	if(i == 0)
95		mask |= All;
96
97	op := spec[i++];
98	if(op != '+' && op != '-' && op != '=')
99		return (0, 0, 0);
100
101	mode := 0;
102	for(; i < len spec; i++){
103		case spec[i]{
104		'r' =>
105			mode |= Read;
106		'w' =>
107			mode |= Write;
108		'x' =>
109			mode |= Exec;
110		'a' =>
111			mode |= Sys->DMAPPEND;
112		'l' =>
113			mode |= Sys->DMEXCL;
114		't' =>
115			mode |= Sys->DMTMP;
116		* =>
117			return (0, 0, 0);
118		}
119	}
120	if(op == '+' || op == '-')
121		mask &= mode;
122	if(op == '-')
123		mode = ~mode;
124	return (1, mask, mode);
125}
126