Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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