Blob
1 #include "stdinc.h"3 #include "9.h"5 enum {6 Nl = 256, /* max. command line length */7 Nq = 8*1024, /* amount of I/O buffered */8 };10 typedef struct Q {11 QLock lock;12 Rendez full;13 Rendez empty;15 char q[Nq];16 int n;17 int r;18 int w;19 } Q;21 typedef struct Cons {22 QLock lock;23 int ref;24 int closed;25 int fd;26 int srvfd;27 int ctlfd;28 Q* iq; /* points to console.iq */29 Q* oq; /* points to console.oq */30 } Cons;32 char *currfsysname;34 static struct {35 Q* iq; /* input */36 Q* oq; /* output */37 char l[Nl]; /* command line assembly */38 int nl; /* current line length */39 int nopens;41 char* prompt;42 int np;43 } console;45 static void46 consClose(Cons* cons)47 {48 qlock(&cons->lock);49 cons->closed = 1;51 cons->ref--;52 if(cons->ref > 0){53 qlock(&cons->iq->lock);54 rwakeup(&cons->iq->full);55 qunlock(&cons->iq->lock);56 qlock(&cons->oq->lock);57 rwakeup(&cons->oq->empty);58 qunlock(&cons->oq->lock);59 qunlock(&cons->lock);60 return;61 }63 if(cons->ctlfd != -1){64 close(cons->ctlfd);65 cons->srvfd = -1;66 }67 if(cons->srvfd != -1){68 close(cons->srvfd);69 cons->srvfd = -1;70 }71 if(cons->fd != -1){72 close(cons->fd);73 cons->fd = -1;74 }75 qunlock(&cons->lock);76 vtfree(cons);77 console.nopens--;78 }80 static void81 consIProc(void* v)82 {83 Q *q;84 Cons *cons;85 int n, w;86 char buf[Nq/4];88 threadsetname("consI");90 cons = v;91 q = cons->iq;92 for(;;){93 /*94 * Can't tell the difference between zero-length read95 * and eof, so keep calling read until we get an error.96 */97 if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0)98 break;99 qlock(&q->lock);100 while(Nq - q->n < n && !cons->closed)101 rsleep(&q->full);102 w = Nq - q->w;103 if(w < n){104 memmove(&q->q[q->w], buf, w);105 memmove(&q->q[0], buf + w, n - w);106 }107 else108 memmove(&q->q[q->w], buf, n);109 q->w = (q->w + n) % Nq;110 q->n += n;111 rwakeup(&q->empty);112 qunlock(&q->lock);113 }114 consClose(cons);115 }117 static void118 consOProc(void* v)119 {120 Q *q;121 Cons *cons;122 char buf[Nq];123 int lastn, n, r;125 threadsetname("consO");127 cons = v;128 q = cons->oq;129 qlock(&q->lock);130 lastn = 0;131 for(;;){132 while(lastn == q->n && !cons->closed)133 rsleep(&q->empty);134 if((n = q->n - lastn) > Nq)135 n = Nq;136 if(n > q->w){137 r = n - q->w;138 memmove(buf, &q->q[Nq - r], r);139 memmove(buf+r, &q->q[0], n - r);140 }141 else142 memmove(buf, &q->q[q->w - n], n);143 lastn = q->n;144 qunlock(&q->lock);145 if(cons->closed || write(cons->fd, buf, n) < 0)146 break;147 qlock(&q->lock);148 rwakeup(&q->empty);149 }150 consClose(cons);151 }153 int154 consOpen(int fd, int srvfd, int ctlfd)155 {156 Cons *cons;158 cons = vtmallocz(sizeof(Cons));159 cons->fd = fd;160 cons->srvfd = srvfd;161 cons->ctlfd = ctlfd;162 cons->iq = console.iq;163 cons->oq = console.oq;164 console.nopens++;166 qlock(&cons->lock);167 cons->ref = 2;168 cons->closed = 0;169 if(proccreate(consOProc, cons, STACK) < 0){170 cons->ref--;171 qunlock(&cons->lock);172 consClose(cons);173 return 0;174 }175 qunlock(&cons->lock);177 if(ctlfd >= 0)178 consIProc(cons);179 else if(proccreate(consIProc, cons, STACK) < 0){180 consClose(cons);181 return 0;182 }184 return 1;185 }187 static int188 qWrite(Q* q, char* p, int n)189 {190 int w;192 qlock(&q->lock);193 if(n > Nq - q->w){194 w = Nq - q->w;195 memmove(&q->q[q->w], p, w);196 memmove(&q->q[0], p + w, n - w);197 q->w = n - w;198 }199 else{200 memmove(&q->q[q->w], p, n);201 q->w += n;202 }203 q->n += n;204 rwakeup(&q->empty);205 qunlock(&q->lock);207 return n;208 }210 static Q*211 qAlloc(void)212 {213 Q *q;215 q = vtmallocz(sizeof(Q));216 q->full.l = &q->lock;217 q->empty.l = &q->lock;218 q->n = q->r = q->w = 0;220 return q;221 }223 static void224 consProc(void* v)225 {226 USED(v);227 Q *q;228 int argc, i, n, r;229 char *argv[20], buf[Nq], *lp, *wbuf;230 char procname[64];232 snprint(procname, sizeof procname, "cons %s", currfsysname);233 threadsetname(procname);235 q = console.iq;236 qWrite(console.oq, console.prompt, console.np);237 qlock(&q->lock);238 for(;;){239 while((n = q->n) == 0)240 rsleep(&q->empty);241 r = Nq - q->r;242 if(r < n){243 memmove(buf, &q->q[q->r], r);244 memmove(buf + r, &q->q[0], n - r);245 }246 else247 memmove(buf, &q->q[q->r], n);248 q->r = (q->r + n) % Nq;249 q->n -= n;250 rwakeup(&q->full);251 qunlock(&q->lock);253 for(i = 0; i < n; i++){254 switch(buf[i]){255 case '\004': /* ^D */256 if(console.nl == 0){257 qWrite(console.oq, "\n", 1);258 break;259 }260 /*FALLTHROUGH*/261 default:262 if(console.nl < Nl-1){263 qWrite(console.oq, &buf[i], 1);264 console.l[console.nl++] = buf[i];265 }266 continue;267 case '\b':268 if(console.nl != 0){269 qWrite(console.oq, &buf[i], 1);270 console.nl--;271 }272 continue;273 case '\n':274 qWrite(console.oq, &buf[i], 1);275 break;276 case '\025': /* ^U */277 qWrite(console.oq, "^U\n", 3);278 console.nl = 0;279 break;280 case '\027': /* ^W */281 console.l[console.nl] = '\0';282 wbuf = vtmalloc(console.nl+1);283 memmove(wbuf, console.l, console.nl+1);284 argc = tokenize(wbuf, argv, nelem(argv));285 if(argc > 0)286 argc--;287 console.nl = 0;288 lp = console.l;289 for(i = 0; i < argc; i++)290 lp += sprint(lp, "%q ", argv[i]);291 console.nl = lp - console.l;292 vtfree(wbuf);293 qWrite(console.oq, "^W\n", 3);294 if(console.nl == 0)295 break;296 qWrite(console.oq, console.l, console.nl);297 continue;298 case '\177':299 qWrite(console.oq, "\n", 1);300 console.nl = 0;301 break;302 }304 console.l[console.nl] = '\0';305 if(console.nl != 0)306 cliExec(console.l);308 console.nl = 0;309 qWrite(console.oq, console.prompt, console.np);310 }312 qlock(&q->lock);313 }314 }316 int317 consWrite(char* buf, int len)318 {319 if(console.oq == nil)320 return write(2, buf, len);321 if(console.nopens == 0)322 write(2, buf, len);323 return qWrite(console.oq, buf, len);324 }326 int327 consPrompt(char* prompt)328 {329 char buf[ERRMAX];331 if(prompt == nil)332 prompt = "prompt";334 vtfree(console.prompt);335 console.np = snprint(buf, sizeof(buf), "%s: ", prompt);336 console.prompt = vtstrdup(buf);338 return console.np;339 }341 int342 consTTY(void)343 {344 int ctl, fd;345 char *name, *p;347 name = "/dev/cons";348 if((fd = open(name, ORDWR)) < 0){349 #ifdef PLAN9PORT350 name = "/dev/tty";351 #else352 name = "#c/cons";353 #endif354 if((fd = open(name, ORDWR)) < 0){355 werrstr("consTTY: open %s: %r", name);356 return 0;357 }358 }360 #ifdef PLAN9PORT361 USED(p);362 ctl = 0;363 #else364 p = smprint("%sctl", name);365 if((ctl = open(p, OWRITE)) < 0){366 close(fd);367 werrstr("consTTY: open %s: %r", p);368 free(p);369 return 0;370 }371 if(write(ctl, "rawon", 5) < 0){372 close(ctl);373 close(fd);374 werrstr("consTTY: write %s: %r", p);375 free(p);376 return 0;377 }378 free(p);379 #endif381 if(consOpen(fd, fd, ctl) == 0){382 close(ctl);383 close(fd);384 return 0;385 }387 return 1;388 }390 int391 consInit(void)392 {393 console.iq = qAlloc();394 console.oq = qAlloc();395 console.nl = 0;397 consPrompt(nil);399 if(proccreate(consProc, nil, STACK) < 0){400 sysfatal("can't start console proc");401 return 0;402 }404 return 1;405 }