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 } 399