xref: /inferno-os/appl/cmd/install/wdiff.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Wdiff;
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 "wrap.m";
12	wrap : Wrap;
13include "sh.m";
14include "keyring.m";
15	keyring : Keyring;
16
17
18Wdiff: module{
19	init:	fn(nil: ref Draw->Context, nil: list of string);
20};
21
22root := "/";
23bflag : int;
24listing : int;
25package: int;
26
27diff(w : ref Wrap->Wrapped, name : string, c : chan of int)
28{
29	sys->pctl(Sys->FORKFD, nil);
30	wrapped := w.root+"/"+name;
31	local := root+"/"+name;
32	(ok, dir) := sys->stat(local);
33	if (ok < 0) {
34		sys->print("cannot stat %s\n", local);
35		c <-= -1;
36		return;
37	}
38	(ok, dir) = sys->stat(wrapped);
39	if (ok < 0) {
40		sys->print("cannot stat %s\n", wrapped);
41		c <-= -1;
42		return;
43	}
44	cmd := "/dis/diff.dis";
45	m := load Command cmd;
46	if(m == nil) {
47		c <-= -1;
48		return;
49	}
50	if (bflag)
51		m->init(nil, cmd :: "-b" :: wrapped :: local :: nil);
52	else
53		m->init(nil, cmd :: wrapped :: local :: nil);
54	c <-= 0;
55}
56
57fatal(err : string)
58{
59	sys->fprint(sys->fildes(2), "%s\n", err);
60	exit;
61}
62
63init(nil: ref Draw->Context, args: list of string)
64{
65	sys = load Sys Sys->PATH;
66	bufio = load Bufio Bufio->PATH;
67	arg = load Arg Arg->PATH;
68	keyring = load Keyring Keyring->PATH;
69	wrap = load Wrap Wrap->PATH;
70	wrap->init(bufio);
71
72	arg->init(args);
73	while ((c := arg->opt()) != 0) {
74		case c {
75			'b' =>
76				bflag = 1;
77			'l' =>
78				listing = 1;
79			'p' =>
80				package = 1;
81			'r' =>
82				root = arg->arg();
83				if (root == nil)
84					fatal("missing root name");
85			* =>
86				fatal(sys->sprint("bad argument -%c", c));
87		}
88	}
89	args = arg->argv();
90	if (args == nil || tl args != nil)
91		fatal("usage: install/wdiff [-blp] [-r root] package");
92	(ok, dir) := sys->stat(hd args);
93	if (ok < 0)
94		fatal(sys->sprint("no such file %s", hd args));
95	w := wrap->openwraphdr(hd args, root, nil, !listing);
96	if (w == nil)
97		fatal("no such package found");
98
99	if(package){
100		while(w.nu > 0 && w.u[w.nu-1].typ == wrap->UPD)
101			w.nu--;
102	}
103
104	digest := array[keyring->MD5dlen] of { * => byte 0 };
105	digest0 := array[keyring->MD5dlen] of { * => byte 0 };
106
107	# loop through each md5sum file of each package in increasing time order
108	for(i := 0; i < w.nu; i++){
109		b := bufio->open(w.u[i].dir+"/md5sum", Sys->OREAD);
110		if (b == nil)
111			fatal("md5sum file not found");
112		while ((p := b.gets('\n')) != nil) {
113			(n, lst) := sys->tokenize(p, " \t\n");
114			if (n != 2)
115				fatal("error in md5sum file");
116			p = hd lst;
117			q := root+"/"+p;
118			(ok, dir) = sys->stat(q);
119			if (ok >= 0 && (dir.mode & Sys->DMDIR))
120				continue;
121			t: int;
122			(ok, t) = wrap->getfileinfo(w, p, nil, digest0, nil);
123			if(ok < 0){
124				sys->print("cannot happen\n");
125				continue;
126			}
127			if(t != w.u[i].time)	# covered by later update
128				continue;
129			if (wrap->md5file(q, digest) < 0) {
130				sys->print("%s removed\n", p);
131				continue;
132			}
133			str := wrap->md5conv(digest);
134			str0 := wrap->md5conv(digest0);
135			# if (str == hd tl lst)
136			if(str == str0)
137				continue;
138			if (listing)
139				sys->print("%s modified\n", p);
140			else {
141				endc := chan of int;
142				spawn diff(w, p, endc);
143				<- endc;
144			}
145		}
146	}
147	wrap->end();
148}
149