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