xref: /inferno-os/appl/cmd/os.b (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
137da2899SCharles.Forsythimplement Os;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsyth	sys: Sys;
537da2899SCharles.Forsyth
637da2899SCharles.Forsythinclude "draw.m";
737da2899SCharles.Forsyth
837da2899SCharles.Forsythinclude "string.m";
937da2899SCharles.Forsyth	str: String;
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsythinclude "arg.m";
1237da2899SCharles.Forsyth
1337da2899SCharles.ForsythOs: module
1437da2899SCharles.Forsyth{
1537da2899SCharles.Forsyth	init:	fn(nil: ref Draw->Context, nil: list of string);
1637da2899SCharles.Forsyth};
1737da2899SCharles.Forsyth
1837da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string)
1937da2899SCharles.Forsyth{
2037da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
2137da2899SCharles.Forsyth	str = load String String->PATH;
2237da2899SCharles.Forsyth	if(str == nil)
2337da2899SCharles.Forsyth		fail(sys->sprint("cannot load %s: %r", String->PATH));
2437da2899SCharles.Forsyth	arg := load Arg Arg->PATH;
2537da2899SCharles.Forsyth	if(arg == nil)
2637da2899SCharles.Forsyth		fail(sys->sprint("cannot load %s: %r", Arg->PATH));
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsyth	arg->init(args);
29*6e425a9dSCharles.Forsyth	arg->setusage("os [-d dir] [-m mount] [-n] [-N nice] [-b] command [arg...]");
3037da2899SCharles.Forsyth
3137da2899SCharles.Forsyth	nice := 0;
3237da2899SCharles.Forsyth	nicearg: string;
3337da2899SCharles.Forsyth	workdir := "";
3437da2899SCharles.Forsyth	mntpoint := "";
35*6e425a9dSCharles.Forsyth	foreground := 1;
36*6e425a9dSCharles.Forsyth
3737da2899SCharles.Forsyth	while((opt := arg->opt()) != 0) {
3837da2899SCharles.Forsyth		case opt {
3937da2899SCharles.Forsyth		'd' =>
4037da2899SCharles.Forsyth			workdir = arg->earg();
4137da2899SCharles.Forsyth		'm' =>
4237da2899SCharles.Forsyth			mntpoint = arg->earg();
4337da2899SCharles.Forsyth		'n' =>
4437da2899SCharles.Forsyth			nice = 1;
4537da2899SCharles.Forsyth		'N' =>
4637da2899SCharles.Forsyth			nice = 1;
4737da2899SCharles.Forsyth			nicearg = sys->sprint(" %q", arg->earg());
48*6e425a9dSCharles.Forsyth		'b' =>
49*6e425a9dSCharles.Forsyth			foreground = 0;
5037da2899SCharles.Forsyth		* =>
5137da2899SCharles.Forsyth			arg->usage();
5237da2899SCharles.Forsyth		}
5337da2899SCharles.Forsyth	}
5437da2899SCharles.Forsyth	args = arg->argv();
5537da2899SCharles.Forsyth	if (args == nil)
5637da2899SCharles.Forsyth		arg->usage();
5737da2899SCharles.Forsyth	arg = nil;
5837da2899SCharles.Forsyth
5937da2899SCharles.Forsyth	sys->pctl(Sys->FORKNS, nil);
6037da2899SCharles.Forsyth	sys->bind("#p", "/prog", Sys->MREPL);		# don't worry if it fails
6137da2899SCharles.Forsyth	if(mntpoint == nil){
6237da2899SCharles.Forsyth		mntpoint = "/cmd";
6337da2899SCharles.Forsyth		if(sys->stat(mntpoint+"/clone").t0 == -1)
6437da2899SCharles.Forsyth		if(sys->bind("#C", "/", Sys->MBEFORE) < 0)
6537da2899SCharles.Forsyth			fail(sys->sprint("bind #C /: %r"));
6637da2899SCharles.Forsyth	}
6737da2899SCharles.Forsyth
6837da2899SCharles.Forsyth	cfd := sys->open(mntpoint+"/clone", sys->ORDWR);
6937da2899SCharles.Forsyth	if(cfd == nil)
7037da2899SCharles.Forsyth		fail(sys->sprint("cannot open /cmd/clone: %r"));
7137da2899SCharles.Forsyth
7237da2899SCharles.Forsyth	buf := array[32] of byte;
7337da2899SCharles.Forsyth	if((n := sys->read(cfd, buf, len buf)) <= 0)
7437da2899SCharles.Forsyth		fail(sys->sprint("cannot read /cmd/clone: %r"));
7537da2899SCharles.Forsyth
7637da2899SCharles.Forsyth	dir := mntpoint+"/"+string buf[0:n];
7737da2899SCharles.Forsyth
7837da2899SCharles.Forsyth	wfd := sys->open(dir+"/wait", Sys->OREAD);
7937da2899SCharles.Forsyth	if(nice && sys->fprint(cfd, "nice%s", nicearg) < 0)
8037da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "os: warning: can't set nice priority: %r\n");
8137da2899SCharles.Forsyth
8237da2899SCharles.Forsyth	if(workdir != nil && sys->fprint(cfd, "dir %s", workdir) < 0)
8337da2899SCharles.Forsyth		fail(sys->sprint("cannot set cwd %q: %r", workdir));
8437da2899SCharles.Forsyth
85*6e425a9dSCharles.Forsyth	if(foreground && sys->fprint(cfd, "killonclose") < 0)
8637da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "os: warning: cannot write killonclose: %r\n");
8737da2899SCharles.Forsyth
8837da2899SCharles.Forsyth	if(sys->fprint(cfd, "exec %s", str->quoted(args)) < 0)
8937da2899SCharles.Forsyth		fail(sys->sprint("cannot exec: %r"));
9037da2899SCharles.Forsyth
91*6e425a9dSCharles.Forsyth	if(foreground){
9237da2899SCharles.Forsyth		if((tocmd := sys->open(dir+"/data", sys->OWRITE)) == nil)
9337da2899SCharles.Forsyth			fail(sys->sprint("canot open %s/data for writing: %r", dir));
9437da2899SCharles.Forsyth		if((fromcmd := sys->open(dir+"/data", sys->OREAD)) == nil)
9537da2899SCharles.Forsyth			fail(sys->sprint("cannot open %s/data for reading: %r", dir));
96*6e425a9dSCharles.Forsyth		if((errcmd := sys->open(dir+"/stderr", sys->OREAD)) == nil)
97*6e425a9dSCharles.Forsyth			fail(sys->sprint("cannot open %s/stderr for reading: %r", dir));
9837da2899SCharles.Forsyth
9937da2899SCharles.Forsyth		spawn copy(sync := chan of int, nil, sys->fildes(0), tocmd);
10037da2899SCharles.Forsyth		pid := <-sync;
10137da2899SCharles.Forsyth		tocmd = nil;
10237da2899SCharles.Forsyth
103*6e425a9dSCharles.Forsyth		spawn copy(sync, nil, errcmd, sys->fildes(2));
104*6e425a9dSCharles.Forsyth		epid := <-sync;
105*6e425a9dSCharles.Forsyth		sync = nil;
106*6e425a9dSCharles.Forsyth		errcmd = nil;
107*6e425a9dSCharles.Forsyth
10837da2899SCharles.Forsyth		spawn copy(nil, done := chan of int, fromcmd, sys->fildes(1));
109*6e425a9dSCharles.Forsyth		fromcmd = nil;
11037da2899SCharles.Forsyth
11137da2899SCharles.Forsyth		# cfd is still open, so if we're killgrp'ed and we're on a platform
11237da2899SCharles.Forsyth		# (e.g. windows) where the fromcmd read is uninterruptible,
11337da2899SCharles.Forsyth		# cfd will be closed, so the command will be killed (due to killonclose), and
11437da2899SCharles.Forsyth		# the fromcmd read should complete, allowing that process to be killed.
11537da2899SCharles.Forsyth
11637da2899SCharles.Forsyth		<-done;
11737da2899SCharles.Forsyth		kill(pid);
118*6e425a9dSCharles.Forsyth		kill(epid);
119*6e425a9dSCharles.Forsyth	}
12037da2899SCharles.Forsyth
12137da2899SCharles.Forsyth	if(wfd != nil){
12237da2899SCharles.Forsyth		status := array[1024] of byte;
12337da2899SCharles.Forsyth		n = sys->read(wfd, status, len status);
12437da2899SCharles.Forsyth		if(n < 0)
12537da2899SCharles.Forsyth			fail(sys->sprint("wait error: %r"));
12637da2899SCharles.Forsyth		s := string status[0:n];
12737da2899SCharles.Forsyth		if(s != nil){
12837da2899SCharles.Forsyth			# pid user sys real status
12937da2899SCharles.Forsyth			flds := str->unquoted(s);
13037da2899SCharles.Forsyth			if(len flds < 5)
13137da2899SCharles.Forsyth				fail(sys->sprint("wait error: odd status: %q", s));
13237da2899SCharles.Forsyth			s = hd tl tl tl tl flds;
13337da2899SCharles.Forsyth			if(0)
13437da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "WAIT: %q\n", s);
13537da2899SCharles.Forsyth			if(s != nil)
13637da2899SCharles.Forsyth				raise "fail:host: "+s;
13737da2899SCharles.Forsyth		}
13837da2899SCharles.Forsyth	}
13937da2899SCharles.Forsyth}
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsythcopy(sync, done: chan of int, f, t: ref Sys->FD)
14237da2899SCharles.Forsyth{
14337da2899SCharles.Forsyth	if(sync != nil)
14437da2899SCharles.Forsyth		sync <-= sys->pctl(0, nil);
14537da2899SCharles.Forsyth	buf := array[8192] of byte;
14637da2899SCharles.Forsyth	for(;;) {
14737da2899SCharles.Forsyth		r := sys->read(f, buf, len buf);
14837da2899SCharles.Forsyth		if(r <= 0)
14937da2899SCharles.Forsyth			break;
15037da2899SCharles.Forsyth		w := sys->write(t, buf, r);
15137da2899SCharles.Forsyth		if(w != r)
15237da2899SCharles.Forsyth			break;
15337da2899SCharles.Forsyth	}
15437da2899SCharles.Forsyth	if(done != nil)
15537da2899SCharles.Forsyth		done <-= 1;
15637da2899SCharles.Forsyth}
15737da2899SCharles.Forsyth
15837da2899SCharles.Forsythkill(pid: int)
15937da2899SCharles.Forsyth{
16037da2899SCharles.Forsyth	fd := sys->open("#p/"+string pid+"/ctl", sys->OWRITE);
16137da2899SCharles.Forsyth	sys->fprint(fd, "kill");
16237da2899SCharles.Forsyth}
16337da2899SCharles.Forsyth
16437da2899SCharles.Forsythfail(msg: string)
16537da2899SCharles.Forsyth{
16637da2899SCharles.Forsyth	sys->fprint(sys->fildes(2), "os: %s\n", msg);
16737da2899SCharles.Forsyth	raise "fail:"+msg;
16837da2899SCharles.Forsyth}
169