xref: /inferno-os/appl/cmd/install/install.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Install;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# Determine which packages need installing and calls install/inst
5*37da2899SCharles.Forsyth# to actually install each one
6*37da2899SCharles.Forsyth#
7*37da2899SCharles.Forsyth
8*37da2899SCharles.Forsyth# usage: install/install -d -F -g -s -u -i installdir -p platform -r root -P package
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythinclude "sys.m";
11*37da2899SCharles.Forsyth	sys: Sys;
12*37da2899SCharles.Forsythinclude "draw.m";
13*37da2899SCharles.Forsythinclude "bufio.m";
14*37da2899SCharles.Forsyth	bufio: Bufio;
15*37da2899SCharles.Forsyth	Iobuf: import bufio;
16*37da2899SCharles.Forsythinclude "string.m";
17*37da2899SCharles.Forsyth	str: String;
18*37da2899SCharles.Forsythinclude "arg.m";
19*37da2899SCharles.Forsyth	arg: Arg;
20*37da2899SCharles.Forsythinclude "readdir.m";
21*37da2899SCharles.Forsyth	readdir : Readdir;
22*37da2899SCharles.Forsythinclude "sh.m";
23*37da2899SCharles.Forsyth
24*37da2899SCharles.ForsythInstall: module
25*37da2899SCharles.Forsyth{
26*37da2899SCharles.Forsyth	init: fn(nil: ref Draw->Context, nil: list of string);
27*37da2899SCharles.Forsyth};
28*37da2899SCharles.Forsyth
29*37da2899SCharles.Forsyth# required dirs, usually in the standard inferno root.
30*37da2899SCharles.Forsyth# The network download doesn't include them because of
31*37da2899SCharles.Forsyth# problems with versions of tar that won't create empty dirs
32*37da2899SCharles.Forsyth# so we'll make sure they exist.
33*37da2899SCharles.Forsyth
34*37da2899SCharles.Forsythreqdirs := array [] of {
35*37da2899SCharles.Forsyth	"/mnt",
36*37da2899SCharles.Forsyth	"/mnt/wrap",
37*37da2899SCharles.Forsyth	"/n",
38*37da2899SCharles.Forsyth	"/n/remote",
39*37da2899SCharles.Forsyth	"/tmp",
40*37da2899SCharles.Forsyth};
41*37da2899SCharles.Forsyth
42*37da2899SCharles.ForsythYES, NO, QUIT, ERR : con iota;
43*37da2899SCharles.ForsythINST : con "install/inst";	# actual install program
44*37da2899SCharles.ForsythMTPT : con "/n/remote";	# mount point for user's inferno root
45*37da2899SCharles.Forsyth
46*37da2899SCharles.Forsythdebug := 0;
47*37da2899SCharles.Forsythforce := 0;
48*37da2899SCharles.Forsythexitemu := 0;
49*37da2899SCharles.Forsythuflag := 0;
50*37da2899SCharles.Forsythstderr : ref Sys->FD;
51*37da2899SCharles.Forsythinstalldir := "/install";
52*37da2899SCharles.Forsythplatform := "Plan9";
53*37da2899SCharles.Forsythlcplatform : string;
54*37da2899SCharles.Forsythroot := "/usr/inferno";
55*37da2899SCharles.Forsythlocal: int;
56*37da2899SCharles.Forsythglobal: int = 1;
57*37da2899SCharles.Forsythwaitfd : ref Sys->FD;
58*37da2899SCharles.Forsyth
59*37da2899SCharles.ForsythProduct : adt {
60*37da2899SCharles.Forsyth	name : string;
61*37da2899SCharles.Forsyth	pkgs : ref Package;
62*37da2899SCharles.Forsyth	nxt : ref Product;
63*37da2899SCharles.Forsyth};
64*37da2899SCharles.Forsyth
65*37da2899SCharles.ForsythPackage : adt {
66*37da2899SCharles.Forsyth	name : string;
67*37da2899SCharles.Forsyth	nxt : ref Package;
68*37da2899SCharles.Forsyth};
69*37da2899SCharles.Forsyth
70*37da2899SCharles.Forsythinstprods : ref Product;	# products/packages already installed
71*37da2899SCharles.Forsyth
72*37da2899SCharles.Forsyth# platform independent packages
73*37da2899SCharles.Forsythxpkgs := array[] of { "inferno", "utils", "src", "ipaq", "minitel", "sds" };
74*37da2899SCharles.Forsythypkgs: list of string;
75*37da2899SCharles.Forsyth
76*37da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string)
77*37da2899SCharles.Forsyth{
78*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
79*37da2899SCharles.Forsyth	stderr = sys->fildes(2);
80*37da2899SCharles.Forsyth
81*37da2899SCharles.Forsyth	# Hack for network download...
82*37da2899SCharles.Forsyth	# make sure the dirs we need exist
83*37da2899SCharles.Forsyth	for (dirix := 0; dirix < len reqdirs; dirix++) {
84*37da2899SCharles.Forsyth		dir := reqdirs[dirix];
85*37da2899SCharles.Forsyth		(exists, nil) := sys->stat(dir);
86*37da2899SCharles.Forsyth		if (exists == -1) {
87*37da2899SCharles.Forsyth			fd := sys->create(dir, Sys->OREAD, Sys->DMDIR + 8r7775);
88*37da2899SCharles.Forsyth			if (fd == nil)
89*37da2899SCharles.Forsyth				fatal(sys->sprint("cannot create directory %s: %r\n", dir));
90*37da2899SCharles.Forsyth			fd = nil;
91*37da2899SCharles.Forsyth		}
92*37da2899SCharles.Forsyth	}
93*37da2899SCharles.Forsyth
94*37da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
95*37da2899SCharles.Forsyth	if(bufio == nil)
96*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot load %s: %r\n", Bufio->PATH));
97*37da2899SCharles.Forsyth	readdir = load Readdir Readdir->PATH;
98*37da2899SCharles.Forsyth	if(readdir == nil)
99*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot load %s: %r\n", Readdir->PATH));
100*37da2899SCharles.Forsyth	str = load String String->PATH;
101*37da2899SCharles.Forsyth	if(str == nil)
102*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot load %s: %r\n", String->PATH));
103*37da2899SCharles.Forsyth	arg = load Arg Arg->PATH;
104*37da2899SCharles.Forsyth	if(arg == nil)
105*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot load %s: %r\n", Arg->PATH));
106*37da2899SCharles.Forsyth	arg->init(args);
107*37da2899SCharles.Forsyth	while((c := arg->opt()) != 0) {
108*37da2899SCharles.Forsyth		case c {
109*37da2899SCharles.Forsyth			'd' =>
110*37da2899SCharles.Forsyth				debug = 1;
111*37da2899SCharles.Forsyth			'F' =>
112*37da2899SCharles.Forsyth				force = 1;
113*37da2899SCharles.Forsyth			's' =>
114*37da2899SCharles.Forsyth				exitemu = 1;
115*37da2899SCharles.Forsyth			'i' =>
116*37da2899SCharles.Forsyth				installdir = arg->arg();
117*37da2899SCharles.Forsyth				if (installdir == nil)
118*37da2899SCharles.Forsyth					fatal("install directory missing");
119*37da2899SCharles.Forsyth			'p' =>
120*37da2899SCharles.Forsyth				platform = arg->arg();
121*37da2899SCharles.Forsyth				if (platform == nil)
122*37da2899SCharles.Forsyth					fatal("platform missing");
123*37da2899SCharles.Forsyth			'P' =>
124*37da2899SCharles.Forsyth				pkg := arg->arg();
125*37da2899SCharles.Forsyth				if (pkg == nil)
126*37da2899SCharles.Forsyth					fatal("package missing");
127*37da2899SCharles.Forsyth				ypkgs = pkg :: ypkgs;
128*37da2899SCharles.Forsyth			'r' =>
129*37da2899SCharles.Forsyth				root = arg->arg();
130*37da2899SCharles.Forsyth				if (root == nil)
131*37da2899SCharles.Forsyth					fatal("inferno root missing");
132*37da2899SCharles.Forsyth			'u' =>
133*37da2899SCharles.Forsyth				uflag = 1;
134*37da2899SCharles.Forsyth			'g' =>
135*37da2899SCharles.Forsyth				global = 0;
136*37da2899SCharles.Forsyth			'*' =>
137*37da2899SCharles.Forsyth				usage();
138*37da2899SCharles.Forsyth		}
139*37da2899SCharles.Forsyth	}
140*37da2899SCharles.Forsyth	if (arg->argv() != nil)
141*37da2899SCharles.Forsyth		usage();
142*37da2899SCharles.Forsyth	lcplatform = str->tolower(platform);
143*37da2899SCharles.Forsyth	(ok, dir) := sys->stat(installdir);
144*37da2899SCharles.Forsyth	if (ok < 0)
145*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot open install directory %s", installdir));
146*37da2899SCharles.Forsyth	nt := lcplatform == "nt";
147*37da2899SCharles.Forsyth	if (nt) {
148*37da2899SCharles.Forsyth		# root os of the form ?:/.........
149*37da2899SCharles.Forsyth		if (len root < 3 || root[1] != ':' || root[2] != '/')
150*37da2899SCharles.Forsyth			fatal(sys->sprint("root %s not of the form ?:/.......", root));
151*37da2899SCharles.Forsyth		spec := root[0:2];
152*37da2899SCharles.Forsyth		root = root[2:];
153*37da2899SCharles.Forsyth		if (sys->bind("#U"+spec, MTPT, Sys->MREPL|Sys->MCREATE) < 0)
154*37da2899SCharles.Forsyth			fatal(sys->sprint("cannot bind to drive %s", spec));
155*37da2899SCharles.Forsyth	}
156*37da2899SCharles.Forsyth	else {
157*37da2899SCharles.Forsyth		if (root[0] != '/')
158*37da2899SCharles.Forsyth			fatal(sys->sprint("root %s must be an absolute path name", root));
159*37da2899SCharles.Forsyth		if (sys->bind("#U*", MTPT, Sys->MREPL|Sys->MCREATE) < 0)
160*37da2899SCharles.Forsyth			fatal("cannot bind to system root");
161*37da2899SCharles.Forsyth	}
162*37da2899SCharles.Forsyth	(ok, dir) = sys->stat(MTPT+root);
163*37da2899SCharles.Forsyth	if (ok >= 0) {
164*37da2899SCharles.Forsyth		if ((dir.mode & Sys->DMDIR) == 0)
165*37da2899SCharles.Forsyth			fatal(sys->sprint("inferno root %s is not a directory", root));
166*37da2899SCharles.Forsyth	}
167*37da2899SCharles.Forsyth	else if (sys->create(MTPT+root, Sys->OREAD, 8r775 | Sys->DMDIR) == nil)
168*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot create inferno root %s: %r", root));
169*37da2899SCharles.Forsyth	# need a writable tmp directory /tmp in case installing from CD
170*37da2899SCharles.Forsyth	(ok, dir) = sys->stat(MTPT+root+"/tmp");
171*37da2899SCharles.Forsyth	if (ok >= 0) {
172*37da2899SCharles.Forsyth		if ((dir.mode & Sys->DMDIR) == 0)
173*37da2899SCharles.Forsyth			fatal(sys->sprint("inferno root tmp %s is not a directory", root+"/tmp"));
174*37da2899SCharles.Forsyth	}
175*37da2899SCharles.Forsyth	else if (sys->create(MTPT+root+"/tmp", Sys->OREAD, 8r775 | Sys->DMDIR) == nil)
176*37da2899SCharles.Forsyth		fatal(sys->sprint("cannot create inferno root tmp %s: %r", root+"/tmp"));
177*37da2899SCharles.Forsyth	if (sys->bind(MTPT+root, MTPT, Sys->MREPL | Sys->MCREATE) < 0)
178*37da2899SCharles.Forsyth		fatal("cannot bind inferno root");
179*37da2899SCharles.Forsyth	if (sys->bind(MTPT+"/tmp", "/tmp", Sys->MREPL | Sys->MCREATE) < 0)
180*37da2899SCharles.Forsyth		fatal("cannot bind inferno root tmp");
181*37da2899SCharles.Forsyth	root = MTPT;
182*37da2899SCharles.Forsyth
183*37da2899SCharles.Forsyth	if (nt || 1)
184*37da2899SCharles.Forsyth		local = 1;
185*37da2899SCharles.Forsyth	else {
186*37da2899SCharles.Forsyth		sys->print("You can either install software specific to %s only or\n", platform);
187*37da2899SCharles.Forsyth		sys->print(" install software for all platforms that we support.\n");
188*37da2899SCharles.Forsyth		sys->print("If you are unsure what to do, answer yes to the question following.\n");
189*37da2899SCharles.Forsyth		sys->print(" You can install the remainder of the software at a later date if desired.\n");
190*37da2899SCharles.Forsyth		sys->print("\n");
191*37da2899SCharles.Forsyth		b := bufio->fopen(sys->fildes(0), Bufio->OREAD);
192*37da2899SCharles.Forsyth		if (b == nil)
193*37da2899SCharles.Forsyth			fatal("cannot open stdin");
194*37da2899SCharles.Forsyth		for (;;) {
195*37da2899SCharles.Forsyth			sys->print("Install software specific to %s only ? (yes/no/quit) ", platform);
196*37da2899SCharles.Forsyth			resp := getresponse(b);
197*37da2899SCharles.Forsyth			ans := answer(resp);
198*37da2899SCharles.Forsyth			if (ans == QUIT)
199*37da2899SCharles.Forsyth				exit;
200*37da2899SCharles.Forsyth			else if (ans == ERR)
201*37da2899SCharles.Forsyth				sys->print("bad response %s\n\n", resp);
202*37da2899SCharles.Forsyth			else {
203*37da2899SCharles.Forsyth				local = ans == YES;
204*37da2899SCharles.Forsyth				break;
205*37da2899SCharles.Forsyth			}
206*37da2899SCharles.Forsyth		}
207*37da2899SCharles.Forsyth	}
208*37da2899SCharles.Forsyth	instprods = dowraps(root+"/wrap");
209*37da2899SCharles.Forsyth	doprods(installdir);
210*37da2899SCharles.Forsyth	if (!nt)
211*37da2899SCharles.Forsyth		sys->print("installation complete\n");
212*37da2899SCharles.Forsyth	if (exitemu)
213*37da2899SCharles.Forsyth		shutdown();
214*37da2899SCharles.Forsyth}
215*37da2899SCharles.Forsyth
216*37da2899SCharles.Forsythgetresponse(b : ref Iobuf) : string
217*37da2899SCharles.Forsyth{
218*37da2899SCharles.Forsyth	s := b.gets('\n');
219*37da2899SCharles.Forsyth	while (s != nil && (s[0] == ' ' || s[0] == '\t'))
220*37da2899SCharles.Forsyth		s = s[1:];
221*37da2899SCharles.Forsyth	while (s != nil && ((c := s[len s - 1]) == ' ' || c == '\t' || c == '\n'))
222*37da2899SCharles.Forsyth		s = s[0: len s - 1];
223*37da2899SCharles.Forsyth	return s;
224*37da2899SCharles.Forsyth}
225*37da2899SCharles.Forsyth
226*37da2899SCharles.Forsythanswer(s : string) : int
227*37da2899SCharles.Forsyth{
228*37da2899SCharles.Forsyth	s = str->tolower(s);
229*37da2899SCharles.Forsyth	if (s == "y" || s == "yes")
230*37da2899SCharles.Forsyth		return YES;
231*37da2899SCharles.Forsyth	if (s == "n" || s == "no")
232*37da2899SCharles.Forsyth		return NO;
233*37da2899SCharles.Forsyth	if (s == "q" || s == "quit")
234*37da2899SCharles.Forsyth		return QUIT;
235*37da2899SCharles.Forsyth	return ERR;
236*37da2899SCharles.Forsyth}
237*37da2899SCharles.Forsyth
238*37da2899SCharles.Forsythusage()
239*37da2899SCharles.Forsyth{
240*37da2899SCharles.Forsyth	fatal("Usage: install [-d] [-F] [-s] [-u] [-i installdir ] [-p platform ] [-r root]");
241*37da2899SCharles.Forsyth}
242*37da2899SCharles.Forsyth
243*37da2899SCharles.Forsythfatal(s : string)
244*37da2899SCharles.Forsyth{
245*37da2899SCharles.Forsyth	sys->fprint(stderr, "install: %s\n", s);
246*37da2899SCharles.Forsyth	exit;
247*37da2899SCharles.Forsyth}
248*37da2899SCharles.Forsyth
249*37da2899SCharles.Forsythdowraps(d : string) : ref Product
250*37da2899SCharles.Forsyth{
251*37da2899SCharles.Forsyth	p : ref Product;
252*37da2899SCharles.Forsyth
253*37da2899SCharles.Forsyth	# make an inventory of what is already apparently installed
254*37da2899SCharles.Forsyth	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);
255*37da2899SCharles.Forsyth	for (i := 0; i < n; i++) {
256*37da2899SCharles.Forsyth		if (dir[i].mode & Sys->DMDIR) {
257*37da2899SCharles.Forsyth			p = ref Product(str->tolower(dir[i].name), nil, p);
258*37da2899SCharles.Forsyth			p.pkgs = dowrap(d + "/" + dir[i].name);
259*37da2899SCharles.Forsyth		}
260*37da2899SCharles.Forsyth	}
261*37da2899SCharles.Forsyth	return p;
262*37da2899SCharles.Forsyth}
263*37da2899SCharles.Forsyth
264*37da2899SCharles.Forsythdowrap(d : string) : ref Package
265*37da2899SCharles.Forsyth{
266*37da2899SCharles.Forsyth	p : ref Package;
267*37da2899SCharles.Forsyth
268*37da2899SCharles.Forsyth	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);
269*37da2899SCharles.Forsyth	for (i := 0; i < n; i++)
270*37da2899SCharles.Forsyth		p = ref Package(dir[i].name, p);
271*37da2899SCharles.Forsyth	return p;
272*37da2899SCharles.Forsyth}
273*37da2899SCharles.Forsyth
274*37da2899SCharles.Forsythdoprods(d : string)
275*37da2899SCharles.Forsyth{
276*37da2899SCharles.Forsyth	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);
277*37da2899SCharles.Forsyth	for (i := 0; i < n; i++) {
278*37da2899SCharles.Forsyth		if (dir[i].mode & Sys->DMDIR)
279*37da2899SCharles.Forsyth			doprod(str->tolower(dir[i].name), d + "/" + dir[i].name);
280*37da2899SCharles.Forsyth	}
281*37da2899SCharles.Forsyth}
282*37da2899SCharles.Forsyth
283*37da2899SCharles.Forsythdoprod(pr : string, d : string)
284*37da2899SCharles.Forsyth{
285*37da2899SCharles.Forsyth	# base package, updates and update packages have the name
286*37da2899SCharles.Forsyth	# <timestamp> or <timestamp.gz>
287*37da2899SCharles.Forsyth	if (!wanted(pr))
288*37da2899SCharles.Forsyth		return;
289*37da2899SCharles.Forsyth	(dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT);
290*37da2899SCharles.Forsyth	for (i := 0; i < n; i++) {
291*37da2899SCharles.Forsyth		pk := dir[i].name;
292*37da2899SCharles.Forsyth		l := len pk;
293*37da2899SCharles.Forsyth		if (l >= 4 && pk[l-3:l] == ".gz")
294*37da2899SCharles.Forsyth			pk = pk[0:l-3];
295*37da2899SCharles.Forsyth		else if (l >= 5 && (pk[l-4:] == ".tgz" || pk[l-4:] == ".9gz"))
296*37da2899SCharles.Forsyth			pk = pk[0:l-4];
297*37da2899SCharles.Forsyth		dopkg(pk, pr, d+"/"+dir[i].name);
298*37da2899SCharles.Forsyth
299*37da2899SCharles.Forsyth	}
300*37da2899SCharles.Forsyth}
301*37da2899SCharles.Forsyth
302*37da2899SCharles.Forsythdopkg(pk : string, pr : string, d : string)
303*37da2899SCharles.Forsyth{
304*37da2899SCharles.Forsyth	if (!installed(pk, pr))
305*37da2899SCharles.Forsyth		install(d);
306*37da2899SCharles.Forsyth}
307*37da2899SCharles.Forsyth
308*37da2899SCharles.Forsythinstalled(pkg : string, prd : string) : int
309*37da2899SCharles.Forsyth{
310*37da2899SCharles.Forsyth	for (pr := instprods; pr != nil; pr = pr.nxt) {
311*37da2899SCharles.Forsyth		if (pr.name == prd) {
312*37da2899SCharles.Forsyth			for (pk := pr.pkgs; pk != nil; pk = pk.nxt) {
313*37da2899SCharles.Forsyth				if (pk.name == pkg)
314*37da2899SCharles.Forsyth					return 1;
315*37da2899SCharles.Forsyth			}
316*37da2899SCharles.Forsyth			return 0;
317*37da2899SCharles.Forsyth		}
318*37da2899SCharles.Forsyth	}
319*37da2899SCharles.Forsyth	return 0;
320*37da2899SCharles.Forsyth}
321*37da2899SCharles.Forsyth
322*37da2899SCharles.Forsythlookup(pr : string) : int
323*37da2899SCharles.Forsyth{
324*37da2899SCharles.Forsyth	for (i := 0; i < len xpkgs; i++) {
325*37da2899SCharles.Forsyth		if (xpkgs[i] == pr)
326*37da2899SCharles.Forsyth			return i;
327*37da2899SCharles.Forsyth	}
328*37da2899SCharles.Forsyth	return -1;
329*37da2899SCharles.Forsyth}
330*37da2899SCharles.Forsyth
331*37da2899SCharles.Forsythplookup(pr: string): int
332*37da2899SCharles.Forsyth{
333*37da2899SCharles.Forsyth	for(ps := ypkgs; ps != nil; ps = tl ps)
334*37da2899SCharles.Forsyth		if(pr == hd ps)
335*37da2899SCharles.Forsyth			return 1;
336*37da2899SCharles.Forsyth	return 0;
337*37da2899SCharles.Forsyth}
338*37da2899SCharles.Forsyth
339*37da2899SCharles.Forsythwanted(pr : string) : int
340*37da2899SCharles.Forsyth{
341*37da2899SCharles.Forsyth	if (!local || global)
342*37da2899SCharles.Forsyth		return 1;
343*37da2899SCharles.Forsyth	if(ypkgs != nil)	# overrides everything else
344*37da2899SCharles.Forsyth		return plookup(pr);
345*37da2899SCharles.Forsyth	found := lookup(pr);
346*37da2899SCharles.Forsyth	if (found >= 0)
347*37da2899SCharles.Forsyth		return 1;
348*37da2899SCharles.Forsyth	return pr == lcplatform || prefix(lcplatform, pr);
349*37da2899SCharles.Forsyth}
350*37da2899SCharles.Forsyth
351*37da2899SCharles.Forsythinstall(d : string)
352*37da2899SCharles.Forsyth{
353*37da2899SCharles.Forsyth	if (waitfd == nil)
354*37da2899SCharles.Forsyth		waitfd = openwait(sys->pctl(0, nil));
355*37da2899SCharles.Forsyth	sys->fprint(stderr, "installing package %s\n", d);
356*37da2899SCharles.Forsyth	if (debug)
357*37da2899SCharles.Forsyth		return;
358*37da2899SCharles.Forsyth	c := chan of int;
359*37da2899SCharles.Forsyth	args := "-t" :: "-v" :: "-r" :: root :: d :: nil;
360*37da2899SCharles.Forsyth	if (uflag)
361*37da2899SCharles.Forsyth		args = "-u" :: args;
362*37da2899SCharles.Forsyth	if (force)
363*37da2899SCharles.Forsyth		args = "-F" :: args;
364*37da2899SCharles.Forsyth	spawn exec(INST, INST :: args, c);
365*37da2899SCharles.Forsyth	execpid := <- c;
366*37da2899SCharles.Forsyth	wait(waitfd, execpid);
367*37da2899SCharles.Forsyth}
368*37da2899SCharles.Forsyth
369*37da2899SCharles.Forsythexec(cmd : string, argl : list of string, ci : chan of int)
370*37da2899SCharles.Forsyth{
371*37da2899SCharles.Forsyth	ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil);
372*37da2899SCharles.Forsyth	file := cmd;
373*37da2899SCharles.Forsyth	if(len file<4 || file[len file-4:] !=".dis")
374*37da2899SCharles.Forsyth		file += ".dis";
375*37da2899SCharles.Forsyth	c := load Command file;
376*37da2899SCharles.Forsyth	if(c == nil) {
377*37da2899SCharles.Forsyth		err := sys->sprint("%r");
378*37da2899SCharles.Forsyth		if(file[0] !='/' && file[0:2] !="./") {
379*37da2899SCharles.Forsyth			c = load Command "/dis/"+file;
380*37da2899SCharles.Forsyth			if(c == nil)
381*37da2899SCharles.Forsyth				err = sys->sprint("%r");
382*37da2899SCharles.Forsyth		}
383*37da2899SCharles.Forsyth		if(c == nil)
384*37da2899SCharles.Forsyth			fatal(sys->sprint("%s: %s\n", cmd, err));
385*37da2899SCharles.Forsyth	}
386*37da2899SCharles.Forsyth	c->init(nil, argl);
387*37da2899SCharles.Forsyth}
388*37da2899SCharles.Forsyth
389*37da2899SCharles.Forsythopenwait(pid : int) : ref Sys->FD
390*37da2899SCharles.Forsyth{
391*37da2899SCharles.Forsyth	w := sys->sprint("#p/%d/wait", pid);
392*37da2899SCharles.Forsyth	fd := sys->open(w, Sys->OREAD);
393*37da2899SCharles.Forsyth	if (fd == nil)
394*37da2899SCharles.Forsyth		fatal("fd == nil in wait");
395*37da2899SCharles.Forsyth	return fd;
396*37da2899SCharles.Forsyth}
397*37da2899SCharles.Forsyth
398*37da2899SCharles.Forsythwait(wfd : ref Sys->FD, wpid : int)
399*37da2899SCharles.Forsyth{
400*37da2899SCharles.Forsyth	n : int;
401*37da2899SCharles.Forsyth
402*37da2899SCharles.Forsyth	buf := array[Sys->WAITLEN] of byte;
403*37da2899SCharles.Forsyth	status := "";
404*37da2899SCharles.Forsyth	for(;;) {
405*37da2899SCharles.Forsyth		if ((n = sys->read(wfd, buf, len buf)) < 0)
406*37da2899SCharles.Forsyth			fatal("bad read in wait");
407*37da2899SCharles.Forsyth		status = string buf[0:n];
408*37da2899SCharles.Forsyth		break;
409*37da2899SCharles.Forsyth	}
410*37da2899SCharles.Forsyth	if (int status != wpid)
411*37da2899SCharles.Forsyth		fatal("bad status in wait");
412*37da2899SCharles.Forsyth	if(status[len status - 1] != ':')
413*37da2899SCharles.Forsyth		fatal(sys->sprint("%s\n", status));
414*37da2899SCharles.Forsyth}
415*37da2899SCharles.Forsyth
416*37da2899SCharles.Forsythshutdown()
417*37da2899SCharles.Forsyth{
418*37da2899SCharles.Forsyth	fd := sys->open("/dev/sysctl", sys->OWRITE);
419*37da2899SCharles.Forsyth	if(fd == nil)
420*37da2899SCharles.Forsyth		fatal("cannot shutdown emu");
421*37da2899SCharles.Forsyth	if (sys->write(fd, array of byte "halt", 4) < 0)
422*37da2899SCharles.Forsyth		fatal(sys->sprint("shutdown: write failed: %r\n"));
423*37da2899SCharles.Forsyth}
424*37da2899SCharles.Forsyth
425*37da2899SCharles.Forsythprefix(s, t : string) : int
426*37da2899SCharles.Forsyth{
427*37da2899SCharles.Forsyth	if (len s <= len t)
428*37da2899SCharles.Forsyth		return t[0:len s] == s;
429*37da2899SCharles.Forsyth	return 0;
430*37da2899SCharles.Forsyth}
431