[inferno-npe] 2 new revisions pushed by extrudedaluminiu on 2010-02-12 17:47 GMT

3 views
Skip to first unread message

infer...@googlecode.com

unread,
Feb 12, 2010, 12:47:52 PM2/12/10
to inferno-n...@googlegroups.com
2 new revisions:

Revision: 19448eabba
Author: me@challenger
Date: Fri Feb 12 09:30:14 2010
Log: Import 9cpu from Roger Peppe's infauth framework....
http://code.google.com/p/inferno-npe/source/detail?r=19448eabba

Revision: 75a1e5db6f
Author: me@challenger
Date: Fri Feb 12 09:46:25 2010
Log: Add ksd_rundtors() to pexit on all hosted platforms.
http://code.google.com/p/inferno-npe/source/detail?r=75a1e5db6f

==============================================================================
Revision: 19448eabba
Author: me@challenger
Date: Fri Feb 12 09:30:14 2010
Log: Import 9cpu from Roger Peppe's infauth framework.

Allows connecting to Plan 9 CPU servers.
http://code.google.com/p/inferno-npe/source/detail?r=19448eabba

Added:
/appl/authsrc/9cpu.b
/appl/authsrc/fdrun.b
/appl/authsrc/mkfile
/appl/authsrc/remotesh.b
/appl/authsrc/winsrv.b
/man/2/fdrun
/module/fdrun.m
Modified:
/appl/mkfile
/lib/ndb/local

