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