15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier
35e96a66cSDavid du Colombier #include "9.h"
45e96a66cSDavid du Colombier
55e96a66cSDavid du Colombier enum {
65e96a66cSDavid du Colombier Nl = 256, /* max. command line length */
75e96a66cSDavid du Colombier Nq = 8*1024, /* amount of I/O buffered */
85e96a66cSDavid du Colombier };
95e96a66cSDavid du Colombier
105e96a66cSDavid du Colombier typedef struct Q {
11*d7aba6c3SDavid du Colombier QLock lock;
12*d7aba6c3SDavid du Colombier Rendez full;
13*d7aba6c3SDavid du Colombier Rendez empty;
145e96a66cSDavid du Colombier
155e96a66cSDavid du Colombier char q[Nq];
165e96a66cSDavid du Colombier int n;
175e96a66cSDavid du Colombier int r;
185e96a66cSDavid du Colombier int w;
195e96a66cSDavid du Colombier } Q;
205e96a66cSDavid du Colombier
215e96a66cSDavid du Colombier typedef struct Cons {
22*d7aba6c3SDavid du Colombier QLock lock;
235e96a66cSDavid du Colombier int ref;
245e96a66cSDavid du Colombier int closed;
255e96a66cSDavid du Colombier int fd;
265e96a66cSDavid du Colombier int srvfd;
275e96a66cSDavid du Colombier int ctlfd;
285e96a66cSDavid du Colombier Q* iq; /* points to console.iq */
295e96a66cSDavid du Colombier Q* oq; /* points to console.oq */
305e96a66cSDavid du Colombier } Cons;
315e96a66cSDavid du Colombier
32b8a11165SDavid du Colombier char *currfsysname;
33b8a11165SDavid du Colombier
345e96a66cSDavid du Colombier static struct {
355e96a66cSDavid du Colombier Q* iq; /* input */
365e96a66cSDavid du Colombier Q* oq; /* output */
375e96a66cSDavid du Colombier char l[Nl]; /* command line assembly */
385e96a66cSDavid du Colombier int nl; /* current line length */
39dc5a79c1SDavid du Colombier int nopens;
405e96a66cSDavid du Colombier
415e96a66cSDavid du Colombier char* prompt;
425e96a66cSDavid du Colombier int np;
435e96a66cSDavid du Colombier } console;
445e96a66cSDavid du Colombier
455e96a66cSDavid du Colombier static void
consClose(Cons * cons)465e96a66cSDavid du Colombier consClose(Cons* cons)
475e96a66cSDavid du Colombier {
48*d7aba6c3SDavid du Colombier qlock(&cons->lock);
495e96a66cSDavid du Colombier cons->closed = 1;
505e96a66cSDavid du Colombier
515e96a66cSDavid du Colombier cons->ref--;
525e96a66cSDavid du Colombier if(cons->ref > 0){
53*d7aba6c3SDavid du Colombier qlock(&cons->iq->lock);
54*d7aba6c3SDavid du Colombier rwakeup(&cons->iq->full);
55*d7aba6c3SDavid du Colombier qunlock(&cons->iq->lock);
56*d7aba6c3SDavid du Colombier qlock(&cons->oq->lock);
57*d7aba6c3SDavid du Colombier rwakeup(&cons->oq->empty);
58*d7aba6c3SDavid du Colombier qunlock(&cons->oq->lock);
59*d7aba6c3SDavid du Colombier qunlock(&cons->lock);
605e96a66cSDavid du Colombier return;
615e96a66cSDavid du Colombier }
625e96a66cSDavid du Colombier
635e96a66cSDavid du Colombier if(cons->ctlfd != -1){
645e96a66cSDavid du Colombier close(cons->ctlfd);
655e96a66cSDavid du Colombier cons->srvfd = -1;
665e96a66cSDavid du Colombier }
675e96a66cSDavid du Colombier if(cons->srvfd != -1){
685e96a66cSDavid du Colombier close(cons->srvfd);
695e96a66cSDavid du Colombier cons->srvfd = -1;
705e96a66cSDavid du Colombier }
715e96a66cSDavid du Colombier if(cons->fd != -1){
725e96a66cSDavid du Colombier close(cons->fd);
735e96a66cSDavid du Colombier cons->fd = -1;
745e96a66cSDavid du Colombier }
75*d7aba6c3SDavid du Colombier qunlock(&cons->lock);
76*d7aba6c3SDavid du Colombier vtfree(cons);
77dc5a79c1SDavid du Colombier console.nopens--;
785e96a66cSDavid du Colombier }
795e96a66cSDavid du Colombier
805e96a66cSDavid du Colombier static void
consIProc(void * v)815e96a66cSDavid du Colombier consIProc(void* v)
825e96a66cSDavid du Colombier {
835e96a66cSDavid du Colombier Q *q;
845e96a66cSDavid du Colombier Cons *cons;
855e96a66cSDavid du Colombier int n, w;
865e96a66cSDavid du Colombier char buf[Nq/4];
875e96a66cSDavid du Colombier
88*d7aba6c3SDavid du Colombier threadsetname("consI");
895e96a66cSDavid du Colombier
905e96a66cSDavid du Colombier cons = v;
915e96a66cSDavid du Colombier q = cons->iq;
925e96a66cSDavid du Colombier for(;;){
935e96a66cSDavid du Colombier /*
945e96a66cSDavid du Colombier * Can't tell the difference between zero-length read
955e96a66cSDavid du Colombier * and eof, so keep calling read until we get an error.
965e96a66cSDavid du Colombier */
975e96a66cSDavid du Colombier if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0)
985e96a66cSDavid du Colombier break;
99*d7aba6c3SDavid du Colombier qlock(&q->lock);
1005e96a66cSDavid du Colombier while(Nq - q->n < n && !cons->closed)
101*d7aba6c3SDavid du Colombier rsleep(&q->full);
1025e96a66cSDavid du Colombier w = Nq - q->w;
1035e96a66cSDavid du Colombier if(w < n){
1045e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, w);
1055e96a66cSDavid du Colombier memmove(&q->q[0], buf + w, n - w);
1065e96a66cSDavid du Colombier }
1075e96a66cSDavid du Colombier else
1085e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, n);
1095e96a66cSDavid du Colombier q->w = (q->w + n) % Nq;
1105e96a66cSDavid du Colombier q->n += n;
111*d7aba6c3SDavid du Colombier rwakeup(&q->empty);
112*d7aba6c3SDavid du Colombier qunlock(&q->lock);
1135e96a66cSDavid du Colombier }
1145e96a66cSDavid du Colombier consClose(cons);
1155e96a66cSDavid du Colombier }
1165e96a66cSDavid du Colombier
1175e96a66cSDavid du Colombier static void
consOProc(void * v)1185e96a66cSDavid du Colombier consOProc(void* v)
1195e96a66cSDavid du Colombier {
1205e96a66cSDavid du Colombier Q *q;
1215e96a66cSDavid du Colombier Cons *cons;
1225e96a66cSDavid du Colombier char buf[Nq];
1235e96a66cSDavid du Colombier int lastn, n, r;
1245e96a66cSDavid du Colombier
125*d7aba6c3SDavid du Colombier threadsetname("consO");
1265e96a66cSDavid du Colombier
1275e96a66cSDavid du Colombier cons = v;
1285e96a66cSDavid du Colombier q = cons->oq;
129*d7aba6c3SDavid du Colombier qlock(&q->lock);
1305e96a66cSDavid du Colombier lastn = 0;
1315e96a66cSDavid du Colombier for(;;){
1325e96a66cSDavid du Colombier while(lastn == q->n && !cons->closed)
133*d7aba6c3SDavid du Colombier rsleep(&q->empty);
1345e96a66cSDavid du Colombier if((n = q->n - lastn) > Nq)
1355e96a66cSDavid du Colombier n = Nq;
1365e96a66cSDavid du Colombier if(n > q->w){
1375e96a66cSDavid du Colombier r = n - q->w;
1385e96a66cSDavid du Colombier memmove(buf, &q->q[Nq - r], r);
1395e96a66cSDavid du Colombier memmove(buf+r, &q->q[0], n - r);
1405e96a66cSDavid du Colombier }
1415e96a66cSDavid du Colombier else
1425e96a66cSDavid du Colombier memmove(buf, &q->q[q->w - n], n);
1435e96a66cSDavid du Colombier lastn = q->n;
144*d7aba6c3SDavid du Colombier qunlock(&q->lock);
1455e96a66cSDavid du Colombier if(cons->closed || write(cons->fd, buf, n) < 0)
1465e96a66cSDavid du Colombier break;
147*d7aba6c3SDavid du Colombier qlock(&q->lock);
148*d7aba6c3SDavid du Colombier rwakeup(&q->empty);
1495e96a66cSDavid du Colombier }
1505e96a66cSDavid du Colombier consClose(cons);
1515e96a66cSDavid du Colombier }
1525e96a66cSDavid du Colombier
1535e96a66cSDavid du Colombier int
consOpen(int fd,int srvfd,int ctlfd)1545e96a66cSDavid du Colombier consOpen(int fd, int srvfd, int ctlfd)
1555e96a66cSDavid du Colombier {
1565e96a66cSDavid du Colombier Cons *cons;
1575e96a66cSDavid du Colombier
158*d7aba6c3SDavid du Colombier cons = vtmallocz(sizeof(Cons));
1595e96a66cSDavid du Colombier cons->fd = fd;
1605e96a66cSDavid du Colombier cons->srvfd = srvfd;
1615e96a66cSDavid du Colombier cons->ctlfd = ctlfd;
1625e96a66cSDavid du Colombier cons->iq = console.iq;
1635e96a66cSDavid du Colombier cons->oq = console.oq;
164dc5a79c1SDavid du Colombier console.nopens++;
1655e96a66cSDavid du Colombier
166*d7aba6c3SDavid du Colombier qlock(&cons->lock);
1675e96a66cSDavid du Colombier cons->ref = 2;
1685e96a66cSDavid du Colombier cons->closed = 0;
169*d7aba6c3SDavid du Colombier if(proccreate(consOProc, cons, STACK) < 0){
1705e96a66cSDavid du Colombier cons->ref--;
171*d7aba6c3SDavid du Colombier qunlock(&cons->lock);
1725e96a66cSDavid du Colombier consClose(cons);
1735e96a66cSDavid du Colombier return 0;
1745e96a66cSDavid du Colombier }
175*d7aba6c3SDavid du Colombier qunlock(&cons->lock);
1765e96a66cSDavid du Colombier
1775e96a66cSDavid du Colombier if(ctlfd >= 0)
1785e96a66cSDavid du Colombier consIProc(cons);
179*d7aba6c3SDavid du Colombier else if(proccreate(consIProc, cons, STACK) < 0){
1805e96a66cSDavid du Colombier consClose(cons);
1815e96a66cSDavid du Colombier return 0;
1825e96a66cSDavid du Colombier }
1835e96a66cSDavid du Colombier
1845e96a66cSDavid du Colombier return 1;
1855e96a66cSDavid du Colombier }
1865e96a66cSDavid du Colombier
1875e96a66cSDavid du Colombier static int
qWrite(Q * q,char * p,int n)1885e96a66cSDavid du Colombier qWrite(Q* q, char* p, int n)
1895e96a66cSDavid du Colombier {
1905e96a66cSDavid du Colombier int w;
1915e96a66cSDavid du Colombier
192*d7aba6c3SDavid du Colombier qlock(&q->lock);
1935e96a66cSDavid du Colombier if(n > Nq - q->w){
1945e96a66cSDavid du Colombier w = Nq - q->w;
1955e96a66cSDavid du Colombier memmove(&q->q[q->w], p, w);
1965e96a66cSDavid du Colombier memmove(&q->q[0], p + w, n - w);
1975e96a66cSDavid du Colombier q->w = n - w;
1985e96a66cSDavid du Colombier }
1995e96a66cSDavid du Colombier else{
2005e96a66cSDavid du Colombier memmove(&q->q[q->w], p, n);
2015e96a66cSDavid du Colombier q->w += n;
2025e96a66cSDavid du Colombier }
2035e96a66cSDavid du Colombier q->n += n;
204*d7aba6c3SDavid du Colombier rwakeup(&q->empty);
205*d7aba6c3SDavid du Colombier qunlock(&q->lock);
2065e96a66cSDavid du Colombier
2075e96a66cSDavid du Colombier return n;
2085e96a66cSDavid du Colombier }
2095e96a66cSDavid du Colombier
2105e96a66cSDavid du Colombier static Q*
qAlloc(void)2115e96a66cSDavid du Colombier qAlloc(void)
2125e96a66cSDavid du Colombier {
2135e96a66cSDavid du Colombier Q *q;
2145e96a66cSDavid du Colombier
215*d7aba6c3SDavid du Colombier q = vtmallocz(sizeof(Q));
216*d7aba6c3SDavid du Colombier q->full.l = &q->lock;
217*d7aba6c3SDavid du Colombier q->empty.l = &q->lock;
2185e96a66cSDavid du Colombier q->n = q->r = q->w = 0;
2195e96a66cSDavid du Colombier
2205e96a66cSDavid du Colombier return q;
2215e96a66cSDavid du Colombier }
2225e96a66cSDavid du Colombier
2235e96a66cSDavid du Colombier static void
consProc(void *)2245e96a66cSDavid du Colombier consProc(void*)
2255e96a66cSDavid du Colombier {
2265e96a66cSDavid du Colombier Q *q;
2275e96a66cSDavid du Colombier int argc, i, n, r;
2285e96a66cSDavid du Colombier char *argv[20], buf[Nq], *lp, *wbuf;
229b8a11165SDavid du Colombier char procname[64];
2305e96a66cSDavid du Colombier
231b8a11165SDavid du Colombier snprint(procname, sizeof procname, "cons %s", currfsysname);
232*d7aba6c3SDavid du Colombier threadsetname(procname);
2335e96a66cSDavid du Colombier
2345e96a66cSDavid du Colombier q = console.iq;
2355e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np);
236*d7aba6c3SDavid du Colombier qlock(&q->lock);
2375e96a66cSDavid du Colombier for(;;){
2385e96a66cSDavid du Colombier while((n = q->n) == 0)
239*d7aba6c3SDavid du Colombier rsleep(&q->empty);
2405e96a66cSDavid du Colombier r = Nq - q->r;
2415e96a66cSDavid du Colombier if(r < n){
2425e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], r);
2435e96a66cSDavid du Colombier memmove(buf + r, &q->q[0], n - r);
2445e96a66cSDavid du Colombier }
2455e96a66cSDavid du Colombier else
2465e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], n);
2475e96a66cSDavid du Colombier q->r = (q->r + n) % Nq;
2485e96a66cSDavid du Colombier q->n -= n;
249*d7aba6c3SDavid du Colombier rwakeup(&q->full);
250*d7aba6c3SDavid du Colombier qunlock(&q->lock);
2515e96a66cSDavid du Colombier
2525e96a66cSDavid du Colombier for(i = 0; i < n; i++){
2535e96a66cSDavid du Colombier switch(buf[i]){
2545e96a66cSDavid du Colombier case '\004': /* ^D */
2555e96a66cSDavid du Colombier if(console.nl == 0){
2565e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1);
2575e96a66cSDavid du Colombier break;
2585e96a66cSDavid du Colombier }
2595e96a66cSDavid du Colombier /*FALLTHROUGH*/
2605e96a66cSDavid du Colombier default:
2615e96a66cSDavid du Colombier if(console.nl < Nl-1){
2625e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2635e96a66cSDavid du Colombier console.l[console.nl++] = buf[i];
2645e96a66cSDavid du Colombier }
2655e96a66cSDavid du Colombier continue;
2665e96a66cSDavid du Colombier case '\b':
2675e96a66cSDavid du Colombier if(console.nl != 0){
2685e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2695e96a66cSDavid du Colombier console.nl--;
2705e96a66cSDavid du Colombier }
2715e96a66cSDavid du Colombier continue;
2725e96a66cSDavid du Colombier case '\n':
2735e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2745e96a66cSDavid du Colombier break;
2755e96a66cSDavid du Colombier case '\025': /* ^U */
2765e96a66cSDavid du Colombier qWrite(console.oq, "^U\n", 3);
2775e96a66cSDavid du Colombier console.nl = 0;
2785e96a66cSDavid du Colombier break;
2795e96a66cSDavid du Colombier case '\027': /* ^W */
2805e96a66cSDavid du Colombier console.l[console.nl] = '\0';
281*d7aba6c3SDavid du Colombier wbuf = vtmalloc(console.nl+1);
2825e96a66cSDavid du Colombier memmove(wbuf, console.l, console.nl+1);
2835e96a66cSDavid du Colombier argc = tokenize(wbuf, argv, nelem(argv));
2845e96a66cSDavid du Colombier if(argc > 0)
2855e96a66cSDavid du Colombier argc--;
2865e96a66cSDavid du Colombier console.nl = 0;
2875e96a66cSDavid du Colombier lp = console.l;
2885e96a66cSDavid du Colombier for(i = 0; i < argc; i++)
2895e96a66cSDavid du Colombier lp += sprint(lp, "%q ", argv[i]);
2905e96a66cSDavid du Colombier console.nl = lp - console.l;
291*d7aba6c3SDavid du Colombier vtfree(wbuf);
2925e96a66cSDavid du Colombier qWrite(console.oq, "^W\n", 3);
2935e96a66cSDavid du Colombier if(console.nl == 0)
2945e96a66cSDavid du Colombier break;
2955e96a66cSDavid du Colombier qWrite(console.oq, console.l, console.nl);
2965e96a66cSDavid du Colombier continue;
2975e96a66cSDavid du Colombier case '\177':
2985e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1);
2995e96a66cSDavid du Colombier console.nl = 0;
3005e96a66cSDavid du Colombier break;
3015e96a66cSDavid du Colombier }
3025e96a66cSDavid du Colombier
3035e96a66cSDavid du Colombier console.l[console.nl] = '\0';
3045e96a66cSDavid du Colombier if(console.nl != 0)
3055e96a66cSDavid du Colombier cliExec(console.l);
3065e96a66cSDavid du Colombier
3075e96a66cSDavid du Colombier console.nl = 0;
3085e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np);
3095e96a66cSDavid du Colombier }
3105e96a66cSDavid du Colombier
311*d7aba6c3SDavid du Colombier qlock(&q->lock);
3125e96a66cSDavid du Colombier }
3135e96a66cSDavid du Colombier }
3145e96a66cSDavid du Colombier
3155e96a66cSDavid du Colombier int
consWrite(char * buf,int len)3165e96a66cSDavid du Colombier consWrite(char* buf, int len)
3175e96a66cSDavid du Colombier {
3185e96a66cSDavid du Colombier if(console.oq == nil)
319dc5a79c1SDavid du Colombier return write(2, buf, len);
320dc5a79c1SDavid du Colombier if(console.nopens == 0)
321dc5a79c1SDavid du Colombier write(2, buf, len);
3225e96a66cSDavid du Colombier return qWrite(console.oq, buf, len);
3235e96a66cSDavid du Colombier }
3245e96a66cSDavid du Colombier
3255e96a66cSDavid du Colombier int
consPrompt(char * prompt)3265e96a66cSDavid du Colombier consPrompt(char* prompt)
3275e96a66cSDavid du Colombier {
3285e96a66cSDavid du Colombier char buf[ERRMAX];
3295e96a66cSDavid du Colombier
3305e96a66cSDavid du Colombier if(prompt == nil)
3315e96a66cSDavid du Colombier prompt = "prompt";
3325e96a66cSDavid du Colombier
333*d7aba6c3SDavid du Colombier vtfree(console.prompt);
3345e96a66cSDavid du Colombier console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
335*d7aba6c3SDavid du Colombier console.prompt = vtstrdup(buf);
3365e96a66cSDavid du Colombier
3375e96a66cSDavid du Colombier return console.np;
3385e96a66cSDavid du Colombier }
3395e96a66cSDavid du Colombier
3405e96a66cSDavid du Colombier int
consTTY(void)3415e96a66cSDavid du Colombier consTTY(void)
3425e96a66cSDavid du Colombier {
3435e96a66cSDavid du Colombier int ctl, fd;
3445e96a66cSDavid du Colombier char *name, *p;
3455e96a66cSDavid du Colombier
3465e96a66cSDavid du Colombier name = "/dev/cons";
3475e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){
3485e96a66cSDavid du Colombier name = "#c/cons";
3495e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){
350*d7aba6c3SDavid du Colombier werrstr("consTTY: open %s: %r", name);
3515e96a66cSDavid du Colombier return 0;
3525e96a66cSDavid du Colombier }
3535e96a66cSDavid du Colombier }
3545e96a66cSDavid du Colombier
3555e96a66cSDavid du Colombier p = smprint("%sctl", name);
3565e96a66cSDavid du Colombier if((ctl = open(p, OWRITE)) < 0){
3575e96a66cSDavid du Colombier close(fd);
358*d7aba6c3SDavid du Colombier werrstr("consTTY: open %s: %r", p);
3595e96a66cSDavid du Colombier free(p);
3605e96a66cSDavid du Colombier return 0;
3615e96a66cSDavid du Colombier }
3625e96a66cSDavid du Colombier if(write(ctl, "rawon", 5) < 0){
3635e96a66cSDavid du Colombier close(ctl);
3645e96a66cSDavid du Colombier close(fd);
365*d7aba6c3SDavid du Colombier werrstr("consTTY: write %s: %r", p);
3665e96a66cSDavid du Colombier free(p);
3675e96a66cSDavid du Colombier return 0;
3685e96a66cSDavid du Colombier }
3695e96a66cSDavid du Colombier free(p);
3705e96a66cSDavid du Colombier
3715e96a66cSDavid du Colombier if(consOpen(fd, fd, ctl) == 0){
3725e96a66cSDavid du Colombier close(ctl);
3735e96a66cSDavid du Colombier close(fd);
3745e96a66cSDavid du Colombier return 0;
3755e96a66cSDavid du Colombier }
3765e96a66cSDavid du Colombier
3775e96a66cSDavid du Colombier return 1;
3785e96a66cSDavid du Colombier }
3795e96a66cSDavid du Colombier
3805e96a66cSDavid du Colombier int
consInit(void)3815e96a66cSDavid du Colombier consInit(void)
3825e96a66cSDavid du Colombier {
3835e96a66cSDavid du Colombier console.iq = qAlloc();
3845e96a66cSDavid du Colombier console.oq = qAlloc();
3855e96a66cSDavid du Colombier console.nl = 0;
3865e96a66cSDavid du Colombier
3875e96a66cSDavid du Colombier consPrompt(nil);
3885e96a66cSDavid du Colombier
389*d7aba6c3SDavid du Colombier if(proccreate(consProc, nil, STACK) < 0){
390*d7aba6c3SDavid du Colombier sysfatal("can't start console proc");
3915e96a66cSDavid du Colombier return 0;
3925e96a66cSDavid du Colombier }
3935e96a66cSDavid du Colombier
3945e96a66cSDavid du Colombier return 1;
3955e96a66cSDavid du Colombier }
396