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 {
115e96a66cSDavid du Colombier VtLock* lock;
125e96a66cSDavid du Colombier VtRendez* full;
135e96a66cSDavid du Colombier VtRendez* 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 {
225e96a66cSDavid du Colombier VtLock* 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
32*b8a11165SDavid du Colombier char *currfsysname;
33*b8a11165SDavid 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 {
485e96a66cSDavid du Colombier vtLock(cons->lock);
495e96a66cSDavid du Colombier cons->closed = 1;
505e96a66cSDavid du Colombier
515e96a66cSDavid du Colombier cons->ref--;
525e96a66cSDavid du Colombier if(cons->ref > 0){
535e96a66cSDavid du Colombier vtLock(cons->iq->lock);
545e96a66cSDavid du Colombier vtWakeup(cons->iq->full);
555e96a66cSDavid du Colombier vtUnlock(cons->iq->lock);
565e96a66cSDavid du Colombier vtLock(cons->oq->lock);
575e96a66cSDavid du Colombier vtWakeup(cons->oq->empty);
585e96a66cSDavid du Colombier vtUnlock(cons->oq->lock);
595e96a66cSDavid du Colombier vtUnlock(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 }
755e96a66cSDavid du Colombier vtUnlock(cons->lock);
765e96a66cSDavid du Colombier vtLockFree(cons->lock);
775e96a66cSDavid du Colombier vtMemFree(cons);
78dc5a79c1SDavid du Colombier console.nopens--;
795e96a66cSDavid du Colombier }
805e96a66cSDavid du Colombier
815e96a66cSDavid du Colombier static void
consIProc(void * v)825e96a66cSDavid du Colombier consIProc(void* v)
835e96a66cSDavid du Colombier {
845e96a66cSDavid du Colombier Q *q;
855e96a66cSDavid du Colombier Cons *cons;
865e96a66cSDavid du Colombier int n, w;
875e96a66cSDavid du Colombier char buf[Nq/4];
885e96a66cSDavid du Colombier
895e96a66cSDavid du Colombier vtThreadSetName("consI");
905e96a66cSDavid du Colombier
915e96a66cSDavid du Colombier cons = v;
925e96a66cSDavid du Colombier q = cons->iq;
935e96a66cSDavid du Colombier for(;;){
945e96a66cSDavid du Colombier /*
955e96a66cSDavid du Colombier * Can't tell the difference between zero-length read
965e96a66cSDavid du Colombier * and eof, so keep calling read until we get an error.
975e96a66cSDavid du Colombier */
985e96a66cSDavid du Colombier if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0)
995e96a66cSDavid du Colombier break;
1005e96a66cSDavid du Colombier vtLock(q->lock);
1015e96a66cSDavid du Colombier while(Nq - q->n < n && !cons->closed)
1025e96a66cSDavid du Colombier vtSleep(q->full);
1035e96a66cSDavid du Colombier w = Nq - q->w;
1045e96a66cSDavid du Colombier if(w < n){
1055e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, w);
1065e96a66cSDavid du Colombier memmove(&q->q[0], buf + w, n - w);
1075e96a66cSDavid du Colombier }
1085e96a66cSDavid du Colombier else
1095e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, n);
1105e96a66cSDavid du Colombier q->w = (q->w + n) % Nq;
1115e96a66cSDavid du Colombier q->n += n;
1125e96a66cSDavid du Colombier vtWakeup(q->empty);
1135e96a66cSDavid du Colombier vtUnlock(q->lock);
1145e96a66cSDavid du Colombier }
1155e96a66cSDavid du Colombier consClose(cons);
1165e96a66cSDavid du Colombier }
1175e96a66cSDavid du Colombier
1185e96a66cSDavid du Colombier static void
consOProc(void * v)1195e96a66cSDavid du Colombier consOProc(void* v)
1205e96a66cSDavid du Colombier {
1215e96a66cSDavid du Colombier Q *q;
1225e96a66cSDavid du Colombier Cons *cons;
1235e96a66cSDavid du Colombier char buf[Nq];
1245e96a66cSDavid du Colombier int lastn, n, r;
1255e96a66cSDavid du Colombier
1265e96a66cSDavid du Colombier vtThreadSetName("consO");
1275e96a66cSDavid du Colombier
1285e96a66cSDavid du Colombier cons = v;
1295e96a66cSDavid du Colombier q = cons->oq;
1305e96a66cSDavid du Colombier vtLock(q->lock);
1315e96a66cSDavid du Colombier lastn = 0;
1325e96a66cSDavid du Colombier for(;;){
1335e96a66cSDavid du Colombier while(lastn == q->n && !cons->closed)
1345e96a66cSDavid du Colombier vtSleep(q->empty);
1355e96a66cSDavid du Colombier if((n = q->n - lastn) > Nq)
1365e96a66cSDavid du Colombier n = Nq;
1375e96a66cSDavid du Colombier if(n > q->w){
1385e96a66cSDavid du Colombier r = n - q->w;
1395e96a66cSDavid du Colombier memmove(buf, &q->q[Nq - r], r);
1405e96a66cSDavid du Colombier memmove(buf+r, &q->q[0], n - r);
1415e96a66cSDavid du Colombier }
1425e96a66cSDavid du Colombier else
1435e96a66cSDavid du Colombier memmove(buf, &q->q[q->w - n], n);
1445e96a66cSDavid du Colombier lastn = q->n;
1455e96a66cSDavid du Colombier vtUnlock(q->lock);
1465e96a66cSDavid du Colombier if(cons->closed || write(cons->fd, buf, n) < 0)
1475e96a66cSDavid du Colombier break;
1485e96a66cSDavid du Colombier vtLock(q->lock);
1495e96a66cSDavid du Colombier vtWakeup(q->empty);
1505e96a66cSDavid du Colombier }
1515e96a66cSDavid du Colombier consClose(cons);
1525e96a66cSDavid du Colombier }
1535e96a66cSDavid du Colombier
1545e96a66cSDavid du Colombier int
consOpen(int fd,int srvfd,int ctlfd)1555e96a66cSDavid du Colombier consOpen(int fd, int srvfd, int ctlfd)
1565e96a66cSDavid du Colombier {
1575e96a66cSDavid du Colombier Cons *cons;
1585e96a66cSDavid du Colombier
1595e96a66cSDavid du Colombier cons = vtMemAllocZ(sizeof(Cons));
1605e96a66cSDavid du Colombier cons->lock = vtLockAlloc();
1615e96a66cSDavid du Colombier cons->fd = fd;
1625e96a66cSDavid du Colombier cons->srvfd = srvfd;
1635e96a66cSDavid du Colombier cons->ctlfd = ctlfd;
1645e96a66cSDavid du Colombier cons->iq = console.iq;
1655e96a66cSDavid du Colombier cons->oq = console.oq;
166dc5a79c1SDavid du Colombier console.nopens++;
1675e96a66cSDavid du Colombier
1685e96a66cSDavid du Colombier vtLock(cons->lock);
1695e96a66cSDavid du Colombier cons->ref = 2;
1705e96a66cSDavid du Colombier cons->closed = 0;
1715e96a66cSDavid du Colombier if(vtThread(consOProc, cons) < 0){
1725e96a66cSDavid du Colombier cons->ref--;
1735e96a66cSDavid du Colombier vtUnlock(cons->lock);
1745e96a66cSDavid du Colombier consClose(cons);
1755e96a66cSDavid du Colombier return 0;
1765e96a66cSDavid du Colombier }
1775e96a66cSDavid du Colombier vtUnlock(cons->lock);
1785e96a66cSDavid du Colombier
1795e96a66cSDavid du Colombier if(ctlfd >= 0)
1805e96a66cSDavid du Colombier consIProc(cons);
1815e96a66cSDavid du Colombier else if(vtThread(consIProc, cons) < 0){
1825e96a66cSDavid du Colombier consClose(cons);
1835e96a66cSDavid du Colombier return 0;
1845e96a66cSDavid du Colombier }
1855e96a66cSDavid du Colombier
1865e96a66cSDavid du Colombier return 1;
1875e96a66cSDavid du Colombier }
1885e96a66cSDavid du Colombier
1895e96a66cSDavid du Colombier static int
qWrite(Q * q,char * p,int n)1905e96a66cSDavid du Colombier qWrite(Q* q, char* p, int n)
1915e96a66cSDavid du Colombier {
1925e96a66cSDavid du Colombier int w;
1935e96a66cSDavid du Colombier
1945e96a66cSDavid du Colombier vtLock(q->lock);
1955e96a66cSDavid du Colombier if(n > Nq - q->w){
1965e96a66cSDavid du Colombier w = Nq - q->w;
1975e96a66cSDavid du Colombier memmove(&q->q[q->w], p, w);
1985e96a66cSDavid du Colombier memmove(&q->q[0], p + w, n - w);
1995e96a66cSDavid du Colombier q->w = n - w;
2005e96a66cSDavid du Colombier }
2015e96a66cSDavid du Colombier else{
2025e96a66cSDavid du Colombier memmove(&q->q[q->w], p, n);
2035e96a66cSDavid du Colombier q->w += n;
2045e96a66cSDavid du Colombier }
2055e96a66cSDavid du Colombier q->n += n;
2065e96a66cSDavid du Colombier vtWakeup(q->empty);
2075e96a66cSDavid du Colombier vtUnlock(q->lock);
2085e96a66cSDavid du Colombier
2095e96a66cSDavid du Colombier return n;
2105e96a66cSDavid du Colombier }
2115e96a66cSDavid du Colombier
2125e96a66cSDavid du Colombier static Q*
qAlloc(void)2135e96a66cSDavid du Colombier qAlloc(void)
2145e96a66cSDavid du Colombier {
2155e96a66cSDavid du Colombier Q *q;
2165e96a66cSDavid du Colombier
2175e96a66cSDavid du Colombier q = vtMemAllocZ(sizeof(Q));
2185e96a66cSDavid du Colombier q->lock = vtLockAlloc();
2195e96a66cSDavid du Colombier q->full = vtRendezAlloc(q->lock);
2205e96a66cSDavid du Colombier q->empty = vtRendezAlloc(q->lock);
2215e96a66cSDavid du Colombier q->n = q->r = q->w = 0;
2225e96a66cSDavid du Colombier
2235e96a66cSDavid du Colombier return q;
2245e96a66cSDavid du Colombier }
2255e96a66cSDavid du Colombier
2265e96a66cSDavid du Colombier static void
consProc(void *)2275e96a66cSDavid du Colombier consProc(void*)
2285e96a66cSDavid du Colombier {
2295e96a66cSDavid du Colombier Q *q;
2305e96a66cSDavid du Colombier int argc, i, n, r;
2315e96a66cSDavid du Colombier char *argv[20], buf[Nq], *lp, *wbuf;
232*b8a11165SDavid du Colombier char procname[64];
2335e96a66cSDavid du Colombier
234*b8a11165SDavid du Colombier snprint(procname, sizeof procname, "cons %s", currfsysname);
235*b8a11165SDavid du Colombier vtThreadSetName(procname);
2365e96a66cSDavid du Colombier
2375e96a66cSDavid du Colombier q = console.iq;
2385e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np);
2395e96a66cSDavid du Colombier vtLock(q->lock);
2405e96a66cSDavid du Colombier for(;;){
2415e96a66cSDavid du Colombier while((n = q->n) == 0)
2425e96a66cSDavid du Colombier vtSleep(q->empty);
2435e96a66cSDavid du Colombier r = Nq - q->r;
2445e96a66cSDavid du Colombier if(r < n){
2455e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], r);
2465e96a66cSDavid du Colombier memmove(buf + r, &q->q[0], n - r);
2475e96a66cSDavid du Colombier }
2485e96a66cSDavid du Colombier else
2495e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], n);
2505e96a66cSDavid du Colombier q->r = (q->r + n) % Nq;
2515e96a66cSDavid du Colombier q->n -= n;
2525e96a66cSDavid du Colombier vtWakeup(q->full);
2535e96a66cSDavid du Colombier vtUnlock(q->lock);
2545e96a66cSDavid du Colombier
2555e96a66cSDavid du Colombier for(i = 0; i < n; i++){
2565e96a66cSDavid du Colombier switch(buf[i]){
2575e96a66cSDavid du Colombier case '\004': /* ^D */
2585e96a66cSDavid du Colombier if(console.nl == 0){
2595e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1);
2605e96a66cSDavid du Colombier break;
2615e96a66cSDavid du Colombier }
2625e96a66cSDavid du Colombier /*FALLTHROUGH*/
2635e96a66cSDavid du Colombier default:
2645e96a66cSDavid du Colombier if(console.nl < Nl-1){
2655e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2665e96a66cSDavid du Colombier console.l[console.nl++] = buf[i];
2675e96a66cSDavid du Colombier }
2685e96a66cSDavid du Colombier continue;
2695e96a66cSDavid du Colombier case '\b':
2705e96a66cSDavid du Colombier if(console.nl != 0){
2715e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2725e96a66cSDavid du Colombier console.nl--;
2735e96a66cSDavid du Colombier }
2745e96a66cSDavid du Colombier continue;
2755e96a66cSDavid du Colombier case '\n':
2765e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1);
2775e96a66cSDavid du Colombier break;
2785e96a66cSDavid du Colombier case '\025': /* ^U */
2795e96a66cSDavid du Colombier qWrite(console.oq, "^U\n", 3);
2805e96a66cSDavid du Colombier console.nl = 0;
2815e96a66cSDavid du Colombier break;
2825e96a66cSDavid du Colombier case '\027': /* ^W */
2835e96a66cSDavid du Colombier console.l[console.nl] = '\0';
2845e96a66cSDavid du Colombier wbuf = vtMemAlloc(console.nl+1);
2855e96a66cSDavid du Colombier memmove(wbuf, console.l, console.nl+1);
2865e96a66cSDavid du Colombier argc = tokenize(wbuf, argv, nelem(argv));
2875e96a66cSDavid du Colombier if(argc > 0)
2885e96a66cSDavid du Colombier argc--;
2895e96a66cSDavid du Colombier console.nl = 0;
2905e96a66cSDavid du Colombier lp = console.l;
2915e96a66cSDavid du Colombier for(i = 0; i < argc; i++)
2925e96a66cSDavid du Colombier lp += sprint(lp, "%q ", argv[i]);
2935e96a66cSDavid du Colombier console.nl = lp - console.l;
2945e96a66cSDavid du Colombier vtMemFree(wbuf);
2955e96a66cSDavid du Colombier qWrite(console.oq, "^W\n", 3);
2965e96a66cSDavid du Colombier if(console.nl == 0)
2975e96a66cSDavid du Colombier break;
2985e96a66cSDavid du Colombier qWrite(console.oq, console.l, console.nl);
2995e96a66cSDavid du Colombier continue;
3005e96a66cSDavid du Colombier case '\177':
3015e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1);
3025e96a66cSDavid du Colombier console.nl = 0;
3035e96a66cSDavid du Colombier break;
3045e96a66cSDavid du Colombier }
3055e96a66cSDavid du Colombier
3065e96a66cSDavid du Colombier console.l[console.nl] = '\0';
3075e96a66cSDavid du Colombier if(console.nl != 0)
3085e96a66cSDavid du Colombier cliExec(console.l);
3095e96a66cSDavid du Colombier
3105e96a66cSDavid du Colombier console.nl = 0;
3115e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np);
3125e96a66cSDavid du Colombier }
3135e96a66cSDavid du Colombier
3145e96a66cSDavid du Colombier vtLock(q->lock);
3155e96a66cSDavid du Colombier }
3165e96a66cSDavid du Colombier }
3175e96a66cSDavid du Colombier
3185e96a66cSDavid du Colombier int
consWrite(char * buf,int len)3195e96a66cSDavid du Colombier consWrite(char* buf, int len)
3205e96a66cSDavid du Colombier {
3215e96a66cSDavid du Colombier if(console.oq == nil)
322dc5a79c1SDavid du Colombier return write(2, buf, len);
323dc5a79c1SDavid du Colombier if(console.nopens == 0)
324dc5a79c1SDavid du Colombier write(2, buf, len);
3255e96a66cSDavid du Colombier return qWrite(console.oq, buf, len);
3265e96a66cSDavid du Colombier }
3275e96a66cSDavid du Colombier
3285e96a66cSDavid du Colombier int
consPrompt(char * prompt)3295e96a66cSDavid du Colombier consPrompt(char* prompt)
3305e96a66cSDavid du Colombier {
3315e96a66cSDavid du Colombier char buf[ERRMAX];
3325e96a66cSDavid du Colombier
3335e96a66cSDavid du Colombier if(prompt == nil)
3345e96a66cSDavid du Colombier prompt = "prompt";
3355e96a66cSDavid du Colombier
3365e96a66cSDavid du Colombier vtMemFree(console.prompt);
3375e96a66cSDavid du Colombier console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
3385e96a66cSDavid du Colombier console.prompt = vtStrDup(buf);
3395e96a66cSDavid du Colombier
3405e96a66cSDavid du Colombier return console.np;
3415e96a66cSDavid du Colombier }
3425e96a66cSDavid du Colombier
3435e96a66cSDavid du Colombier int
consTTY(void)3445e96a66cSDavid du Colombier consTTY(void)
3455e96a66cSDavid du Colombier {
3465e96a66cSDavid du Colombier int ctl, fd;
3475e96a66cSDavid du Colombier char *name, *p;
3485e96a66cSDavid du Colombier
3495e96a66cSDavid du Colombier name = "/dev/cons";
3505e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){
3515e96a66cSDavid du Colombier name = "#c/cons";
3525e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){
3535e96a66cSDavid du Colombier vtSetError("consTTY: open %s: %r", name);
3545e96a66cSDavid du Colombier return 0;
3555e96a66cSDavid du Colombier }
3565e96a66cSDavid du Colombier }
3575e96a66cSDavid du Colombier
3585e96a66cSDavid du Colombier p = smprint("%sctl", name);
3595e96a66cSDavid du Colombier if((ctl = open(p, OWRITE)) < 0){
3605e96a66cSDavid du Colombier close(fd);
3615e96a66cSDavid du Colombier vtSetError("consTTY: open %s: %r", p);
3625e96a66cSDavid du Colombier free(p);
3635e96a66cSDavid du Colombier return 0;
3645e96a66cSDavid du Colombier }
3655e96a66cSDavid du Colombier if(write(ctl, "rawon", 5) < 0){
3665e96a66cSDavid du Colombier close(ctl);
3675e96a66cSDavid du Colombier close(fd);
3685e96a66cSDavid du Colombier vtSetError("consTTY: write %s: %r", p);
3695e96a66cSDavid du Colombier free(p);
3705e96a66cSDavid du Colombier return 0;
3715e96a66cSDavid du Colombier }
3725e96a66cSDavid du Colombier free(p);
3735e96a66cSDavid du Colombier
3745e96a66cSDavid du Colombier if(consOpen(fd, fd, ctl) == 0){
3755e96a66cSDavid du Colombier close(ctl);
3765e96a66cSDavid du Colombier close(fd);
3775e96a66cSDavid du Colombier return 0;
3785e96a66cSDavid du Colombier }
3795e96a66cSDavid du Colombier
3805e96a66cSDavid du Colombier return 1;
3815e96a66cSDavid du Colombier }
3825e96a66cSDavid du Colombier
3835e96a66cSDavid du Colombier int
consInit(void)3845e96a66cSDavid du Colombier consInit(void)
3855e96a66cSDavid du Colombier {
3865e96a66cSDavid du Colombier console.iq = qAlloc();
3875e96a66cSDavid du Colombier console.oq = qAlloc();
3885e96a66cSDavid du Colombier console.nl = 0;
3895e96a66cSDavid du Colombier
3905e96a66cSDavid du Colombier consPrompt(nil);
3915e96a66cSDavid du Colombier
3925e96a66cSDavid du Colombier if(vtThread(consProc, nil) < 0){
3935e96a66cSDavid du Colombier vtFatal("can't start console proc");
3945e96a66cSDavid du Colombier return 0;
3955e96a66cSDavid du Colombier }
3965e96a66cSDavid du Colombier
3975e96a66cSDavid du Colombier return 1;
3985e96a66cSDavid du Colombier }
399