=======================================
--- /dev/null
+++ /appl/authsrc/9cpu.b Fri Feb 12 09:30:14 2010
@@ -0,0 +1,455 @@
+implement P9cpu;
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "arg.m";
+include "sh.m";
+ sh: Sh;
+include "fdrun.m";
+ fdrun: FDrun;
+include "factotum.m";
+include "encoding.m";
+ b64: Encoding;
+include "keyring.m";
+include "security.m";
+
+# to do/test:
+# - inferno command
+# - garbage process collection
+
+# issues around factotum with inferno:
+#
+# key retention - adding keys to secstore is not easy, as it
+# has to be done manually, and keys obtained with
+# getauthinfo are somewhat unwieldy.
+# we don't want to have to do a getauthinfo
+# every time we start factotum.
+#
+# algorithm negotiation - would it be reasonable to
+# add algorithm specification to keyspec?
+# e.g. proto=infauth role=server 'algs=rc4_256 sha1 md5'
+# or proto=infauth role=client 'alg=rc4_256/sha1'
+# if not, how can the desired/allowed algorithm(s) be specified?
+
+MaxStr: con 128; # as defined in /sys/src/cmd/cpu.c
+
+P9cpu: module {
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+authmethods := array[] of {"p9", "netkey"};
+finish: chan of int;
+
+init(ctxt: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ sh = load Sh Sh->PATH;
+ b64 = load Encoding Encoding->BASE64PATH;
+ arg := load Arg Arg->PATH;
+ fdrun = load FDrun FDrun->PATH;
+ fdrun->init();
+
+ authmethod := "p9";
+ keyspec := "";
+ ealgs := "rc4_256 sha1";
+ wmexport := 0;
+ p9win := 0;
+ infernocmd := 0;
+ relaynotes := 1;
+ p9winopts: list of string;
+ system := "";
+ cmd := "";
+
+ arg->init(argv);
+ arg->setusage("9cpu [-wrIn] [-e crypto_algs] [-a auth_method] [-k
keyspec] [-c cmd] [-h system]");
+ while((opt := arg->opt()) != 0){
+ case opt {
+ 'a' =>
+ authmethod = arg->earg();
+ 'k' =>
+ keyspec = arg->earg();
+ 'e' =>
+ ealgs = arg->earg();
+ 'w' =>
+ wmexport = 1;
+ 'r' =>
+ p9win = 1;
+ 'I' =>
+ infernocmd = 1;
+ wmexport = 1;
+ 'n' =>
+ relaynotes = 0;
+ 'x' =>
+ p9winopts = "-x"+arg->earg() :: p9winopts;
+ 'y' =>
+ p9winopts = "-y"+arg->earg() :: p9winopts;
+ 'h' =>
+ system = arg->earg();
+ 'c' =>
+ cmd = arg->earg();
+ * =>
+ arg->usage();
+ }
+ }
+ argv = arg->argv();
+ if(argv != nil)
+ arg->usage();
+ for(i := 0; i < len authmethods; i++)
+ if(authmethod == authmethods[i])
+ break;
+ if(i == len authmethods)
+ fatal(sys->sprint("unknown authentication method %q", authmethod));
+
+ sys->pctl(Sys->FORKNS, nil);
+ (dfd, err) := rexcall(system, authmethod, keyspec, ealgs);
+ if(dfd == nil)
+ fatal(err);
+ if(p9win && cmd == nil)
+ cmd = "rio";
+ else if(infernocmd){
+ if(cmd == nil)
+ cmd = "sh -i";
+ cmd = "emu /dis/sh -c "+
+ shquoted("{"+
+ "bind '#U*' /n/local;"+
+ "wmimport -d /n/local/mnt/term/dev -w /n/local/mnt/term/mnt/wm sh -c "+
+ shquoted(cmd)+
+ "}"
+ );
+ }
+ finish = chan[1] of int;
+ if(cmd != nil){
+ # guard against limited size command buffer at other end.
+ if(len array of byte cmd + 3 > MaxStr){
+ writestr(dfd, "! . /mnt/term/dev/cpucmd", "command", 0);
+ spawn servefileproc(sync := chan of int, "/dev", "cpucmd", array of
byte (cmd+"\n"));
+ <-sync;
+ }else
+ writestr(dfd, "! "+cmd, "command", 0);
+ }
+ cwd := sys->fd2path(sys->open(".", Sys->OREAD));
+ if(cwd == nil)
+ writestr(dfd, "NO", "dir", 0);
+ else
+ writestr(dfd, cwd, "dir", 0);
+
+ (ok, data) := readstr(dfd, '\0');
+ if(ok == -1)
+ fatal("waiting for FS");
+ if(len data < 2 || data[0:2] != "FS")
+ fatal("remote cpu: "+data);
+ exdir: string;
+ (ok, exdir) = readstr(dfd, '\0');
+ if(exdir != "/")
+ fatal("cannot export portion of namespace");
+
+ sys->write(dfd, array[] of {byte 'O', byte 'K'}, 2);
+
+ # set up the namespace that we wish to export
+ if(wmexport){
+ sys->pipe(p := array[2] of ref Sys->FD);
+ fdrun->run(ctxt, "wmexport"::nil, "0--", p[0:1], chan[1] of string);
+ sys->mount(p[1], nil, "/mnt/wm", Sys->MREPL, nil);
+ }
+ if(relaynotes && !p9win){
+ spawn relaynotesproc(sync := chan of int);
+ <-sync;
+ }
+
+ if(p9win){
+ fdrun->run(ctxt, "9win"::"-s"::p9winopts, "0--", array[] of {dfd},
status := chan of string);
+ err = <-status;
+ finish <-= 1;
+ if(err != nil)
+ raise "fail:"+err;
+ }else{
+ if(sys->export(dfd, "/", Sys->EXPWAIT) == -1)
+ sys->print("export error: %r\n");
+ finish <-= 1;
+ }
+}
+
+shquoted(s: string): string
+{
+ return sh->quoted(ref Sh->Listnode(nil, s)::nil, 1);
+}
+
+rexcall(system, authmethod, keyspec, ealgs: string): (ref Sys->FD, string)
+{
+ Negerr: con "negotiating authentication method";
+ na := netmkaddr(system, nil, "ncpu");
+ (ok, c) := sys->dial(na, nil);
+ if(ok == -1)
+ return (nil, sys->sprint("cannot dial %q: %r", na));
+
+ # plan 9 cpu protocol
+ a := authmethod;
+ if(ealgs != nil)
+ a += " " + ealgs;
+ writestr(c.dfd, a, Negerr, 0);
+ err: string;
+ (ok, err) = readstr(c.dfd, '\0');
+ if(ok == -1)
+ return (nil, Negerr);
+ if(err != nil)
+ return (nil, "readstr: "+err);
+
+ case authmethod {
+ "p9" =>
+ return p9auth(c.dfd, ealgs, keyspec);
+ "netkey" =>
+ return netkeyauth(c.dfd);
+ }
+ return (nil, "unknown auth method");
+}
+
+netkeyauth(fd: ref Sys->FD): (ref Sys->FD, string)
+{
+ (ok, user) := ask("user["+getuser()+"]", getuser());
+ if(ok == -1)
+ return (nil, "terminated");
+ writestr(fd, user, "challenge/response", 1);
+ for(;;){
+ chall: string;
+ (ok, chall) = readstr(fd, '\0');
+ if(ok == -1)
+ return (nil, sys->sprint("readstr: %r"));
+ if(chall == nil)
+ return (fd, nil);
+ resp: string;
+ (ok, resp) = ask("challenge: "+chall+"; response", nil);
+ if(ok == -1)
+ break;
+ writestr(fd, resp, "challenge/response", 1);
+ }
+ return (nil, "terminated");
+}
+
+ask(q: string, default: string): (int, string)
+{
+ sys->print("%s: ", q);
+ (ok, s) := readstr(sys->fildes(0), '\n');
+ if(ok == -1)
+ return (-1, nil);
+ if(s == nil)
+ return (0, default);
+ return (0, s);
+}
+
+p9auth(fd: ref Sys->FD, ealgs, keyspec: string): (ref Sys->FD, string)
+{
+ factotum := load Factotum Factotum->PATH;
+ if(factotum == nil)
+ return (nil, sys->sprint("cannot load %q: %r", Factotum->PATH));
+ factotum->init();
+ keyring := load Keyring Keyring->PATH;
+ if(keyring == nil)
+ return (nil, sys->sprint("cannot load %q: %r", Keyring->PATH));
+ ai := factotum->proxy(fd, sys->open("/mnt/factotum/rpc", Sys->ORDWR),
+ sys->sprint("proto=p9any role=client %s", keyspec));
+ if(ai == nil)
+ return (nil, sys->sprint("factotum: %r"));
+ if(len ai.secret != 8)
+ return (nil, "expected different length of secret");
+
+ if(ealgs == nil)
+ return (fd, nil);
+
+ key := array[16] of byte;
+ key[4:] = ai.secret;
+ randombytes(key[0:4]);
+ if(sys->write(fd, key, 4) != 4)
+ return (nil, sys->sprint("write: %r"));
+ if(readn(fd, key[12:], 4) != 4)
+ return (nil, sys->sprint("read: %r"));
+ digest := array[Keyring->SHA1dlen] of byte;
+ keyring->sha1(key, len key, digest, nil);
+ (efd, err) := pushssl(fd, ealgs, mksecret(digest), mksecret(digest[10:]));
+ if(efd == nil)
+ return (nil, sys->sprint("cannot push ssl: %s", err));
+ return (efd, nil);
+}
+
+# plan 9 bug/strangeness: interpret hex string as base64 to use as secret.
+mksecret(f: array of byte): array of byte
+{
+ return b64->dec(
+ sys->sprint(
+ "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
+ int f[0], int f[1], int f[2], int f[3], int f[4],
+ int f[5], int f[6], int f[7], int f[8], int f[9])
+ );
+}
+
+# set up shell window button; relay events from that
+relaynotesproc(sync: chan of int)
+{
+ shctl := sys->open("/chan/shctl", Sys->OWRITE);
+ if(shctl == nil){
+ sys->fprint(sys->fildes(2), "cpu: cannot relay notes: not in shell
window\n");
+ sync <-= -1;
+ exit;
+ }
+ sys->fprint(shctl, "clear");
+ if(sys->fprint(shctl, "action Interrupt interrupt") == -1){
+ sys->fprint(sys->fildes(2), "cpu: cannot create interrupt button: %r\n");
+ sync <-= -1;
+ exit;
+ }
+ # create dummy placeholder file
+ fio := file2chan("/dev", "cpunote");
+
+ sys->bind("/chan/shctl", "/dev/cpunote", Sys->MREPL);
+ sync <-= 0;
+ finish <-= <-finish;
+ sys->fprint(shctl, "clear");
+ fio = nil;
+}
+
+file2chan(d, f: string): ref Sys->FileIO
+{
+ if((fio := sys->file2chan(d, f)) == nil){
+ sys->bind("#s", "/dev", Sys->MBEFORE);
+ fio = sys->file2chan(d, f);
+ }
+ return fio;
+}
+
+servefileproc(sync: chan of int, d, f: string, data: array of byte)
+{
+ fio := file2chan(d, f);
+ sync <-= sys->pctl(0, nil);
+ for(;;)alt{
+ (offset, nil, nil, rc) := <-fio.read =>
+ if(rc != nil){
+ if(offset > len data)
+ offset = len data;
+ rc <-= (data[offset:], nil);
+ }
+ (nil, nil, nil, wc) := <-fio.write =>
+ if(wc != nil)
+ wc <-= (-1, "permission denied");
+ <-finish =>
+ finish <-= 1;
+ exit;
+ }
+}
+
+pushssl(fd: ref Sys->FD, ealgs: string, secretin, secretout: array of
byte): (ref Sys->FD, string)
+{
+ ssl := load SSL SSL->PATH;
+ if(ssl == nil)
+ return (nil, sys->sprint("canot load %q: %r", SSL->PATH));
+ (err, c) := ssl->connect(fd);
+ if(err != nil)
+ return (nil, "can't connect ssl: " + err);
+
+ err = ssl->secret(c, secretin, secretout);
+ if(err != nil)
+ return (nil, "can't write secret: " + err);
+
+ if(sys->fprint(c.cfd, "alg %s", ealgs) < 0)
+ return (nil, sys->sprint("can't push algorithm %s: %r", ealgs));
+
+ return (c.dfd, nil);
+}
+
+writestr(fd: ref Sys->FD, s: string, thing: string, ignore: int)
+{
+ x := array of byte s;
+ x0 := array[len x+1] of byte;
+ x0[0:] = x;
+ x0[len x] = byte 0;
+ n := sys->write(fd, x0, len x0);
+ if(!ignore && n != len x0)
+ fatal(sys->sprint("writing network: %s: %r", thing));
+}
+
+readstr(fd: ref Sys->FD, c: int): (int, string)
+{
+ buf := array[128] of byte;
+ b := buf;
+ l := 0;
+ while(len b > 0){
+ n := sys->read(fd, b, 1);
+ if(n <= 0)
+ return (-1, nil);
+ if(int b[0] == c)
+ return (0, string buf[0:l]);
+ l++;
+ b = b[1:];
+ }
+ return (-1, nil);
+}
+
+netmkaddr(addr, net, svc: string): string
+{
+ if(net == nil)
+ net = "net";
+ (n, nil) := sys->tokenize(addr, "!");
+ if(n <= 1){
+ if(svc== nil)
+ return sys->sprint("%s!%s", net, addr);
+ return sys->sprint("%s!%s!%s", net, addr, svc);
+ }
+ if(svc == nil || n > 2)
+ return addr;
+ return sys->sprint("%s!%s", addr, svc);
+}
+
+randombytes(buf: array of byte): int
+{
+ fd := sys->open("/dev/notquiterandom", Sys->OREAD);
+ if(fd == nil)
+ return -1;
+ if(sys->read(fd, buf, len buf) != len buf)
+ return -1;
+ return 0;
+}
+
+getuser(): string
+{
+ if ((s := readfile("/dev/user")) == nil)
+ return "none";
+ return s;
+}
+
+readfile(f: string): string
+{
+ fd := sys->open(f, sys->OREAD);
+ if(fd == nil)
+ return nil;
+
+ buf := array[8192] of byte;
+ n := sys->read(fd, buf, len buf);
+ if(n < 0)
+ return nil;
+
+ return string buf[0:n];
+}
+
+readn(fd: ref Sys->FD, buf: array of byte, nb: int): int
+{
+ for(nr := 0; nr < nb;){
+ n := sys->read(fd, buf[nr:], nb-nr);
+ if(n <= 0){
+ if(nr == 0)
+ return n;
+ break;
+ }
+ nr += n;
+ }
+ return nr;
+}
+
+fatal(err: string)
+{
+ sys->fprint(sys->fildes(2), "cpu: %s\n", err);
+ raise "fail:error";
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
=======================================
--- /dev/null
+++ /appl/authsrc/fdrun.b Fri Feb 12 09:30:14 2010
@@ -0,0 +1,63 @@
+implement FDrun;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+include "fdrun.m";
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ sh = load Sh Sh->PATH;
+}
+
+# run command args; spec specifies how to arrange the file descriptors
+# for the command; spec[i] specifies how to arrange fd i; a decimal digit
n,
+# means use sfds[n]; 'x' means use /dev/null; '-' means leave untouched.
+# status of command is sent down result.
+run(ctxt: ref Draw->Context, args: list of string, spec: string, sfds:
array of ref Sys->FD, result: chan of string): int
+{
+ fds := array[len spec] of ref Sys->FD;
+ for(i := 0; i < len spec; i++){
+ case spec[i] {
+ 'x' =>
+ fds[i] = sys->open("/dev/null", Sys->ORDWR);
+ '-' =>
+ ;
+ '0' to '9' =>
+ p := spec[i] - '0';
+ if(p >= len sfds){
+ sys->werrstr("fd array too short");
+ return -1;
+ }
+ fds[i] = sfds[p];
+ * =>
+ sys->werrstr("invalid character in spec");
+ return -1;
+ }
+ }
+ sfds = nil;
+ spawn runpipe(ctxt, args, fds, sync := chan of int, result);
+ <-sync;
+ return 0;
+}
+
+runpipe(ctxt: ref Draw->Context,
+ args: list of string,
+ fds: array of ref Sys->FD,
+ sync: chan of int,
+ result: chan of string)
+{
+ sys->pctl(Sys->FORKFD, nil);
+ fl: list of int;
+ for(i := 0; i < len fds; i++){
+ if(fds[i] != nil && fds[i].fd != i)
+ sys->dup(fds[i].fd, i);
+ fl = i :: fl;
+ }
+ fds = nil;
+ sys->pctl(Sys->NEWFD, fl);
+ sync <-= 0;
+ result <-= sh->run(ctxt, args);
+}
=======================================
--- /dev/null
+++ /appl/authsrc/mkfile Fri Feb 12 09:30:14 2010
@@ -0,0 +1,15 @@
+<../../mkconfig
+
+TARG=\
+ 9cpu.dis\
+ fdrun.dis\
+ remotesh.dis\
+ winsrv.dis\
+
+SYSMODULES=\
+ fdrun.m\
+
+DISBIN=$ROOT/dis
+
+<$ROOT/mkfiles/mkdis
+
=======================================
--- /dev/null
+++ /appl/authsrc/remotesh.b Fri Feb 12 09:30:14 2010
@@ -0,0 +1,858 @@
+implement WmSh;
+
+include "sys.m";
+ sys: Sys;
+ FileIO: import sys;
+
+include "draw.m";
+ draw: Draw;
+ Context, Rect: import draw;
+
+include "tk.m";
+ tk: Tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+include "plumbmsg.m";
+ plumbmsg: Plumbmsg;
+ Msg: import plumbmsg;
+
+include "workdir.m";
+
+include "string.m";
+ str: String;
+
+include "arg.m";
+
+WmSh: module
+{
+ init: fn(ctxt: ref Draw->Context, args: list of string);
+};
+
+Command: type WmSh;
+
+BSW: con 23; # ^w bacspace word
+BSL: con 21; # ^u backspace line
+EOT: con 4; # ^d end of file
+ESC: con 27; # hold mode
+
+# XXX line-based limits are inadequate - memory is still
+# blown if a client writes a very long line.
+HIWAT: con 2000; # maximum number of lines in transcript
+LOWAT: con 1500; # amount to reduce to after high water
+
+Name: con "Shell";
+
+Rdreq: adt
+{
+ off: int;
+ nbytes: int;
+ fid: int;
+ rc: chan of (array of byte, string);
+};
+
+shwin_cfg := array[] of {
+ "menu .m",
+ ".m add command -text noscroll -command {send edit noscroll}",
+ ".m add command -text cut -command {send edit cut}",
+ ".m add command -text paste -command {send edit paste}",
+ ".m add command -text snarf -command {send edit snarf}",
+ ".m add command -text send -command {send edit send}",
+ "frame .b -bd 1 -relief ridge",
+ "frame .ft -bd 0",
+ "scrollbar .ft.scroll -command {send scroll t}",
+ "text .ft.t -bd 1 -relief flat -yscrollcommand {send scroll s} -bg white
-selectforeground black -selectbackground #CCCCCC",
+ ".ft.t tag configure sel -relief flat",
+ "pack .ft.scroll -side left -fill y",
+ "pack .ft.t -fill both -expand 1",
+ "pack .Wm_t -fill x",
+ "pack .b -anchor w -fill x",
+ "pack .ft -fill both -expand 1",
+ "focus .ft.t",
+ "bind .ft.t <Key> {send keys {%A}}",
+ "bind .ft.t <Control-d> {send keys {%A}}",
+ "bind .ft.t <Control-h> {send keys {%A}}",
+ "bind .ft.t <Control-w> {send keys {%A}}",
+ "bind .ft.t <Control-u> {send keys {%A}}",
+ "bind .ft.t <Button-1> +{send but1 pressed}",
+ "bind .ft.t <Double-Button-1> +{send but1 pressed}",
+ "bind .ft.t <ButtonRelease-1> +{send but1 released}",
+ "bind .ft.t <ButtonPress-2> {send but2 %X %Y}",
+ "bind .ft.t <Motion-Button-2-Button-1> {}",
+ "bind .ft.t <Motion-ButtonPress-2> {}",
+ "bind .ft.t <ButtonPress-3> {send but3 pressed}",
+ "bind .ft.t <ButtonRelease-3> {send but3 released %x %y}",
+ "bind .ft.t <Motion-Button-3> {}",
+ "bind .ft.t <Motion-Button-3-Button-1> {}",
+ "bind .ft.t <Double-Button-3> {}",
+ "bind .ft.t <Double-ButtonRelease-3> {}",
+};
+
+rdreq: list of Rdreq;
+menuindex := "0";
+holding := 0;
+plumbed := 0;
+rawon := 0;
+rawinput := "";
+scrolling := 1;
+partialread: array of byte;
+cwd := "";
+width, height, font: string;
+
+events: list of string;
+evrdreq: list of Rdreq;
+winname: string;
+srvdir: string;
+runshell := 1;
+
+badmod(p: string)
+{
+ sys->print("wm/sh: cannot load %s: %r\n", p);
+ raise "fail:bad module";
+}
+
+init(ctxt: ref Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ tk = load Tk Tk->PATH;
+
+ tkclient = load Tkclient Tkclient->PATH;
+ if (tkclient == nil)
+ badmod(Tkclient->PATH);
+
+ str = load String String->PATH;
+ if (str == nil)
+ badmod(String->PATH);
+
+ arg := load Arg Arg->PATH;
+ if (arg == nil)
+ badmod(Arg->PATH);
+ arg->init(argv);
+ arg->setusage("wm/sh [-ilxvn] [-w width] [-h height] [-f font] [-c
command] [file [args...]");
+
+ plumbmsg = load Plumbmsg Plumbmsg->PATH;
+
+ shargs: list of string;
+ while ((opt := arg->opt()) != 0) {
+ case opt {
+ 'w' =>
+ width = arg->earg();
+ 'h' =>
+ height = arg->earg();
+ 'f' =>
+ font = arg->earg();
+ 's' =>
+ srvdir = arg->earg();
+ runshell = 0;
+ 'c' =>
+ shargs = arg->earg() :: "-c" :: shargs;
+ 'i' or 'l' or 'x' or 'v' or 'n' =>
+ shargs = sys->sprint("-%c", opt) :: shargs;
+ * =>
+ arg->usage();
+ }
+ }
+ argv = arg->argv();
+ for (; shargs != nil; shargs = tl shargs)
+ argv = hd shargs :: argv;
+
+ sys->pctl(Sys->NEWPGRP | Sys->FORKENV, nil);
+ if(srvdir == nil){
+ sys->pctl(Sys->FORKNS, nil);
+ srvdir = "/chan";
+ }
+
+ tkclient->init();
+ if (ctxt == nil)
+ ctxt = tkclient->makedrawcontext();
+ if(ctxt == nil){
+ sys->fprint(sys->fildes(2), "sh: no window context\n");
+ raise "fail:bad context";
+ }
+
+ if(plumbmsg != nil && plumbmsg->init(1, nil, 0) >= 0){
+ plumbed = 1;
+ workdir := load Workdir Workdir->PATH;
+ cwd = workdir->init();
+ }
+
+ winname = Name + " " + cwd;
+
+ spawn main(ctxt, argv, sync := chan of int);
+ if(<-sync == -1)
+ raise "fail:initialisation error";
+}
+
+task(t: ref Tk->Toplevel)
+{
+ tkclient->wmctl(t, "task");
+}
+
+atend(t: ref Tk->Toplevel, w: string): int
+{
+ s := cmd(t, w+" yview");
+ for(i := 0; i < len s; i++)
+ if(s[i] == ' ')
+ break;
+ return i == len s - 2 && s[i+1] == '1';
+}
+
+main(ctxt: ref Draw->Context, argv: list of string, sync: chan of int)
+{
+ (t, titlectl) := tkclient->toplevel(ctxt, "", winname, Tkclient->Appl);
+ wm := t.ctxt;
+
+ edit := chan of string;
+ tk->namechan(t, edit, "edit");
+
+ keys := chan of string;
+ tk->namechan(t, keys, "keys");
+
+ butcmd := chan of string;
+ tk->namechan(t, butcmd, "button");
+
+ event := chan of string;
+ tk->namechan(t, event, "action");
+
+ scroll := chan of string;
+ tk->namechan(t, scroll, "scroll");
+
+ but1 := chan of string;
+ tk->namechan(t, but1, "but1");
+ but2 := chan of string;
+ tk->namechan(t, but2, "but2");
+ but3 := chan of string;
+ tk->namechan(t, but3, "but3");
+ button1 := 0;
+ button3 := 0;
+
+ for (i := 0; i < len shwin_cfg; i++)
+ cmd(t, shwin_cfg[i]);
+ (menuw, nil) := itemsize(t, ".m");
+ if (font != nil) {
+ if (font[0] != '/' && (len font == 1 || font[0:2] != "./"))
+ font = "/fonts/" + font;
+ cmd(t, ".ft.t configure -font " + font);
+ }
+ cmd(t, ".ft.t configure -width 65w -height 20h");
+ cmd(t, "pack propagate . 0");
+ if(width != nil)
+ cmd(t, ". configure -width " + width);
+ if(height != nil)
+ cmd(t, ". configure -height " + height);
+ sys->bind("#s", srvdir, sys->MBEFORE);
+ file := sys->file2chan(srvdir, "cons");
+ filectl := sys->file2chan(srvdir, "consctl");
+ shctl := sys->file2chan(srvdir, "shctl");
+ consfile := srvdir+"/cons";
+ if(file == nil || filectl == nil || shctl == nil) {
+ sys->print("newsh: shell cons creation failed: %r\n");
+ sync <-= -1;
+ return;
+ }
+ sync <-= 0;
+ tkclient->onscreen(t, nil);
+ tkclient->startinput(t, "ptr" :: "kbd" :: nil);
+
+
+ if(runshell){
+ spawn newsh(sync, ctxt, argv);
+ <-sync;
+ }
+
+ dummyfwrite := chan of (int, array of byte, int, Sys->Rwrite);
+ fwrite := file.write;
+
+ rdrpc: Rdreq;
+
+ # outpoint is place in text to insert characters printed by programs
+ cmd(t, ".ft.t mark set outpoint 1.0; .ft.t mark gravity outpoint left");
+
+ for(;;) alt {
+ c := <-wm.kbd =>
+ tk->keyboard(t, c);
+ m := <-wm.ptr =>
+ tk->pointer(t, *m);
+ c := <-wm.ctl or
+ c = <-t.wreq or
+ c = <-titlectl =>
+ tkclient->wmctl(t, c);
+ ecmd := <-edit =>
+ editor(t, ecmd);
+ sendinput(t);
+
+ c := <-keys =>
+ cut(t, 1);
+ char := c[1];
+ if(char == '\\')
+ char = c[2];
+ if(rawon){
+ if(int cmd(t, ".ft.t compare insert >= outpoint")){
+ rawinput[len rawinput] = char;
+ sendinput(t);
+ break;
+ }
+ }
+ case char {
+ * =>
+ cmd(t, ".ft.t insert insert "+c);
+ '\n' or
+ EOT =>
+ cmd(t, ".ft.t insert insert "+c);
+ sendinput(t);
+ '\b' =>
+ cmd(t, ".ft.t tkTextDelIns -c");
+ BSL =>
+ cmd(t, ".ft.t tkTextDelIns -l");
+ BSW =>
+ cmd(t, ".ft.t tkTextDelIns -w");
+ ESC =>
+ setholding(t, !holding);
+ }
+ cmd(t, ".ft.t see insert;update");
+
+ c := <-but1 =>
+ button1 = (c == "pressed");
+ button3 = 0; # abort any pending button 3 action
+
+ c := <-but2 =>
+ if(button1){
+ cut(t, 1);
+ cmd(t, "update");
+ break;
+ }
+ (nil, l) := sys->tokenize(c, " ");
+ x := int hd l - menuw/2;
+ y := int hd tl l - int cmd(t, ".m yposition "+menuindex) - 10;
+ cmd(t, ".m activate "+menuindex+"; .m post "+string x+" "+string y+
+ "; update");
+ button3 = 0; # abort any pending button 3 action
+
+ c := <-but3 =>
+ if(c == "pressed"){
+ button3 = 1;
+ if(button1){
+ paste(t);
+ sendinput(t);
+ cmd(t, "update");
+ }
+ break;
+ }
+ if(plumbed == 0 || button3 == 0 || button1 != 0)
+ break;
+ button3 = 0;
+ # plumb message triggered by release of button 3
+ (nil, l) := sys->tokenize(c, " ");
+ x := int hd tl l;
+ y := int hd tl tl l;
+ index := cmd(t, ".ft.t index @"+string x+","+string y);
+ selindex := cmd(t, ".ft.t tag ranges sel");
+ if(selindex != "")
+ insel := cmd(t, ".ft.t compare sel.first <= "+index)=="1" &&
+ cmd(t, ".ft.t compare sel.last >= "+index)=="1";
+ else
+ insel = 0;
+ attr := "";
+ if(insel)
+ text := tk->cmd(t, ".ft.t get sel.first sel.last");
+ else{
+ # have line with text in it
+ # now extract whitespace-bounded string around click
+ (nil, w) := sys->tokenize(index, ".");
+ charno := int hd tl w;
+ left := cmd(t, ".ft.t index {"+index+" linestart}");
+ right := cmd(t, ".ft.t index {"+index+" lineend}");
+ line := tk->cmd(t, ".ft.t get "+left+" "+right);
+ for(i=charno; i>0; --i)
+ if(line[i-1]==' ' || line[i-1]=='\t')
+ break;
+ for(j:=charno; j<len line; j++)
+ if(line[j]==' ' || line[j]=='\t')
+ break;
+ text = line[i:j];
+ attr = "click="+string (charno-i);
+ }
+ msg := ref Msg(
+ "WmSh",
+ "",
+ cwd,
+ "text",
+ attr,
+ array of byte text);
+ if(msg.send() < 0)
+ sys->fprint(sys->fildes(2), "sh: plumbing write error: %r\n");
+ c := <-butcmd =>
+ simulatetype(t, tkunquote(c));
+ sendinput(t);
+ cmd(t, "update");
+ c := <-event =>
+ events = str->append(tkunquote(c), events);
+ if (evrdreq != nil) {
+ rc := (hd evrdreq).rc;
+ rc <-= (array of byte hd events, nil);
+ evrdreq = tl evrdreq;
+ events = tl events;
+ }
+ rdrpc = <-shctl.read =>
+ if(rdrpc.rc == nil)
+ continue;
+ if (events != nil) {
+ rdrpc.rc <-= (array of byte hd events, nil);
+ events = tl events;
+ } else
+ evrdreq = rdrpc :: evrdreq;
+ (nil, data, nil, wc) := <-shctl.write =>
+ if (wc == nil)
+ break;
+ if ((err := shctlcmd(t, string data)) != nil)
+ wc <-= (0, err);
+ else
+ wc <-= (len data, nil);
+ rdrpc = <-filectl.read =>
+ if(rdrpc.rc == nil)
+ continue;
+ rdrpc.rc <-= (nil, "not allowed");
+ (nil, data, nil, wc) := <-filectl.write =>
+ if(wc == nil) {
+ # consctl closed - revert to cooked mode
+ # XXX should revert only on *last* close?
+ rawon = 0;
+ continue;
+ }
+ (nc, cmdlst) := sys->tokenize(string data, " \n");
+ if(nc == 1) {
+ case hd cmdlst {
+ "rawon" =>
+ rawon = 1;
+ rawinput = "";
+ # discard previous input
+ advance := string (len tk->cmd(t, ".ft.t get outpoint end") +1);
+ cmd(t, ".ft.t mark set outpoint outpoint+" + advance + "chars");
+ partialread = nil;
+ "rawoff" =>
+ rawon = 0;
+ partialread = nil;
+ "holdon" =>
+ setholding(t, 1);
+ cmd(t, "update");
+ "holdoff" =>
+ setholding(t, 0);
+ cmd(t, "update");
+ * =>
+ wc <-= (0, "unknown consctl request");
+ continue;
+ }
+ wc <-= (len data, nil);
+ continue;
+ }
+ wc <-= (0, "unknown consctl request");
+
+ rdrpc = <-file.read =>
+ if(rdrpc.rc == nil) {
+ (ok, nil) := sys->stat(consfile);
+ if (ok < 0)
+ return;
+ continue;
+ }
+ append(rdrpc);
+ sendinput(t);
+
+ c := <-scroll =>
+ if(c[0] == 't'){
+ cmd(t, ".ft.t yview "+c[1:]+";update");
+ if(scrolling)
+ fwrite = file.write;
+ else if(atend(t, ".ft.t"))
+ fwrite = file.write;
+ else
+ fwrite = dummyfwrite;
+ }else{
+ cmd(t, ".ft.scroll set "+c[1:]+";update");
+ if(atend(t, ".ft.t") && fwrite == dummyfwrite)
+ fwrite = file.write;
+ }
+ (nil, data, nil, wc) := <-fwrite =>
+ if(wc == nil) {
+ (ok, nil) := sys->stat(consfile);
+ if (ok < 0)
+ return;
+ continue;
+ }
+ needscroll := atend(t, ".ft.t");
+ cdata := cursorcontrol(t, string data);
+ ncdata := string len cdata + "chars;";
+ cmd(t, ".ft.t insert outpoint '"+ cdata);
+ wc <-= (len data, nil);
+ data = nil;
+ s := ".ft.t mark set outpoint outpoint+" + ncdata;
+ if(!atend(t, ".ft.t") && scrolling == 0)
+ fwrite = dummyfwrite;
+ else if(needscroll)
+ s += ".ft.t see outpoint;";
+ s += "update";
+ cmd(t, s);
+ nlines := int cmd(t, ".ft.t index end");
+ if(nlines > HIWAT){
+ s = ".ft.t delete 1.0 "+ string (nlines-LOWAT) +".0;update";
+ cmd(t, s);
+ }
+ }
+}
+
+setholding(t: ref Tk->Toplevel, hold: int)
+{
+ if(hold == holding)
+ return;
+ holding = hold;
+ color := "blue";
+ if(!holding){
+ color = "black";
+ tkclient->settitle(t, winname);
+ sendinput(t);
+ }else
+ tkclient->settitle(t, winname+" (holding)");
+ cmd(t, ".ft.t configure -foreground "+color);
+}
+
+tkunquote(s: string): string
+{
+ if (s == nil)
+ return nil;
+ t: string;
+ if (s[0] != '{' || s[len s - 1] != '}')
+ return s;
+ for (i := 1; i < len s - 1; i++) {
+ if (s[i] == '\\')
+ i++;
+ t[len t] = s[i];
+ }
+ return t;
+}
+
+buttonid := 0;
+shctlcmd(win: ref Tk->Toplevel, c: string): string
+{
+ toks := str->unquoted(c);
+ if (toks == nil)
+ return "null command";
+ n := len toks;
+ case hd toks {
+ "button" or
+ "action"=>
+ # (button|action) title sendtext
+ if (n != 3)
+ return "bad usage";
+ id := ".b.b" + string buttonid++;
+ cmd(win, "button " + id + " -text " + tk->quote(hd tl toks) +
+ " -command 'send " + hd toks + " " + tk->quote(hd tl tl toks));
+ cmd(win, "pack " + id + " -side left");
+ cmd(win, "pack propagate .b 0");
+ "clear" =>
+ cmd(win, "pack propagate .b 1");
+ for (i := 0; i < buttonid; i++)
+ cmd(win, "destroy .b.b" + string i);
+ buttonid = 0;
+ "cwd" =>
+ if (n != 2)
+ return "bad usage";
+ cwd = hd tl toks;
+ winname = Name + " " + cwd;
+ tkclient->settitle(win, winname);
+ * =>
+ return "bad command";
+ }
+ cmd(win, "update");
+ return nil;
+}
+
+
+RPCread: type (int, int, int, chan of (array of byte, string));
+
+append(r: RPCread)
+{
+ t := r :: nil;
+ while(rdreq != nil) {
+ t = hd rdreq :: t;
+ rdreq = tl rdreq;
+ }
+ rdreq = t;
+}
+
+insat(t: ref Tk->Toplevel, mark: string): int
+{
+ return cmd(t, ".ft.t compare insert == "+mark) == "1";
+}
+
+insininput(t: ref Tk->Toplevel): int
+{
+ if(cmd(t, ".ft.t compare insert >= outpoint") != "1")
+ return 0;
+ return cmd(t, ".ft.t compare {insert linestart} == {outpoint linestart}")
== "1";
+}
+
+isalnum(s: string): int
+{
+ if(s == "")
+ return 0;
+ c := s[0];
+ if('a' <= c && c <= 'z')
+ return 1;
+ if('A' <= c && c <= 'Z')
+ return 1;
+ if('0' <= c && c <= '9')
+ return 1;
+ if(c == '_')
+ return 1;
+ if(c > 16rA0)
+ return 1;
+ return 0;
+}
+
+cursorcontrol(t: ref Tk->Toplevel, s: string): string
+{
+ l := len s;
+ for(i := 0; i < l; i++) {
+ case s[i] {
+ '\b' =>
+ pre := "";
+ rem := "";
+ if(i + 1 < l)
+ rem = s[i+1:];
+ if(i == 0) { # erase existing character in line
+ if(tk->cmd(t, ".ft.t get " +
+ "{outpoint linestart} outpoint") != "")
+ cmd(t, ".ft.t delete outpoint-1char");
+ } else {
+ if(s[i-1] != '\n') # don't erase newlines
+ i--;
+ if(i)
+ pre = s[:i];
+ }
+ s = pre + rem;
+ l = len s;
+ i = len pre - 1;
+ '\r' =>
+ s[i] = '\n';
+ if(i + 1 < l && s[i+1] == '\n') # \r\n
+ s = s[:i] + s[i+1:];
+ else if(i > 0 && s[i-1] == '\n') # \n\r
+ s = s[:i-1] + s[i:];
+ l = len s;
+ '\0' =>
+ s[i] = Sys->UTFerror;
+ }
+ }
+ return s;
+}
+
+editor(t: ref Tk->Toplevel, ecmd: string)
+{
+ s, snarf: string;
+
+ case ecmd {
+ "scroll" =>
+ menuindex = "0";
+ scrolling = 1;
+ cmd(t, ".m entryconfigure 0 -text noscroll -command {send edit
noscroll}");
+ "noscroll" =>
+ menuindex = "0";
+ scrolling = 0;
+ cmd(t, ".m entryconfigure 0 -text scroll -command {send edit scroll}");
+ "cut" =>
+ menuindex = "1";
+ cut(t, 1);
+ "paste" =>
+ menuindex = "2";
+ paste(t);
+ "snarf" =>
+ menuindex = "3";
+ if(cmd(t, ".ft.t tag ranges sel") == "")
+ break;
+ snarf = tk->cmd(t, ".ft.t get sel.first sel.last");
+ tkclient->snarfput(snarf);
+ "send" =>
+ menuindex = "4";
+ if(cmd(t, ".ft.t tag ranges sel") != ""){
+ snarf = tk->cmd(t, ".ft.t get sel.first sel.last");
+ tkclient->snarfput(snarf);
+ }else{
+ snarf = tkclient->snarfget();
+ }
+ if(snarf != "")
+ s = snarf;
+ else
+ return;
+ if(s[len s-1] != '\n' && s[len s-1] != EOT)
+ s[len s] = '\n';
+ simulatetype(t, s);
+ }
+ cmd(t, "update");
+}
+
+simulatetype(t: ref Tk->Toplevel, s: string)
+{
+ if(rawon){
+ rawinput += s;
+ }else{
+ cmd(t, ".ft.t see end; .ft.t insert end '"+s);
+ cmd(t, ".ft.t mark set insert end");
+ tk->cmd(t, ".ft.t tag remove sel sel.first sel.last");
+ }
+}
+
+cut(t: ref Tk->Toplevel, snarfit: int)
+{
+ if(cmd(t, ".ft.t tag ranges sel") == "")
+ return;
+ if(snarfit)
+ tkclient->snarfput(tk->cmd(t, ".ft.t get sel.first sel.last"));
+ cmd(t, ".ft.t delete sel.first sel.last");
+}
+
+paste(t: ref Tk->Toplevel)
+{
+ snarf := tkclient->snarfget();
+ if(snarf == "")
+ return;
+ cut(t, 0);
+ if(rawon && int cmd(t, ".ft.t compare insert >= outpoint")){
+ rawinput += snarf;
+ }else{
+ cmd(t, ".ft.t insert insert '"+snarf);
+ cmd(t, ".ft.t tag add sel insert-"+string len snarf+"chars insert");
+ }
+}
+
+sendinput(t: ref Tk->Toplevel)
+{
+ input: string;
+ if(rawon)
+ input = rawinput;
+ else
+ input = tk->cmd(t, ".ft.t get outpoint end");
+ if(rdreq == nil || (input == nil && len partialread == 0))
+ return;
+ r := hd rdreq;
+ (chars, bytes, partial) := triminput(r.nbytes, input, partialread);
+ if(bytes == nil)
+ return; # no terminator yet
+ rdreq = tl rdreq;
+
+ alt {
+ r.rc <-= (bytes, nil) =>
+ # check that it really was sent
+ alt {
+ r.rc <-= (nil, nil) =>
+ ;
+ * =>
+ return;
+ }
+ * =>
+ return; # requester has disappeared; ignore his request and try another
+ }
+ if(rawon)
+ rawinput = rawinput[chars:];
+ else
+ cmd(t, ".ft.t mark set outpoint outpoint+" + string chars + "chars");
+ partialread = partial;
+}
+
+# read at most nr bytes from the input string, returning the number of
characters
+# consumed, the bytes to be read, and any remaining bytes from a partially
+# read multibyte UTF character.
+triminput(nr: int, input: string, partial: array of byte): (int, array of
byte, array of byte)
+{
+ if(nr <= len partial)
+ return (0, partial[0:nr], partial[nr:]);
+ if(holding)
+ return (0, nil, partial);
+
+ # keep the array bounds within sensible limits
+ if(nr > len input*Sys->UTFmax)
+ nr = len input*Sys->UTFmax;
+ buf := array[nr+Sys->UTFmax] of byte;
+ t := len partial;
+ buf[0:] = partial;
+
+ hold := !rawon;
+ i := 0;
+ while(i < len input){
+ c := input[i++];
+ # special case for ^D - don't read the actual ^D character
+ if(!rawon && c == EOT){
+ hold = 0;
+ break;
+ }
+
+ t += sys->char2byte(c, buf, t);
+ if(c == '\n' && !rawon){
+ hold = 0;
+ break;
+ }
+ if(t >= nr)
+ break;
+ }
+ if(hold){
+ for(j := i; j < len input; j++){
+ c := input[j];
+ if(c == '\n' || c == EOT)
+ break;
+ }
+ if(j == len input)
+ return (0, nil, partial);
+ # strip ^D when next read would read it, otherwise
+ # we'll give premature EOF.
+ if(i == j && input[i] == EOT)
+ i++;
+ }
+ partial = nil;
+ if(t > nr){
+ partial = buf[nr:t];
+ t = nr;
+ }
+ return (i, buf[0:t], partial);
+}
+
+newsh(sync: chan of int, ctxt: ref Context, args: list of string)
+{
+ sys->pctl(sys->NEWFD, nil);
+
+ sys->bind(srvdir+"/cons", "/dev/cons", sys->MREPL);
+ sys->bind(srvdir+"/consctl", "/dev/consctl", sys->MREPL);
+
+ fd0 := sys->open("/dev/cons", sys->OREAD|sys->ORCLOSE);
+ fd1 := sys->open("/dev/cons", sys->OWRITE);
+ fd2 := sys->open("/dev/cons", sys->OWRITE);
+
+ sync <-= 0;
+
+ sh := load Command "/dis/sh.dis";
+ if(sh == nil)
+ return;
+
+ {
+ sh->init(ctxt, "sh" :: "-n" :: args);
+ }exception{
+ "fail:*" =>
+ exit;
+ }
+}
+
+cmd(top: ref Tk->Toplevel, c: string): string
+{
+ s:= tk->cmd(top, c);
+# sys->print("* %s\n", c);
+ if (s != nil && s[0] == '!')
+ sys->fprint(sys->fildes(2), "wmsh: tk error on '%s': %s\n", c, s);
+ return s;
+}
+
+itemsize(top: ref Tk->Toplevel, item: string): (int, int)
+{
+ w := int tk->cmd(top, item + " cget -actwidth");
+ h := int tk->cmd(top, item + " cget -actheight");
+ b := int tk->cmd(top, item + " cget -borderwidth");
+ return (w+b, h+b);
+}
=======================================
--- /dev/null
+++ /appl/authsrc/winsrv.b Fri Feb 12 09:30:14 2010
@@ -0,0 +1,118 @@
+implement Newwin;
+# serve /n/rwin/new, allowing new shell windows to be created
+# by remote agents. assumes mntgen on /n.
+# write kind of window to be created into /n/rwin/new (sh or rio); read
name of directory
+# containing cons/consctl, etc
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+
+Newwin: module {
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+init(ctxt: ref Draw->Context, nil: list of string)
+{
+ sys = load Sys Sys->PATH;
+ sh = load Sh Sh->PATH;
+
+ sys->pipe(p := array[2] of ref Sys->FD);
+ spawn srv(ctxt, p[0], sync := chan of int);
+ p[0] = nil;
+ <-sync;
+ if(sys->mount(p[1], nil, "/n/rwin", Sys->MREPL, nil) == -1)
+ raise "fail:cannot mount";
+}
+
+srv(ctxt: ref Draw->Context, fd: ref Sys->FD, sync: chan of int)
+{
+ sys->pctl(Sys->FORKNS | Sys->FORKFD, nil);
+ sync <-= 0;
+ spawn export(fd, "/n/rwin");
+
+ sys->bind("#s", "/n/rwin", Sys->MBEFORE);
+ sh->run(nil, "mount" :: "-a" :: "{mntgen}" :: "/n/rwin" :: nil);
+ fio := sys->file2chan("/n/rwin", "new");
+ if(fio == nil){
+ sys->print("cannot make /chan/newwin: %r");
+ return;
+ }
+ spawn srv0(ctxt, fio);
+}
+
+export(fd: ref Sys->FD, d: string)
+{
+ sys->export(fd, d, Sys->EXPWAIT);
+}
+
+srv0(ctxt: ref Draw->Context, fio: ref Sys->FileIO)
+{
+ pending: list of (int, array of byte);
+loop:
+ for(;;)alt{
+ (nil, data, fid, wc) := <-fio.write =>
+ if(wc == nil)
+ break;
+ if(len data > 0 && data[len data - 1] == byte '\n')
+ data = data[0:len data - 1];
+ for(p := pending; p != nil; p = tl p)
+ if((hd p).t0 == fid){
+ wc <-= (-1, "request already pending");
+ continue loop;
+ }
+ (d, e) := newwin(ctxt, string data);
+ if(d == nil)
+ wc <-= (-1, sys->sprint("cannot start shell: %s", e));
+ else{
+ pending = (fid, array of byte d) :: pending;
+ wc <-= (len data, nil);
+ }
+ (offset, nb, fid, rc) := <-fio.read =>
+ p: list of (int, array of byte);
+ if(rc == nil){
+ for(; pending != nil; pending = tl pending)
+ if((hd pending).t0 != fid)
+ p = hd pending :: p;
+ pending = p;
+ break;
+ }
+ d: array of byte;
+ for(; pending != nil; pending = tl pending){
+ if((hd pending).t0 == fid)
+ d = (hd pending).t1;
+ else
+ p = hd pending :: p;
+ }
+ if(offset >= len d)
+ rc <-= (nil, nil);
+ else{
+ rc <-= (d, nil);
+ if(offset + nb < len d)
+ pending = (fid, d) :: pending;
+ }
+ }
+}
+
+n := 0;
+
+newwin(ctxt: ref Draw->Context, kind: string): (string, string)
+{
+ d := sys->sprint("%d", n++);
+ case kind {
+ "sh" =>
+ e := sh->run(ctxt, "/dis/remotesh" :: "-s" :: "/n/rwin/"+d :: nil);
+ if(e != nil)
+ return (nil, e);
+ "rio" =>
+ e := sh->run(ctxt, "9win" :: "-s" :: "/n/rwin/"+d :: nil);
+ if(e != nil)
+ return (nil, e);
+ sys->bind("/dev", "/n/rwin/"+d, Sys->MAFTER);
+ * =>
+ return (nil, "known kind of window");
+ }
+ return (d, nil);
+}
=======================================
--- /dev/null
+++ /man/2/fdrun Fri Feb 12 09:30:14 2010
@@ -0,0 +1,73 @@
+.TH FDRUN 2
+.SH NAME
+fdrun \-
+run a shell command with I/O redirection.
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "draw.m";
+include "fdrun.m";
+fdrun := load FDrun FDrun->PATH;
+
+init: fn();
+run: fn(ctxt: ref Draw->Context, argv: list of string,
+ spec: string, sfds: array of ref Sys->FD, result: chan of string): int;
+.EE
+.SH DESCRIPTION
+.B FDrun
+runs a
+.IR sh (1)
+command, redirecting some of its file descriptors
+to user-specified files.
+.B Init
+must be called first, to initialise the module.
+.B Run
+invokes the command given by
+.I argv
+(the first element being the name of the command)
+using the graphics context
+.IR ctxt .
+.I Spec
+specifies the redirections that should take place,
+each character specifying the redirection for a
+particular file descriptor (\f5spec[\fIi\fP]\fR gives
+the specification for file descriptor
+.IR i ).
+If the character is a decimal digit, say
+.IR d ,
+the file is redirected to
+.IR sfds [ d ];
+if it is the character
+.BR x ,
+it is redirected to
+.BR /dev/null ;
+if the character is a hyphen (\f5-\fP),
+no redirection will take place.
+.PP
+.B Run
+returns without waiting for the
+command to finish (it returns -1
+if the specification was invalid). When
+the command has terminated, its exit
+status will be sent on
+.IR result .
+.SH EXAMPLE
+Compile a Limbo program and save any errors or warnings:
+.EX
+fdrun := load FDrun FDrun->PATH;
+fdrun->init();
+sys->pipe(p := array[2] of ref Sys->FD);
+result := chan of string;
+fdrun->run(nil, "limbo"::"-gw"::"myfile.b"::nil, "x00", array[] of {p[1]},
result);
+efd := p[0];
+p = nil;
+\&... read any output from efd until EOF
+r := <-result;
+if(r != nil)
+ sys->print("compilation failed (%s)\n", r);
+.EE
+.SH SOURCE
+.B /appl/lib/fdrun.b
+.SH SEE ALSO
+.IR sh (1),
+.IR sh (2)
=======================================
--- /dev/null
+++ /module/fdrun.m Fri Feb 12 09:30:14 2010
@@ -0,0 +1,5 @@
+FDrun: module {
+ PATH: con "/dis/fdrun.dis";
+ init: fn();
+ run: fn(ctxt: ref Draw->Context, args: list of string, spec: string,
sfds: array of ref Sys->FD, result: chan of string): int;
+};
=======================================
--- /appl/mkfile Fri Jan 29 05:54:02 2010
+++ /appl/mkfile Fri Feb 12 09:30:14 2010
@@ -3,6 +3,7 @@
DIRS=\
acme\
alphabet\
+ authsrc\
charon\
cmd\
collab\
=======================================
--- /lib/ndb/local Fri Dec 22 12:52:35 2006
+++ /lib/ndb/local Fri Feb 12 09:30:14 2010
@@ -18,3 +18,6 @@
GAMES=your_games_server
registry=your_registry_server
gridsched=your_inferno_grid_scheduler
+
+auth=sources.cs.bell-labs.com authdom=outside.plan9.bell-labs.com
+auth=omni.9gridchan.org authdom=omni

==============================================================================
Revision: 75a1e5db6f
Author: me@challenger
Date: Fri Feb 12 09:46:25 2010
Log: Add ksd_rundtors() to pexit on all hosted platforms.
http://code.google.com/p/inferno-npe/source/detail?r=75a1e5db6f

Modified:
/emu/DragonFly/emu
/emu/DragonFly/emu-g
/emu/DragonFly/os.c
/emu/FreeBSD/emu
/emu/FreeBSD/os.c
/emu/Hp/emu
/emu/Hp/os.c
/emu/Irix/emu
/emu/Irix/os.c
/emu/Linux/emu
/emu/Linux/mkfile
/emu/MacOSX/emu
/emu/MacOSX/emu-g
/emu/MacOSX/os.c
/emu/NetBSD/emu
/emu/NetBSD/os.c
/emu/OpenBSD/emu
/emu/OpenBSD/os.c
/emu/Plan9/emu
/emu/Plan9/emusig
/emu/Plan9/os.c
/emu/Solaris/emu
/emu/Solaris/os.c
/emu/Unixware/emu
/emu/Unixware/os.c

=======================================
--- /emu/DragonFly/emu Fri Jan 29 02:36:15 2010
+++ /emu/DragonFly/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/DragonFly/emu-g Fri Jan 29 02:36:15 2010
+++ /emu/DragonFly/emu-g Fri Feb 12 09:46:25 2010
@@ -19,6 +19,7 @@
mem

lib
+ avl
interp
math
keyring
@@ -52,6 +53,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/DragonFly/os.c Sun Feb 7 07:49:54 2010
+++ /emu/DragonFly/os.c Fri Feb 12 09:46:25 2010
@@ -60,6 +60,10 @@
closesigs(e->sigs);
}
kstack = p->kstack;
+
+ ksd_rundtors();
+
+ free(p->ksd);
free(p->prog);
free(p);
if(kstack != nil)
=======================================
--- /emu/FreeBSD/emu Fri Jan 29 02:36:15 2010
+++ /emu/FreeBSD/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/FreeBSD/os.c Sun Feb 7 07:49:54 2010
+++ /emu/FreeBSD/os.c Fri Feb 12 09:46:25 2010
@@ -60,6 +60,10 @@
closesigs(e->sigs);
}
kstack = p->kstack;
+
+ ksd_rundtors();
+
+ free(p->ksd);
free(p->prog);
free(p);
if(kstack != nil)
=======================================
--- /emu/Hp/emu Fri Jan 29 02:36:15 2010
+++ /emu/Hp/emu Fri Feb 12 09:46:25 2010
@@ -26,6 +26,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -69,6 +70,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Hp/os.c Fri Dec 22 09:07:39 2006
+++ /emu/Hp/os.c Fri Feb 12 09:46:25 2010
@@ -79,6 +79,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(up->prog);
free(up);
pthread_exit(0);
=======================================
--- /emu/Irix/emu Fri Jan 29 02:36:15 2010
+++ /emu/Irix/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Irix/os.c Fri Dec 22 09:07:39 2006
+++ /emu/Irix/os.c Fri Feb 12 09:46:25 2010
@@ -69,6 +69,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(up->prog);
free(up);
exit(0);
=======================================
--- /emu/Linux/emu Sat Feb 6 08:24:58 2010
+++ /emu/Linux/emu Fri Feb 12 09:46:25 2010
@@ -69,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Linux/mkfile Tue Feb 9 23:24:33 2010
+++ /emu/Linux/mkfile Fri Feb 12 09:46:25 2010
@@ -4,7 +4,7 @@

#Configurable parameters

-CONF=emu-g #default configuration
+CONF=emu #default configuration
CONFLIST=emu emu-g
CLEANCONFLIST=

=======================================
--- /emu/MacOSX/emu Fri Jan 29 02:36:15 2010
+++ /emu/MacOSX/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/MacOSX/emu-g Fri Jan 29 02:36:15 2010
+++ /emu/MacOSX/emu-g Fri Feb 12 09:46:25 2010
@@ -21,6 +21,7 @@
mem

lib
+ avl
interp
math
keyring
@@ -54,6 +55,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/MacOSX/os.c Fri Dec 22 16:30:12 2006
+++ /emu/MacOSX/os.c Fri Feb 12 09:46:25 2010
@@ -86,6 +86,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(e->user);
free(p->prog);
free(p);
=======================================
--- /emu/NetBSD/emu Fri Jan 29 02:36:15 2010
+++ /emu/NetBSD/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/NetBSD/os.c Mon Feb 1 04:40:39 2010
+++ /emu/NetBSD/os.c Fri Feb 12 09:46:25 2010
@@ -63,6 +63,10 @@
closesigs(e->sigs);
}
kstack = up->kstack;
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(up->prog);
free(up);
if(kstack != nil)
=======================================
--- /emu/OpenBSD/emu Fri Jan 29 02:36:15 2010
+++ /emu/OpenBSD/emu Fri Feb 12 09:46:25 2010
@@ -26,6 +26,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -69,6 +70,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/OpenBSD/os.c Sun Feb 7 07:49:54 2010
+++ /emu/OpenBSD/os.c Fri Feb 12 09:46:25 2010
@@ -65,6 +65,10 @@
closesigs(e->sigs);
}
kstack = p->kstack;
+
+ ksd_rundtors();
+
+ free(p->ksd);
free(p->prog);
free(p);
if(kstack != nil)
=======================================
--- /emu/Plan9/emu Fri Jan 29 02:36:15 2010
+++ /emu/Plan9/emu Fri Feb 12 09:46:25 2010
@@ -26,6 +26,7 @@
# ip and eia are simply bound in from Plan 9

