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
consClose(Cons * cons)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
consIProc(void * v)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
consOProc(void * v)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
consOpen(int fd,int srvfd,int ctlfd)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
qWrite(Q * q,char * p,int n)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*
qAlloc(void)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
consProc(void *)224 consProc(void*)
225 {
226 Q *q;
227 int argc, i, n, r;
228 char *argv[20], buf[Nq], *lp, *wbuf;
229 char procname[64];
230
231 snprint(procname, sizeof procname, "cons %s", currfsysname);
232 threadsetname(procname);
233
234 q = console.iq;
235 qWrite(console.oq, console.prompt, console.np);
236 qlock(&q->lock);
237 for(;;){
238 while((n = q->n) == 0)
239 rsleep(&q->empty);
240 r = Nq - q->r;
241 if(r < n){
242 memmove(buf, &q->q[q->r], r);
243 memmove(buf + r, &q->q[0], n - r);
244 }
245 else
246 memmove(buf, &q->q[q->r], n);
247 q->r = (q->r + n) % Nq;
248 q->n -= n;
249 rwakeup(&q->full);
250 qunlock(&q->lock);
251
252 for(i = 0; i < n; i++){
253 switch(buf[i]){
254 case '\004': /* ^D */
255 if(console.nl == 0){
256 qWrite(console.oq, "\n", 1);
257 break;
258 }
259 /*FALLTHROUGH*/
260 default:
261 if(console.nl < Nl-1){
262 qWrite(console.oq, &buf[i], 1);
263 console.l[console.nl++] = buf[i];
264 }
265 continue;
266 case '\b':
267 if(console.nl != 0){
268 qWrite(console.oq, &buf[i], 1);
269 console.nl--;
270 }
271 continue;
272 case '\n':
273 qWrite(console.oq, &buf[i], 1);
274 break;
275 case '\025': /* ^U */
276 qWrite(console.oq, "^U\n", 3);
277 console.nl = 0;
278 break;
279 case '\027': /* ^W */
280 console.l[console.nl] = '\0';
281 wbuf = vtmalloc(console.nl+1);
282 memmove(wbuf, console.l, console.nl+1);
283 argc = tokenize(wbuf, argv, nelem(argv));
284 if(argc > 0)
285 argc--;
286 console.nl = 0;
287 lp = console.l;
288 for(i = 0; i < argc; i++)
289 lp += sprint(lp, "%q ", argv[i]);
290 console.nl = lp - console.l;
291 vtfree(wbuf);
292 qWrite(console.oq, "^W\n", 3);
293 if(console.nl == 0)
294 break;
295 qWrite(console.oq, console.l, console.nl);
296 continue;
297 case '\177':
298 qWrite(console.oq, "\n", 1);
299 console.nl = 0;
300 break;
301 }
302
303 console.l[console.nl] = '\0';
304 if(console.nl != 0)
305 cliExec(console.l);
306
307 console.nl = 0;
308 qWrite(console.oq, console.prompt, console.np);
309 }
310
311 qlock(&q->lock);
312 }
313 }
314
315 int
consWrite(char * buf,int len)316 consWrite(char* buf, int len)
317 {
318 if(console.oq == nil)
319 return write(2, buf, len);
320 if(console.nopens == 0)
321 write(2, buf, len);
322 return qWrite(console.oq, buf, len);
323 }
324
325 int
consPrompt(char * prompt)326 consPrompt(char* prompt)
327 {
328 char buf[ERRMAX];
329
330 if(prompt == nil)
331 prompt = "prompt";
332
333 vtfree(console.prompt);
334 console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
335 console.prompt = vtstrdup(buf);
336
337 return console.np;
338 }
339
340 int
consTTY(void)341 consTTY(void)
342 {
343 int ctl, fd;
344 char *name, *p;
345
346 name = "/dev/cons";
347 if((fd = open(name, ORDWR)) < 0){
348 name = "#c/cons";
349 if((fd = open(name, ORDWR)) < 0){
350 werrstr("consTTY: open %s: %r", name);
351 return 0;
352 }
353 }
354
355 p = smprint("%sctl", name);
356 if((ctl = open(p, OWRITE)) < 0){
357 close(fd);
358 werrstr("consTTY: open %s: %r", p);
359 free(p);
360 return 0;
361 }
362 if(write(ctl, "rawon", 5) < 0){
363 close(ctl);
364 close(fd);
365 werrstr("consTTY: write %s: %r", p);
366 free(p);
367 return 0;
368 }
369 free(p);
370
371 if(consOpen(fd, fd, ctl) == 0){
372 close(ctl);
373 close(fd);
374 return 0;
375 }
376
377 return 1;
378 }
379
380 int
consInit(void)381 consInit(void)
382 {
383 console.iq = qAlloc();
384 console.oq = qAlloc();
385 console.nl = 0;
386
387 consPrompt(nil);
388
389 if(proccreate(consProc, nil, STACK) < 0){
390 sysfatal("can't start console proc");
391 return 0;
392 }
393
394 return 1;
395 }
396