plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

Ccons.c (6722B)


      1 #include "stdinc.h"
      2 
      3 #include "9.h"
      4 
      5 enum {
      6 	Nl	= 256,			/* max. command line length */
      7 	Nq	= 8*1024,		/* amount of I/O buffered */
      8 };
      9 
     10 typedef struct Q {
     11 	QLock	lock;
     12 	Rendez	full;
     13 	Rendez	empty;
     14 
     15 	char	q[Nq];
     16 	int	n;
     17 	int	r;
     18 	int	w;
     19 } Q;
     20 
     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;
     31 
     32 char *currfsysname;
     33 
     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;
     40 
     41 	char*	prompt;
     42 	int	np;
     43 } console;
     44 
     45 static void
     46 consClose(Cons* cons)
     47 {
     48 	qlock(&cons->lock);
     49 	cons->closed = 1;
     50 
     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 	}
     62 
     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 }
     79 
     80 static void
     81 consIProc(void* v)
     82 {
     83 	Q *q;
     84 	Cons *cons;
     85 	int n, w;
     86 	char buf[Nq/4];
     87 
     88 	threadsetname("consI");
     89 
     90 	cons = v;
     91 	q = cons->iq;
     92 	for(;;){
     93 		/*
     94 		 * Can't tell the difference between zero-length read
     95 		 * 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 		else
    108 			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 }
    116 
    117 static void
    118 consOProc(void* v)
    119 {
    120 	Q *q;
    121 	Cons *cons;
    122 	char buf[Nq];
    123 	int lastn, n, r;
    124 
    125 	threadsetname("consO");
    126 
    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 		else
    142 			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 }
    152 
    153 int
    154 consOpen(int fd, int srvfd, int ctlfd)
    155 {
    156 	Cons *cons;
    157 
    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++;
    165 
    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);
    176 
    177 	if(ctlfd >= 0)
    178 		consIProc(cons);
    179 	else if(proccreate(consIProc, cons, STACK) < 0){
    180 		consClose(cons);
    181 		return 0;
    182 	}
    183 
    184 	return 1;
    185 }
    186 
    187 static int
    188 qWrite(Q* q, char* p, int n)
    189 {
    190 	int w;
    191 
    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);
    206 
    207 	return n;
    208 }
    209 
    210 static Q*
    211 qAlloc(void)
    212 {
    213 	Q *q;
    214 
    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;
    219 
    220 	return q;
    221 }
    222 
    223 static void
    224 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];
    231 
    232 	snprint(procname, sizeof procname, "cons %s", currfsysname);
    233 	threadsetname(procname);
    234 
    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 		else
    247 			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);
    252 
    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 			}
    303 
    304 			console.l[console.nl] = '\0';
    305 			if(console.nl != 0)
    306 				cliExec(console.l);
    307 
    308 			console.nl = 0;
    309 			qWrite(console.oq, console.prompt, console.np);
    310 		}
    311 
    312 		qlock(&q->lock);
    313 	}
    314 }
    315 
    316 int
    317 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 }
    325 
    326 int
    327 consPrompt(char* prompt)
    328 {
    329 	char buf[ERRMAX];
    330 
    331 	if(prompt == nil)
    332 		prompt = "prompt";
    333 
    334 	vtfree(console.prompt);
    335 	console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
    336 	console.prompt = vtstrdup(buf);
    337 
    338 	return console.np;
    339 }
    340 
    341 int
    342 consTTY(void)
    343 {
    344 	int ctl, fd;
    345 	char *name, *p;
    346 
    347 	name = "/dev/cons";
    348 	if((fd = open(name, ORDWR)) < 0){
    349 #ifdef PLAN9PORT
    350 		name = "/dev/tty";
    351 #else
    352 		name = "#c/cons";
    353 #endif
    354 		if((fd = open(name, ORDWR)) < 0){
    355 			werrstr("consTTY: open %s: %r", name);
    356 			return 0;
    357 		}
    358 	}
    359 
    360 #ifdef PLAN9PORT
    361 	USED(p);
    362 	ctl = 0;
    363 #else
    364 	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 #endif
    380 
    381 	if(consOpen(fd, fd, ctl) == 0){
    382 		close(ctl);
    383 		close(fd);
    384 		return 0;
    385 	}
    386 
    387 	return 1;
    388 }
    389 
    390 int
    391 consInit(void)
    392 {
    393 	console.iq = qAlloc();
    394 	console.oq = qAlloc();
    395 	console.nl = 0;
    396 
    397 	consPrompt(nil);
    398 
    399 	if(proccreate(consProc, nil, STACK) < 0){
    400 		sysfatal("can't start console proc");
    401 		return 0;
    402 	}
    403 
    404 	return 1;
    405 }