lib
+ avl
interp
tk
freetype
@@ -70,6 +71,7 @@
exportfs
exptab
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Plan9/emusig Fri Jan 29 02:36:15 2010
+++ /emu/Plan9/emusig Fri Feb 12 09:46:25 2010
@@ -20,6 +20,7 @@
# ip and eia are simply bound in from Plan 9

lib
+ avl
interp
tk
freetype
@@ -57,6 +58,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Plan9/os.c Fri Dec 22 09:07:39 2006
+++ /emu/Plan9/os.c Fri Feb 12 09:46:25 2010
@@ -59,6 +59,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(e->user);
free(up->prog);
up->prog = nil;
=======================================
--- /emu/Solaris/emu Fri Jan 29 02:36:15 2010
+++ /emu/Solaris/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Solaris/os.c Fri Jan 15 05:50:58 2010
+++ /emu/Solaris/os.c Fri Feb 12 09:46:25 2010
@@ -60,6 +60,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(up->prog);
sema_destroy(up->os);
free(up->os);
=======================================
--- /emu/Unixware/emu Fri Jan 29 02:36:15 2010
+++ /emu/Unixware/emu Fri Feb 12 09:46:25 2010
@@ -25,6 +25,7 @@
mem

lib
+ avl
interp
tk
freetype
@@ -68,6 +69,7 @@
exception
exportfs
inferno
+ ksd
latin1
main
parse
=======================================
--- /emu/Unixware/os.c Fri Dec 22 09:07:39 2006
+++ /emu/Unixware/os.c Fri Feb 12 09:46:25 2010
@@ -59,6 +59,10 @@
closeegrp(e->egrp);
closesigs(e->sigs);
}
+
+ ksd_rundtors();
+
+ free(up->ksd);
free(up->prog);
sema_destroy(up->os);
free(up->os);

Reply all
Reply to author
Forward
0 new messages