1*5e96a66cSDavid du Colombier #include "stdinc.h" 2*5e96a66cSDavid du Colombier 3*5e96a66cSDavid du Colombier #include "9.h" 4*5e96a66cSDavid du Colombier 5*5e96a66cSDavid du Colombier enum { 6*5e96a66cSDavid du Colombier Nl = 256, /* max. command line length */ 7*5e96a66cSDavid du Colombier Nq = 8*1024, /* amount of I/O buffered */ 8*5e96a66cSDavid du Colombier }; 9*5e96a66cSDavid du Colombier 10*5e96a66cSDavid du Colombier typedef struct Q { 11*5e96a66cSDavid du Colombier VtLock* lock; 12*5e96a66cSDavid du Colombier VtRendez* full; 13*5e96a66cSDavid du Colombier VtRendez* empty; 14*5e96a66cSDavid du Colombier 15*5e96a66cSDavid du Colombier char q[Nq]; 16*5e96a66cSDavid du Colombier int n; 17*5e96a66cSDavid du Colombier int r; 18*5e96a66cSDavid du Colombier int w; 19*5e96a66cSDavid du Colombier } Q; 20*5e96a66cSDavid du Colombier 21*5e96a66cSDavid du Colombier typedef struct Cons { 22*5e96a66cSDavid du Colombier VtLock* lock; 23*5e96a66cSDavid du Colombier int ref; 24*5e96a66cSDavid du Colombier int closed; 25*5e96a66cSDavid du Colombier int fd; 26*5e96a66cSDavid du Colombier int srvfd; 27*5e96a66cSDavid du Colombier int ctlfd; 28*5e96a66cSDavid du Colombier Q* iq; /* points to console.iq */ 29*5e96a66cSDavid du Colombier Q* oq; /* points to console.oq */ 30*5e96a66cSDavid du Colombier } Cons; 31*5e96a66cSDavid du Colombier 32*5e96a66cSDavid du Colombier static struct { 33*5e96a66cSDavid du Colombier Q* iq; /* input */ 34*5e96a66cSDavid du Colombier Q* oq; /* output */ 35*5e96a66cSDavid du Colombier char l[Nl]; /* command line assembly */ 36*5e96a66cSDavid du Colombier int nl; /* current line length */ 37*5e96a66cSDavid du Colombier 38*5e96a66cSDavid du Colombier char* prompt; 39*5e96a66cSDavid du Colombier int np; 40*5e96a66cSDavid du Colombier } console; 41*5e96a66cSDavid du Colombier 42*5e96a66cSDavid du Colombier static void 43*5e96a66cSDavid du Colombier consClose(Cons* cons) 44*5e96a66cSDavid du Colombier { 45*5e96a66cSDavid du Colombier vtLock(cons->lock); 46*5e96a66cSDavid du Colombier cons->closed = 1; 47*5e96a66cSDavid du Colombier 48*5e96a66cSDavid du Colombier cons->ref--; 49*5e96a66cSDavid du Colombier if(cons->ref > 0){ 50*5e96a66cSDavid du Colombier vtLock(cons->iq->lock); 51*5e96a66cSDavid du Colombier vtWakeup(cons->iq->full); 52*5e96a66cSDavid du Colombier vtUnlock(cons->iq->lock); 53*5e96a66cSDavid du Colombier vtLock(cons->oq->lock); 54*5e96a66cSDavid du Colombier vtWakeup(cons->oq->empty); 55*5e96a66cSDavid du Colombier vtUnlock(cons->oq->lock); 56*5e96a66cSDavid du Colombier vtUnlock(cons->lock); 57*5e96a66cSDavid du Colombier return; 58*5e96a66cSDavid du Colombier } 59*5e96a66cSDavid du Colombier 60*5e96a66cSDavid du Colombier if(cons->ctlfd != -1){ 61*5e96a66cSDavid du Colombier close(cons->ctlfd); 62*5e96a66cSDavid du Colombier cons->srvfd = -1; 63*5e96a66cSDavid du Colombier } 64*5e96a66cSDavid du Colombier if(cons->srvfd != -1){ 65*5e96a66cSDavid du Colombier close(cons->srvfd); 66*5e96a66cSDavid du Colombier cons->srvfd = -1; 67*5e96a66cSDavid du Colombier } 68*5e96a66cSDavid du Colombier if(cons->fd != -1){ 69*5e96a66cSDavid du Colombier close(cons->fd); 70*5e96a66cSDavid du Colombier cons->fd = -1; 71*5e96a66cSDavid du Colombier } 72*5e96a66cSDavid du Colombier 73*5e96a66cSDavid du Colombier vtUnlock(cons->lock); 74*5e96a66cSDavid du Colombier vtLockFree(cons->lock); 75*5e96a66cSDavid du Colombier vtMemFree(cons); 76*5e96a66cSDavid du Colombier } 77*5e96a66cSDavid du Colombier 78*5e96a66cSDavid du Colombier static void 79*5e96a66cSDavid du Colombier consIProc(void* v) 80*5e96a66cSDavid du Colombier { 81*5e96a66cSDavid du Colombier Q *q; 82*5e96a66cSDavid du Colombier Cons *cons; 83*5e96a66cSDavid du Colombier int n, w; 84*5e96a66cSDavid du Colombier char buf[Nq/4]; 85*5e96a66cSDavid du Colombier 86*5e96a66cSDavid du Colombier vtThreadSetName("consI"); 87*5e96a66cSDavid du Colombier 88*5e96a66cSDavid du Colombier cons = v; 89*5e96a66cSDavid du Colombier q = cons->iq; 90*5e96a66cSDavid du Colombier for(;;){ 91*5e96a66cSDavid du Colombier /* 92*5e96a66cSDavid du Colombier * Can't tell the difference between zero-length read 93*5e96a66cSDavid du Colombier * and eof, so keep calling read until we get an error. 94*5e96a66cSDavid du Colombier */ 95*5e96a66cSDavid du Colombier if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0) 96*5e96a66cSDavid du Colombier break; 97*5e96a66cSDavid du Colombier vtLock(q->lock); 98*5e96a66cSDavid du Colombier while(Nq - q->n < n && !cons->closed) 99*5e96a66cSDavid du Colombier vtSleep(q->full); 100*5e96a66cSDavid du Colombier w = Nq - q->w; 101*5e96a66cSDavid du Colombier if(w < n){ 102*5e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, w); 103*5e96a66cSDavid du Colombier memmove(&q->q[0], buf + w, n - w); 104*5e96a66cSDavid du Colombier } 105*5e96a66cSDavid du Colombier else 106*5e96a66cSDavid du Colombier memmove(&q->q[q->w], buf, n); 107*5e96a66cSDavid du Colombier q->w = (q->w + n) % Nq; 108*5e96a66cSDavid du Colombier q->n += n; 109*5e96a66cSDavid du Colombier vtWakeup(q->empty); 110*5e96a66cSDavid du Colombier vtUnlock(q->lock); 111*5e96a66cSDavid du Colombier } 112*5e96a66cSDavid du Colombier consClose(cons); 113*5e96a66cSDavid du Colombier } 114*5e96a66cSDavid du Colombier 115*5e96a66cSDavid du Colombier static void 116*5e96a66cSDavid du Colombier consOProc(void* v) 117*5e96a66cSDavid du Colombier { 118*5e96a66cSDavid du Colombier Q *q; 119*5e96a66cSDavid du Colombier Cons *cons; 120*5e96a66cSDavid du Colombier char buf[Nq]; 121*5e96a66cSDavid du Colombier int lastn, n, r; 122*5e96a66cSDavid du Colombier 123*5e96a66cSDavid du Colombier vtThreadSetName("consO"); 124*5e96a66cSDavid du Colombier 125*5e96a66cSDavid du Colombier cons = v; 126*5e96a66cSDavid du Colombier q = cons->oq; 127*5e96a66cSDavid du Colombier vtLock(q->lock); 128*5e96a66cSDavid du Colombier lastn = 0; 129*5e96a66cSDavid du Colombier for(;;){ 130*5e96a66cSDavid du Colombier while(lastn == q->n && !cons->closed) 131*5e96a66cSDavid du Colombier vtSleep(q->empty); 132*5e96a66cSDavid du Colombier if((n = q->n - lastn) > Nq) 133*5e96a66cSDavid du Colombier n = Nq; 134*5e96a66cSDavid du Colombier if(n > q->w){ 135*5e96a66cSDavid du Colombier r = n - q->w; 136*5e96a66cSDavid du Colombier memmove(buf, &q->q[Nq - r], r); 137*5e96a66cSDavid du Colombier memmove(buf+r, &q->q[0], n - r); 138*5e96a66cSDavid du Colombier } 139*5e96a66cSDavid du Colombier else 140*5e96a66cSDavid du Colombier memmove(buf, &q->q[q->w - n], n); 141*5e96a66cSDavid du Colombier lastn = q->n; 142*5e96a66cSDavid du Colombier vtUnlock(q->lock); 143*5e96a66cSDavid du Colombier if(cons->closed || write(cons->fd, buf, n) < 0) 144*5e96a66cSDavid du Colombier break; 145*5e96a66cSDavid du Colombier vtLock(q->lock); 146*5e96a66cSDavid du Colombier vtWakeup(q->empty); 147*5e96a66cSDavid du Colombier } 148*5e96a66cSDavid du Colombier consClose(cons); 149*5e96a66cSDavid du Colombier } 150*5e96a66cSDavid du Colombier 151*5e96a66cSDavid du Colombier int 152*5e96a66cSDavid du Colombier consOpen(int fd, int srvfd, int ctlfd) 153*5e96a66cSDavid du Colombier { 154*5e96a66cSDavid du Colombier Cons *cons; 155*5e96a66cSDavid du Colombier 156*5e96a66cSDavid du Colombier cons = vtMemAllocZ(sizeof(Cons)); 157*5e96a66cSDavid du Colombier cons->lock = vtLockAlloc(); 158*5e96a66cSDavid du Colombier cons->fd = fd; 159*5e96a66cSDavid du Colombier cons->srvfd = srvfd; 160*5e96a66cSDavid du Colombier cons->ctlfd = ctlfd; 161*5e96a66cSDavid du Colombier cons->iq = console.iq; 162*5e96a66cSDavid du Colombier cons->oq = console.oq; 163*5e96a66cSDavid du Colombier 164*5e96a66cSDavid du Colombier vtLock(cons->lock); 165*5e96a66cSDavid du Colombier cons->ref = 2; 166*5e96a66cSDavid du Colombier cons->closed = 0; 167*5e96a66cSDavid du Colombier if(vtThread(consOProc, cons) < 0){ 168*5e96a66cSDavid du Colombier cons->ref--; 169*5e96a66cSDavid du Colombier vtUnlock(cons->lock); 170*5e96a66cSDavid du Colombier consClose(cons); 171*5e96a66cSDavid du Colombier return 0; 172*5e96a66cSDavid du Colombier } 173*5e96a66cSDavid du Colombier vtUnlock(cons->lock); 174*5e96a66cSDavid du Colombier 175*5e96a66cSDavid du Colombier if(ctlfd >= 0) 176*5e96a66cSDavid du Colombier consIProc(cons); 177*5e96a66cSDavid du Colombier else if(vtThread(consIProc, cons) < 0){ 178*5e96a66cSDavid du Colombier consClose(cons); 179*5e96a66cSDavid du Colombier return 0; 180*5e96a66cSDavid du Colombier } 181*5e96a66cSDavid du Colombier 182*5e96a66cSDavid du Colombier return 1; 183*5e96a66cSDavid du Colombier } 184*5e96a66cSDavid du Colombier 185*5e96a66cSDavid du Colombier static int 186*5e96a66cSDavid du Colombier qWrite(Q* q, char* p, int n) 187*5e96a66cSDavid du Colombier { 188*5e96a66cSDavid du Colombier int w; 189*5e96a66cSDavid du Colombier 190*5e96a66cSDavid du Colombier vtLock(q->lock); 191*5e96a66cSDavid du Colombier if(n > Nq - q->w){ 192*5e96a66cSDavid du Colombier w = Nq - q->w; 193*5e96a66cSDavid du Colombier memmove(&q->q[q->w], p, w); 194*5e96a66cSDavid du Colombier memmove(&q->q[0], p + w, n - w); 195*5e96a66cSDavid du Colombier q->w = n - w; 196*5e96a66cSDavid du Colombier } 197*5e96a66cSDavid du Colombier else{ 198*5e96a66cSDavid du Colombier memmove(&q->q[q->w], p, n); 199*5e96a66cSDavid du Colombier q->w += n; 200*5e96a66cSDavid du Colombier } 201*5e96a66cSDavid du Colombier q->n += n; 202*5e96a66cSDavid du Colombier vtWakeup(q->empty); 203*5e96a66cSDavid du Colombier vtUnlock(q->lock); 204*5e96a66cSDavid du Colombier 205*5e96a66cSDavid du Colombier return n; 206*5e96a66cSDavid du Colombier } 207*5e96a66cSDavid du Colombier 208*5e96a66cSDavid du Colombier static Q* 209*5e96a66cSDavid du Colombier qAlloc(void) 210*5e96a66cSDavid du Colombier { 211*5e96a66cSDavid du Colombier Q *q; 212*5e96a66cSDavid du Colombier 213*5e96a66cSDavid du Colombier q = vtMemAllocZ(sizeof(Q)); 214*5e96a66cSDavid du Colombier q->lock = vtLockAlloc(); 215*5e96a66cSDavid du Colombier q->full = vtRendezAlloc(q->lock); 216*5e96a66cSDavid du Colombier q->empty = vtRendezAlloc(q->lock); 217*5e96a66cSDavid du Colombier q->n = q->r = q->w = 0; 218*5e96a66cSDavid du Colombier 219*5e96a66cSDavid du Colombier return q; 220*5e96a66cSDavid du Colombier } 221*5e96a66cSDavid du Colombier 222*5e96a66cSDavid du Colombier static void 223*5e96a66cSDavid du Colombier consProc(void*) 224*5e96a66cSDavid du Colombier { 225*5e96a66cSDavid du Colombier Q *q; 226*5e96a66cSDavid du Colombier int argc, i, n, r; 227*5e96a66cSDavid du Colombier char *argv[20], buf[Nq], *lp, *wbuf; 228*5e96a66cSDavid du Colombier 229*5e96a66cSDavid du Colombier vtThreadSetName("cons"); 230*5e96a66cSDavid du Colombier 231*5e96a66cSDavid du Colombier q = console.iq; 232*5e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np); 233*5e96a66cSDavid du Colombier vtLock(q->lock); 234*5e96a66cSDavid du Colombier for(;;){ 235*5e96a66cSDavid du Colombier while((n = q->n) == 0) 236*5e96a66cSDavid du Colombier vtSleep(q->empty); 237*5e96a66cSDavid du Colombier r = Nq - q->r; 238*5e96a66cSDavid du Colombier if(r < n){ 239*5e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], r); 240*5e96a66cSDavid du Colombier memmove(buf + r, &q->q[0], n - r); 241*5e96a66cSDavid du Colombier } 242*5e96a66cSDavid du Colombier else 243*5e96a66cSDavid du Colombier memmove(buf, &q->q[q->r], n); 244*5e96a66cSDavid du Colombier q->r = (q->r + n) % Nq; 245*5e96a66cSDavid du Colombier q->n -= n; 246*5e96a66cSDavid du Colombier vtWakeup(q->full); 247*5e96a66cSDavid du Colombier vtUnlock(q->lock); 248*5e96a66cSDavid du Colombier 249*5e96a66cSDavid du Colombier for(i = 0; i < n; i++){ 250*5e96a66cSDavid du Colombier switch(buf[i]){ 251*5e96a66cSDavid du Colombier case '\004': /* ^D */ 252*5e96a66cSDavid du Colombier if(console.nl == 0){ 253*5e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1); 254*5e96a66cSDavid du Colombier break; 255*5e96a66cSDavid du Colombier } 256*5e96a66cSDavid du Colombier /*FALLTHROUGH*/ 257*5e96a66cSDavid du Colombier default: 258*5e96a66cSDavid du Colombier if(console.nl < Nl-1){ 259*5e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1); 260*5e96a66cSDavid du Colombier console.l[console.nl++] = buf[i]; 261*5e96a66cSDavid du Colombier } 262*5e96a66cSDavid du Colombier continue; 263*5e96a66cSDavid du Colombier case '\b': 264*5e96a66cSDavid du Colombier if(console.nl != 0){ 265*5e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1); 266*5e96a66cSDavid du Colombier console.nl--; 267*5e96a66cSDavid du Colombier } 268*5e96a66cSDavid du Colombier continue; 269*5e96a66cSDavid du Colombier case '\n': 270*5e96a66cSDavid du Colombier qWrite(console.oq, &buf[i], 1); 271*5e96a66cSDavid du Colombier break; 272*5e96a66cSDavid du Colombier case '\025': /* ^U */ 273*5e96a66cSDavid du Colombier qWrite(console.oq, "^U\n", 3); 274*5e96a66cSDavid du Colombier console.nl = 0; 275*5e96a66cSDavid du Colombier break; 276*5e96a66cSDavid du Colombier case '\027': /* ^W */ 277*5e96a66cSDavid du Colombier console.l[console.nl] = '\0'; 278*5e96a66cSDavid du Colombier wbuf = vtMemAlloc(console.nl+1); 279*5e96a66cSDavid du Colombier memmove(wbuf, console.l, console.nl+1); 280*5e96a66cSDavid du Colombier argc = tokenize(wbuf, argv, nelem(argv)); 281*5e96a66cSDavid du Colombier if(argc > 0) 282*5e96a66cSDavid du Colombier argc--; 283*5e96a66cSDavid du Colombier console.nl = 0; 284*5e96a66cSDavid du Colombier lp = console.l; 285*5e96a66cSDavid du Colombier for(i = 0; i < argc; i++) 286*5e96a66cSDavid du Colombier lp += sprint(lp, "%q ", argv[i]); 287*5e96a66cSDavid du Colombier console.nl = lp - console.l; 288*5e96a66cSDavid du Colombier vtMemFree(wbuf); 289*5e96a66cSDavid du Colombier qWrite(console.oq, "^W\n", 3); 290*5e96a66cSDavid du Colombier if(console.nl == 0) 291*5e96a66cSDavid du Colombier break; 292*5e96a66cSDavid du Colombier qWrite(console.oq, console.l, console.nl); 293*5e96a66cSDavid du Colombier continue; 294*5e96a66cSDavid du Colombier case '\177': 295*5e96a66cSDavid du Colombier qWrite(console.oq, "\n", 1); 296*5e96a66cSDavid du Colombier console.nl = 0; 297*5e96a66cSDavid du Colombier break; 298*5e96a66cSDavid du Colombier } 299*5e96a66cSDavid du Colombier 300*5e96a66cSDavid du Colombier console.l[console.nl] = '\0'; 301*5e96a66cSDavid du Colombier if(console.nl != 0) 302*5e96a66cSDavid du Colombier cliExec(console.l); 303*5e96a66cSDavid du Colombier 304*5e96a66cSDavid du Colombier console.nl = 0; 305*5e96a66cSDavid du Colombier qWrite(console.oq, console.prompt, console.np); 306*5e96a66cSDavid du Colombier } 307*5e96a66cSDavid du Colombier 308*5e96a66cSDavid du Colombier vtLock(q->lock); 309*5e96a66cSDavid du Colombier } 310*5e96a66cSDavid du Colombier } 311*5e96a66cSDavid du Colombier 312*5e96a66cSDavid du Colombier int 313*5e96a66cSDavid du Colombier consWrite(char* buf, int len) 314*5e96a66cSDavid du Colombier { 315*5e96a66cSDavid du Colombier if(console.oq == nil) 316*5e96a66cSDavid du Colombier return fprint(2, buf, len); 317*5e96a66cSDavid du Colombier return qWrite(console.oq, buf, len); 318*5e96a66cSDavid du Colombier } 319*5e96a66cSDavid du Colombier 320*5e96a66cSDavid du Colombier int 321*5e96a66cSDavid du Colombier consPrompt(char* prompt) 322*5e96a66cSDavid du Colombier { 323*5e96a66cSDavid du Colombier char buf[ERRMAX]; 324*5e96a66cSDavid du Colombier 325*5e96a66cSDavid du Colombier if(prompt == nil) 326*5e96a66cSDavid du Colombier prompt = "prompt"; 327*5e96a66cSDavid du Colombier 328*5e96a66cSDavid du Colombier vtMemFree(console.prompt); 329*5e96a66cSDavid du Colombier console.np = snprint(buf, sizeof(buf), "%s: ", prompt); 330*5e96a66cSDavid du Colombier console.prompt = vtStrDup(buf); 331*5e96a66cSDavid du Colombier 332*5e96a66cSDavid du Colombier return console.np; 333*5e96a66cSDavid du Colombier } 334*5e96a66cSDavid du Colombier 335*5e96a66cSDavid du Colombier int 336*5e96a66cSDavid du Colombier consTTY(void) 337*5e96a66cSDavid du Colombier { 338*5e96a66cSDavid du Colombier int ctl, fd; 339*5e96a66cSDavid du Colombier char *name, *p; 340*5e96a66cSDavid du Colombier 341*5e96a66cSDavid du Colombier name = "/dev/cons"; 342*5e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){ 343*5e96a66cSDavid du Colombier name = "#c/cons"; 344*5e96a66cSDavid du Colombier if((fd = open(name, ORDWR)) < 0){ 345*5e96a66cSDavid du Colombier vtSetError("consTTY: open %s: %r", name); 346*5e96a66cSDavid du Colombier return 0; 347*5e96a66cSDavid du Colombier } 348*5e96a66cSDavid du Colombier } 349*5e96a66cSDavid du Colombier 350*5e96a66cSDavid du Colombier p = smprint("%sctl", name); 351*5e96a66cSDavid du Colombier if((ctl = open(p, OWRITE)) < 0){ 352*5e96a66cSDavid du Colombier close(fd); 353*5e96a66cSDavid du Colombier vtSetError("consTTY: open %s: %r", p); 354*5e96a66cSDavid du Colombier free(p); 355*5e96a66cSDavid du Colombier return 0; 356*5e96a66cSDavid du Colombier } 357*5e96a66cSDavid du Colombier if(write(ctl, "rawon", 5) < 0){ 358*5e96a66cSDavid du Colombier close(ctl); 359*5e96a66cSDavid du Colombier close(fd); 360*5e96a66cSDavid du Colombier vtSetError("consTTY: write %s: %r", p); 361*5e96a66cSDavid du Colombier free(p); 362*5e96a66cSDavid du Colombier return 0; 363*5e96a66cSDavid du Colombier } 364*5e96a66cSDavid du Colombier free(p); 365*5e96a66cSDavid du Colombier 366*5e96a66cSDavid du Colombier if(consOpen(fd, fd, ctl) == 0){ 367*5e96a66cSDavid du Colombier close(ctl); 368*5e96a66cSDavid du Colombier close(fd); 369*5e96a66cSDavid du Colombier return 0; 370*5e96a66cSDavid du Colombier } 371*5e96a66cSDavid du Colombier 372*5e96a66cSDavid du Colombier return 1; 373*5e96a66cSDavid du Colombier } 374*5e96a66cSDavid du Colombier 375*5e96a66cSDavid du Colombier int 376*5e96a66cSDavid du Colombier consInit(void) 377*5e96a66cSDavid du Colombier { 378*5e96a66cSDavid du Colombier console.iq = qAlloc(); 379*5e96a66cSDavid du Colombier console.oq = qAlloc(); 380*5e96a66cSDavid du Colombier console.nl = 0; 381*5e96a66cSDavid du Colombier 382*5e96a66cSDavid du Colombier consPrompt(nil); 383*5e96a66cSDavid du Colombier 384*5e96a66cSDavid du Colombier if(vtThread(consProc, nil) < 0){ 385*5e96a66cSDavid du Colombier vtFatal("can't start console proc"); 386*5e96a66cSDavid du Colombier return 0; 387*5e96a66cSDavid du Colombier } 388*5e96a66cSDavid du Colombier 389*5e96a66cSDavid du Colombier return 1; 390*5e96a66cSDavid du Colombier } 391