123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "stdinc.h"
- #include "9.h"
- enum {
- Nl = 256, /* max. command line length */
- Nq = 8*1024, /* amount of I/O buffered */
- };
- typedef struct Q {
- VtLock* lock;
- VtRendez* full;
- VtRendez* empty;
- char q[Nq];
- int n;
- int r;
- int w;
- } Q;
- typedef struct Cons {
- VtLock* lock;
- int ref;
- int closed;
- int fd;
- int srvfd;
- int ctlfd;
- Q* iq; /* points to console.iq */
- Q* oq; /* points to console.oq */
- } Cons;
- char *currfsysname;
- static struct {
- Q* iq; /* input */
- Q* oq; /* output */
- char l[Nl]; /* command line assembly */
- int nl; /* current line length */
- int nopens;
- char* prompt;
- int np;
- } console;
- static void
- consClose(Cons* cons)
- {
- vtLock(cons->lock);
- cons->closed = 1;
- cons->ref--;
- if(cons->ref > 0){
- vtLock(cons->iq->lock);
- vtWakeup(cons->iq->full);
- vtUnlock(cons->iq->lock);
- vtLock(cons->oq->lock);
- vtWakeup(cons->oq->empty);
- vtUnlock(cons->oq->lock);
- vtUnlock(cons->lock);
- return;
- }
- if(cons->ctlfd != -1){
- close(cons->ctlfd);
- cons->srvfd = -1;
- }
- if(cons->srvfd != -1){
- close(cons->srvfd);
- cons->srvfd = -1;
- }
- if(cons->fd != -1){
- close(cons->fd);
- cons->fd = -1;
- }
- vtUnlock(cons->lock);
- vtLockFree(cons->lock);
- vtMemFree(cons);
- console.nopens--;
- }
- static void
- consIProc(void* v)
- {
- Q *q;
- Cons *cons;
- int n, w;
- char buf[Nq/4];
- vtThreadSetName("consI");
- cons = v;
- q = cons->iq;
- for(;;){
- /*
- * Can't tell the difference between zero-length read
- * and eof, so keep calling read until we get an error.
- */
- if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0)
- break;
- vtLock(q->lock);
- while(Nq - q->n < n && !cons->closed)
- vtSleep(q->full);
- w = Nq - q->w;
- if(w < n){
- memmove(&q->q[q->w], buf, w);
- memmove(&q->q[0], buf + w, n - w);
- }
- else
- memmove(&q->q[q->w], buf, n);
- q->w = (q->w + n) % Nq;
- q->n += n;
- vtWakeup(q->empty);
- vtUnlock(q->lock);
- }
- consClose(cons);
- }
- static void
- consOProc(void* v)
- {
- Q *q;
- Cons *cons;
- char buf[Nq];
- int lastn, n, r;
- vtThreadSetName("consO");
- cons = v;
- q = cons->oq;
- vtLock(q->lock);
- lastn = 0;
- for(;;){
- while(lastn == q->n && !cons->closed)
- vtSleep(q->empty);
- if((n = q->n - lastn) > Nq)
- n = Nq;
- if(n > q->w){
- r = n - q->w;
- memmove(buf, &q->q[Nq - r], r);
- memmove(buf+r, &q->q[0], n - r);
- }
- else
- memmove(buf, &q->q[q->w - n], n);
- lastn = q->n;
- vtUnlock(q->lock);
- if(cons->closed || write(cons->fd, buf, n) < 0)
- break;
- vtLock(q->lock);
- vtWakeup(q->empty);
- }
- consClose(cons);
- }
- int
- consOpen(int fd, int srvfd, int ctlfd)
- {
- Cons *cons;
- cons = vtMemAllocZ(sizeof(Cons));
- cons->lock = vtLockAlloc();
- cons->fd = fd;
- cons->srvfd = srvfd;
- cons->ctlfd = ctlfd;
- cons->iq = console.iq;
- cons->oq = console.oq;
- console.nopens++;
- vtLock(cons->lock);
- cons->ref = 2;
- cons->closed = 0;
- if(vtThread(consOProc, cons) < 0){
- cons->ref--;
- vtUnlock(cons->lock);
- consClose(cons);
- return 0;
- }
- vtUnlock(cons->lock);
- if(ctlfd >= 0)
- consIProc(cons);
- else if(vtThread(consIProc, cons) < 0){
- consClose(cons);
- return 0;
- }
- return 1;
- }
- static int
- qWrite(Q* q, char* p, int n)
- {
- int w;
- vtLock(q->lock);
- if(n > Nq - q->w){
- w = Nq - q->w;
- memmove(&q->q[q->w], p, w);
- memmove(&q->q[0], p + w, n - w);
- q->w = n - w;
- }
- else{
- memmove(&q->q[q->w], p, n);
- q->w += n;
- }
- q->n += n;
- vtWakeup(q->empty);
- vtUnlock(q->lock);
- return n;
- }
- static Q*
- qAlloc(void)
- {
- Q *q;
- q = vtMemAllocZ(sizeof(Q));
- q->lock = vtLockAlloc();
- q->full = vtRendezAlloc(q->lock);
- q->empty = vtRendezAlloc(q->lock);
- q->n = q->r = q->w = 0;
- return q;
- }
- static void
- consProc(void *v)
- {
- Q *q;
- int argc, i, n, r;
- char *argv[20], buf[Nq], *lp, *wbuf;
- char procname[64];
- snprint(procname, sizeof procname, "cons %s", currfsysname);
- vtThreadSetName(procname);
- q = console.iq;
- qWrite(console.oq, console.prompt, console.np);
- vtLock(q->lock);
- for(;;){
- while((n = q->n) == 0)
- vtSleep(q->empty);
- r = Nq - q->r;
- if(r < n){
- memmove(buf, &q->q[q->r], r);
- memmove(buf + r, &q->q[0], n - r);
- }
- else
- memmove(buf, &q->q[q->r], n);
- q->r = (q->r + n) % Nq;
- q->n -= n;
- vtWakeup(q->full);
- vtUnlock(q->lock);
- for(i = 0; i < n; i++){
- switch(buf[i]){
- case '\004': /* ^D */
- if(console.nl == 0){
- qWrite(console.oq, "\n", 1);
- break;
- }
- /*FALLTHROUGH*/
- default:
- if(console.nl < Nl-1){
- qWrite(console.oq, &buf[i], 1);
- console.l[console.nl++] = buf[i];
- }
- continue;
- case '\b':
- if(console.nl != 0){
- qWrite(console.oq, &buf[i], 1);
- console.nl--;
- }
- continue;
- case '\n':
- qWrite(console.oq, &buf[i], 1);
- break;
- case '\025': /* ^U */
- qWrite(console.oq, "^U\n", 3);
- console.nl = 0;
- break;
- case '\027': /* ^W */
- console.l[console.nl] = '\0';
- wbuf = vtMemAlloc(console.nl+1);
- memmove(wbuf, console.l, console.nl+1);
- argc = tokenize(wbuf, argv, nelem(argv));
- if(argc > 0)
- argc--;
- console.nl = 0;
- lp = console.l;
- for(i = 0; i < argc; i++)
- lp += sprint(lp, "%q ", argv[i]);
- console.nl = lp - console.l;
- vtMemFree(wbuf);
- qWrite(console.oq, "^W\n", 3);
- if(console.nl == 0)
- break;
- qWrite(console.oq, console.l, console.nl);
- continue;
- case '\177':
- qWrite(console.oq, "\n", 1);
- console.nl = 0;
- break;
- }
- console.l[console.nl] = '\0';
- if(console.nl != 0)
- cliExec(console.l);
- console.nl = 0;
- qWrite(console.oq, console.prompt, console.np);
- }
- vtLock(q->lock);
- }
- }
- int
- consWrite(char* buf, int len)
- {
- if(console.oq == nil)
- return write(2, buf, len);
- if(console.nopens == 0)
- write(2, buf, len);
- return qWrite(console.oq, buf, len);
- }
- int
- consPrompt(char* prompt)
- {
- char buf[ERRMAX];
- if(prompt == nil)
- prompt = "prompt";
- vtMemFree(console.prompt);
- console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
- console.prompt = vtStrDup(buf);
- return console.np;
- }
- int
- consTTY(void)
- {
- int ctl, fd;
- char *name, *p;
- name = "/dev/cons";
- if((fd = open(name, ORDWR)) < 0){
- name = "#c/cons";
- if((fd = open(name, ORDWR)) < 0){
- vtSetError("consTTY: open %s: %r", name);
- return 0;
- }
- }
- p = smprint("%sctl", name);
- if((ctl = open(p, OWRITE)) < 0){
- close(fd);
- vtSetError("consTTY: open %s: %r", p);
- free(p);
- return 0;
- }
- if(write(ctl, "rawon", 5) < 0){
- close(ctl);
- close(fd);
- vtSetError("consTTY: write %s: %r", p);
- free(p);
- return 0;
- }
- free(p);
- if(consOpen(fd, fd, ctl) == 0){
- close(ctl);
- close(fd);
- return 0;
- }
- return 1;
- }
- int
- consInit(void)
- {
- console.iq = qAlloc();
- console.oq = qAlloc();
- console.nl = 0;
- consPrompt(nil);
- if(vtThread(consProc, nil) < 0){
- vtFatal("can't start console proc");
- return 0;
- }
- return 1;
- }
|