xref: /inferno-os/appl/cmd/install/ckproto.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Ckproto;
2
3include "sys.m";
4	sys: Sys;
5include "draw.m";
6include "bufio.m";
7	bufio: Bufio;
8	Iobuf: import bufio;
9include "arg.m";
10	arg: Arg;
11include "readdir.m";
12	readdir : Readdir;
13include "proto.m";
14	proto : Proto;
15include "protocaller.m";
16	protocaller : Protocaller;
17
18WARN, ERROR, FATAL : import Protocaller;
19
20Ckproto: module{
21	init:	fn(nil: ref Draw->Context, nil: list of string);
22	protofile: fn(new : string, old : string, d : ref Sys->Dir);
23	protoerr: fn(lev : int, line : int, err : string);
24};
25
26Dir : adt {
27	name : string;
28	proto : string;
29	parent : cyclic ref Dir;
30	child : cyclic ref Dir;
31	sibling : cyclic ref Dir;
32};
33
34root := "/";
35droot : ref Dir;
36protof : string;
37stderr : ref Sys->FD;
38omitgen := 0;			# forget generated files
39verbose : int;
40ckmode: int;
41
42init(nil: ref Draw->Context, args: list of string)
43{
44	sys = load Sys Sys->PATH;
45	bufio = load Bufio Bufio->PATH;
46	arg = load Arg Arg->PATH;
47	readdir = load Readdir Readdir->PATH;
48	proto = load Proto Proto->PATH;
49	protocaller = load Protocaller "$self";
50
51	stderr = sys->fildes(2);
52	sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKFD, nil);
53	arg->init(args);
54	while ((c := arg->opt()) != 0) {
55		case c {
56			'r' =>
57				root = arg->arg();
58				if (root == nil)
59					fatal("missing argument to -r");
60			'o' =>
61				omitgen = 1;
62			'v' =>
63				verbose = 1;
64			'm' =>
65				ckmode = 1;
66			* =>
67				fatal("usage: install/ckproto [-o] [-v] [-m] [-r root] protofile ....");
68		}
69	}
70	droot = ref Dir("/", nil, nil, nil, nil);
71	droot.parent = droot;
72	args = arg->argv();
73	while (args != nil) {
74		protof = hd args;
75		proto->rdproto(hd args, root, protocaller);
76		args = tl args;
77	}
78	if (verbose)
79		prtree(droot, -1);
80	ckdir(root, droot);
81}
82
83protofile(new : string, old : string, nil : ref Sys->Dir)
84{
85	if (verbose) {
86		if (old == new)
87			sys->print("%s\n", new);
88		else
89	 		sys->print("%s %s\n", new, old);
90	}
91	addfile(droot, old);
92	if (new != old)
93		addfile(droot, new);
94}
95
96protoerr(lev : int, line : int, err : string)
97{
98	s := "line " + string line + " : " + err;
99	case lev {
100		WARN => warn(s);
101		ERROR => error(s);
102		FATAL => fatal(s);
103	}
104}
105
106ckdir(d : string, dird : ref Dir)
107{
108	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);
109	for (i := 0; i < n; i++) {
110		dire := lookup(dird, dir[i].name);
111		if(omitgen && generated(dir[i].name))
112			continue;
113		if (dire == nil){
114			sys->print("%s missing\n", mkpath(d, dir[i].name));
115			continue;
116		}
117		if(ckmode){
118			if(dir[i].mode & Sys->DMDIR){
119				if((dir[i].mode & 8r775) != 8r775)
120					sys->print("directory %s not 775 at least\n", mkpath(d, dir[i].name));
121			}
122			else{
123				if((dir[i].mode & 8r664) != 8r664)
124					sys->print("file %s not 664 at least\n", mkpath(d, dir[i].name));
125			}
126		}
127		if (dir[i].mode & Sys->DMDIR)
128			ckdir(mkpath(d, dir[i].name), dire);
129	}
130}
131
132addfile(root : ref Dir, path : string)
133{
134	elem : string;
135
136	# ckexists(path);
137
138	curd := root;
139	opath := path;
140	while (path != nil) {
141		(elem, path) = split(path);
142		d := lookup(curd, elem);
143		if (d == nil) {
144			d = ref Dir(elem, protof, curd, nil, nil);
145			if (curd.child == nil)
146				curd.child = d;
147			else {
148				prev, this : ref Dir;
149
150				for (this = curd.child; this != nil; this = this.sibling) {
151					if (elem < this.name) {
152						d.sibling = this;
153						if (prev == nil)
154							curd.child = d;
155						else
156							prev.sibling = d;
157						break;
158					}
159					prev = this;
160				}
161				if (this == nil)
162					prev.sibling = d;
163			}
164		}
165		else if (path == nil && d.proto == protof)
166			sys->print("%s repeated in proto %s\n", opath, protof);
167		curd = d;
168	}
169}
170
171lookup(p : ref Dir, f : string) : ref Dir
172{
173	if (f == ".")
174		return p;
175	if (f == "..")
176		return p.parent;
177	for (d := p.child; d != nil; d = d.sibling) {
178		if (d.name == f)
179			return d;
180		if (d.name > f)
181			return nil;
182	}
183	return nil;
184}
185
186prtree(root : ref Dir, indent : int)
187{
188	if (indent >= 0)
189		sys->print("%s%s\n", string array[indent] of { * => byte '\t' }, root.name);
190	for (s := root.child; s != nil; s = s.sibling)
191		prtree(s, indent+1);
192}
193
194mkpath(prefix, elem: string): string
195{
196	slash1 := slash2 := 0;
197	if (len prefix > 0)
198		slash1 = prefix[len prefix - 1] == '/';
199	if (len elem > 0)
200		slash2 = elem[0] == '/';
201	if (slash1 && slash2)
202		return prefix+elem[1:];
203	if (!slash1 && !slash2)
204		return prefix+"/"+elem;
205	return prefix+elem;
206}
207
208split(p : string) : (string, string)
209{
210	if (p == nil)
211		fatal("nil string in split");
212	if (p[0] != '/')
213		fatal("p0 notg / in split");
214	while (p[0] == '/')
215		p = p[1:];
216	i := 0;
217	while (i < len p && p[i] != '/')
218		i++;
219	if (i == len p)
220		return (p, nil);
221	else
222		return (p[0:i], p[i:]);
223}
224
225
226gens := array[] of {
227	"dis", "sbl", "out", "0", "1", "2", "5", "8", "k", "q", "v", "t"
228};
229
230generated(f : string) : int
231{
232	for (i := len f -1; i >= 0; i--)
233		if (f[i] == '.')
234			break;
235	if (i < 0)
236		return 0;
237	suff := f[i+1:];
238	for (i = 0; i < len gens; i++)
239		if (suff == gens[i])
240			return 1;
241	return 0;
242}
243
244warn(s: string)
245{
246	sys->print("%s: %s\n", protof, s);
247}
248
249error(s: string)
250{
251	sys->fprint(stderr, "%s: %s\n", protof, s);
252	exit;;
253}
254
255fatal(s: string)
256{
257	sys->fprint(stderr, "fatal: %s\n", s);
258	exit;
259}
260
261ckexists(path: string)
262{
263	s := mkpath(root, path);
264	(ok, nil) := sys->stat(s);
265	if(ok < 0)
266		sys->print("%s does not exist\n", s);
267}
268