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