#include #include #include #include #include #include <9p.h> #define MIN(a,b) ((a) < (b) ? (a) : (b)) enum { Stacksz = 8192, }; typedef struct Prog { Channel *pidc; char **argv; } Prog; typedef struct Line { uchar *buf; int x, len; } Line; int cons, consctl; Channel *rchan, *wchan, *ichan; File *devcons; static void killer(void *arg) { int *pid = arg; ulong yes; for(;;){ yes = recvul(ichan); if(yes) postnote(PNGROUP, *pid, "interrupt"); } } static void sendline(Channel *c, Line *L) { int n, k; Req *r; uchar *s; s = L->buf; n = L->x; do{ while(!(r = recvp(c))); k = MIN(n, r->ifcall.count); memcpy(r->ofcall.data, s, k); r->ofcall.count = k; respond(r, nil); s += k; n -= k; }while(n > 0); L->x = 0; } static void senderr(Channel *c, char *err) { Req *r; while(!(r = recvp(c))); respond(r, err); } static void echo(uchar c) { write(cons, &c, 1); } static int addchar(Line *L, uchar c) { int send; send = 0; switch(c){ case '\n': send = 1; break; case 4: return 1; case 8: if(L->x > 0){ echo(8); L->x--; } return 0; case 21: while(L->x > 0){ echo(8); L->x--; } return 0; case 23: while(L->x > 0){ c = L->buf[--L->x]; echo(8); if(c == ' ' || c == '\t') break; } return 0; case 127: L->x = 0; sendul(ichan, 1); return 1; } echo(c); L->buf[L->x++] = c; if(L->x == L->len) send = 1; return send; } static Line * makeline(int len) { Line *L; L = malloc(sizeof(*L)); L->buf = malloc(len); L->x = 0; L->len = len; return L; } static void reader(void *) { int n; uchar c; Line *L; char err[ERRMAX]; L = makeline(128); for(;;){ n = read(cons, &c, 1); if(n < 0){ rerrstr(err, sizeof(err)); if(L->x > 0) sendline(rchan, L); senderr(rchan, err); continue; } if(addchar(L, c)) sendline(rchan, L); } } static void writer(void *) { Req *r; int n; char err[ERRMAX]; for(;;){ do r = recvp(wchan); while(!r); n = write(cons, r->ifcall.data, r->ifcall.count); if(n < 0){ rerrstr(err, sizeof(err)); respond(r, err); }else{ r->ofcall.count = n; respond(r, nil); } } } static void fsread(Req *r) { sendp(rchan, r); } static void fswrite(Req *r) { sendp(wchan, r); } /* adapted from acme/win */ int lookinbin(char *s) { if(s[0] == '/') return 0; if(s[0]=='.' && s[1]=='/') return 0; if(s[0]=='.' && s[1]=='.' && s[2]=='/') return 0; return 1; } char* estrstrdup(char *s, char *t) { char *u; u = malloc(strlen(s)+strlen(t)+1); sprint(u, "%s%s", s, t); return u; } void cmdproc(void *arg) { Prog *p = arg; char **av = p->argv; char *cmd; rfork(RFCFDG | RFNOTEG); open("/dev/cons", OREAD); open("/dev/cons", OWRITE); dup(1, 2); procexec(p->pidc, av[0], av); if(lookinbin(av[0])){ cmd = estrstrdup("/bin/", av[0]); procexec(p->pidc, cmd, av); } threadexitsall("exec"); } void runcmd(char **argv) { Channel *waitc; Channel *pidc; Waitmsg *w; Prog prog; int pid; waitc = threadwaitchan(); pidc = chancreate(sizeof(int), 0); prog.argv = argv; prog.pidc = pidc; proccreate(cmdproc, &prog, Stacksz); while(recv(pidc, &pid) == -1 || pid == -1); threadcreate(killer, &pid, Stacksz); while(recv(waitc, &w) == -1); free(w); } void usage(void) { print("usage: tty [-D] cmd arg1 arg2 ...\n"); exits("usage"); } Srv fs = { .read = fsread, .write = fswrite, }; void threadmain(int argc, char *argv[]) { char *user; ARGBEGIN{ case 'D': chatty9p++; break; default: usage(); break; }ARGEND; if(argc == 0) usage(); rfork(RFNAMEG); cons = open("/dev/cons", ORDWR); if(cons < 0) sysfatal("cons: %r"); consctl = open("/dev/consctl", OWRITE); if(consctl < 0) sysfatal("ctl: %r"); fprint(consctl, "rawon\n"); rchan = chancreate(sizeof(void *), 8); wchan = chancreate(sizeof(void *), 8); ichan = chancreate(sizeof(ulong), 8); proccreate(reader, nil, Stacksz); proccreate(writer, nil, Stacksz); user = getuser(); fs.tree = alloctree(user, getuser(), DMDIR|0555, nil); devcons = createfile(fs.tree->root, "cons", user, 0666, nil); threadpostmountsrv(&fs, nil, "/dev", MBEFORE); runcmd(argv); close(consctl); close(cons); threadexitsall(nil); }