1 #include "all.h" 2 3 static Command command[100]; 4 static Flag flag[35]; 5 static char statsdef[20]; /* default stats list */ 6 static int whoflag; 7 8 static void consserve1(void *); 9 static void installcmds(void); 10 11 void 12 consserve(void) 13 { 14 int i; 15 16 strncpy(cons.chan->whochan, "console", sizeof(cons.chan->whochan)); 17 installcmds(); 18 con_session(); 19 cmd_exec("cfs"); 20 cmd_exec("users"); 21 cmd_exec("version"); 22 23 for(i = 0; command[i].arg0; i++) 24 if(strcmp("cwcmd", command[i].arg0) == 0){ 25 cmd_exec("cwcmd touchsb"); 26 break; 27 } 28 29 newproc(consserve1, 0, "con"); 30 } 31 32 /* console commands process */ 33 static void 34 consserve1(void *) 35 { 36 char *conline; 37 38 for (;;) { 39 /* conslock(); */ 40 do { 41 print("%s: ", service); 42 if ((conline = Brdline(&bin, '\n')) == nil) 43 print("\n"); 44 else { 45 conline[Blinelen(&bin)-1] = '\0'; 46 cmd_exec(conline); 47 } 48 } while (conline != nil); 49 } 50 } 51 52 static int 53 cmdcmp(void *va, void *vb) 54 { 55 Command *a, *b; 56 57 a = va; 58 b = vb; 59 return strcmp(a->arg0, b->arg0); 60 } 61 62 void 63 cmd_install(char *arg0, char *help, void (*func)(int, char*[])) 64 { 65 int i; 66 67 qlock(&cons); 68 for(i=0; command[i].arg0; i++) 69 ; 70 if(i >= nelem(command)-2) { 71 qunlock(&cons); 72 print("cmd_install: too many commands\n"); 73 return; 74 } 75 command[i+1].arg0 = 0; 76 command[i].help = help; 77 command[i].func = func; 78 command[i].arg0 = arg0; 79 qsort(command, i+1, sizeof(Command), cmdcmp); 80 qunlock(&cons); 81 } 82 83 void 84 cmd_exec(char *arg) 85 { 86 char line[2*Maxword], *s; 87 char *argv[10]; 88 int argc, i, c; 89 90 if(strlen(arg) >= nelem(line)-2) { 91 print("cmd_exec: line too long\n"); 92 return; 93 } 94 strcpy(line, arg); 95 96 argc = 0; 97 s = line; 98 c = *s++; 99 for(;;) { 100 while(isascii(c) && isspace(c)) 101 c = *s++; 102 if(c == 0) 103 break; 104 if(argc >= nelem(argv)-2) { 105 print("cmd_exec: too many args\n"); 106 return; 107 } 108 argv[argc++] = s-1; 109 while((!isascii(c) || !isspace(c)) && c != '\0') 110 c = *s++; 111 s[-1] = 0; 112 } 113 if(argc <= 0) 114 return; 115 for(i=0; s=command[i].arg0; i++) 116 if(strcmp(argv[0], s) == 0) { 117 (*command[i].func)(argc, argv); 118 prflush(); 119 return; 120 } 121 print("cmd_exec: unknown command: %s\n", argv[0]); 122 } 123 124 static void 125 cmd_halt(int, char *[]) 126 { 127 wlock(&mainlock); /* halt */ 128 sync("halt"); 129 exit(); 130 } 131 132 static void 133 cmd_duallow(int argc, char *argv[]) 134 { 135 int uid; 136 137 if(argc <= 1) { 138 duallow = 0; 139 return; 140 } 141 142 uid = strtouid(argv[1]); 143 if(uid < 0) 144 uid = number(argv[1], -2, 10); 145 if(uid < 0) { 146 print("bad uid %s\n", argv[1]); 147 return; 148 } 149 duallow = uid; 150 } 151 152 static void 153 cmd_stats(int argc, char *argv[]) 154 { 155 int i, c; 156 char buf[30], *s, *p, *q; 157 158 if(argc <= 1) { 159 if(statsdef[0] == 0) 160 strcpy(statsdef, "a"); 161 sprint(buf, "stats s%s", statsdef); 162 cmd_exec(buf); 163 return; 164 } 165 166 strcpy(buf, "stat"); 167 p = strchr(buf, 0); 168 p[1] = 0; 169 170 q = 0; 171 for(i = 1; i < argc; i++) 172 for(s = argv[i]; c = *s; s++) { 173 if(c == 's') 174 continue; 175 if(c == '-') { 176 q = statsdef; 177 continue; 178 } 179 if(q) { 180 *q++ = c; 181 *q = 0; 182 } 183 *p = c; 184 cmd_exec(buf); 185 } 186 } 187 188 static void 189 cmd_stata(int, char *[]) 190 { 191 int i; 192 193 print("cons stats\n"); 194 // print("\twork =%7W%7W%7W rps\n", cons.work+0, cons.work+1, cons.work+2); 195 // print("\trate =%7W%7W%7W tBps\n", cons.rate+0, cons.rate+1, cons.rate+2); 196 // print("\thits =%7W%7W%7W iops\n", cons.bhit+0, cons.bhit+1, cons.bhit+2); 197 // print("\tread =%7W%7W%7W iops\n", cons.bread+0, cons.bread+1, cons.bread+2); 198 // print("\trah =%7W%7W%7W iops\n", cons.brahead+0, cons.brahead+1, cons.brahead+2); 199 // print("\tinit =%7W%7W%7W iops\n", cons.binit+0, cons.binit+1, cons.binit+2); 200 print("\tbufs = %3ld sm %3ld lg %ld res\n", 201 cons.nsmall, cons.nlarge, cons.nreseq); 202 203 for(i=0; i<nelem(mballocs); i++) 204 if(mballocs[i]) 205 print("\t[%d]=%d\n", i, mballocs[i]); 206 207 print("\tioerr= %3ld wr %3ld ww %3ld dr %3ld dw\n", 208 cons.nwormre, cons.nwormwe, cons.nwrenre, cons.nwrenwe); 209 print("\tcache= %9ld hit %9ld miss\n", 210 cons.nwormhit, cons.nwormmiss); 211 } 212 213 static int 214 flagcmp(void *va, void *vb) 215 { 216 Flag *a, *b; 217 218 a = va; 219 b = vb; 220 return strcmp(a->arg0, b->arg0); 221 } 222 223 ulong 224 flag_install(char *arg, char *help) 225 { 226 int i; 227 228 qlock(&cons); 229 for(i=0; flag[i].arg0; i++) 230 ; 231 if(i >= 32) { 232 qunlock(&cons); 233 print("flag_install: too many flags\n"); 234 return 0; 235 } 236 flag[i+1].arg0 = 0; 237 flag[i].arg0 = arg; 238 flag[i].help = help; 239 flag[i].flag = 1<<i; 240 qsort(flag, i+1, sizeof(Flag), flagcmp); 241 qunlock(&cons); 242 return 1<<i; 243 } 244 245 void 246 cmd_flag(int argc, char *argv[]) 247 { 248 int f, n, i, j; 249 char *s; 250 Chan *cp; 251 252 if(argc <= 1) { 253 for(i=0; flag[i].arg0; i++) 254 print("%.4lux %s %s\n", 255 flag[i].flag, flag[i].arg0, flag[i].help); 256 if(cons.flags) 257 print("flag[*] = %.4lux\n", cons.flags); 258 for(cp = chans; cp; cp = cp->next) 259 if(cp->flags) 260 print("flag[%3d] = %.4lux\n", cp->chan, cp->flags); 261 return; 262 } 263 264 f = 0; 265 n = -1; 266 for(i=1; i<argc; i++) { 267 for(j=0; s=flag[j].arg0; j++) 268 if(strcmp(s, argv[i]) == 0) 269 goto found; 270 j = number(argv[i], -1, 10); 271 if(j < 0) { 272 print("bad flag argument: %s\n", argv[i]); 273 continue; 274 } 275 n = j; 276 continue; 277 found: 278 f |= flag[j].flag; 279 } 280 281 if(n < 0) { 282 cons.flags ^= f; 283 if(f == 0) 284 cons.flags = 0; 285 print("flag = %.8lux\n", cons.flags); 286 return; 287 } 288 for(cp = chans; cp; cp = cp->next) 289 if(cp->chan == n) { 290 cp->flags ^= f; 291 if(f == 0) 292 cp->flags = 0; 293 print("flag[%3d] = %.8lux\n", cp->chan, cp->flags); 294 return; 295 } 296 print("no such channel\n"); 297 } 298 299 static void 300 cmd_who(int argc, char *argv[]) 301 { 302 Chan *cp; 303 int i, c; 304 305 c = 0; 306 for(cp = chans; cp; cp = cp->next) { 307 if(cp->whotime == 0 && !(cons.flags & whoflag)) { 308 c++; 309 continue; 310 } 311 if(argc > 1) { 312 for(i=1; i<argc; i++) 313 if(strcmp(argv[i], cp->whoname) == 0) 314 break; 315 if(i >= argc) { 316 c++; 317 continue; 318 } 319 } 320 print("%3d: %10s %24s", cp->chan, 321 cp->whoname? cp->whoname: "<nowhoname>", cp->whochan); 322 if(cp->whoprint) 323 cp->whoprint(cp); 324 print("\n"); 325 prflush(); 326 } 327 if(c > 0) 328 print("%d chans not listed\n", c); 329 } 330 331 static void 332 cmd_hangup(int argc, char *argv[]) 333 { 334 Chan *cp; 335 int n; 336 337 if(argc < 2) { 338 print("usage: hangup chan-number\n"); 339 return; 340 } 341 n = number(argv[1], -1, 10); 342 for(cp = chans; cp; cp = cp->next) { 343 if(cp->whotime == 0) { 344 if(cp->chan == n) 345 print("that chan is hung up\n"); 346 continue; 347 } 348 if(cp->chan == n) { 349 /* need more than just fileinit with tcp */ 350 chanhangup(cp, "console command", 1); 351 fileinit(cp); 352 } 353 } 354 } 355 356 static void 357 cmd_sync(int, char *[]) 358 { 359 wlock(&mainlock); /* sync */ 360 sync("command"); 361 wunlock(&mainlock); 362 print("\n"); 363 } 364 365 static void 366 cmd_help(int argc, char *argv[]) 367 { 368 char *arg; 369 int i, j; 370 371 for(i=0; arg=command[i].arg0; i++) { 372 if(argc > 1) { 373 for(j=1; j<argc; j++) 374 if(strcmp(argv[j], arg) == 0) 375 goto found; 376 continue; 377 } 378 found: 379 print("\t%s %s\n", arg, command[i].help); 380 prflush(); 381 } 382 } 383 384 void 385 cmd_fstat(int argc, char *argv[]) 386 { 387 int i; 388 389 for(i=1; i<argc; i++) { 390 if(walkto(argv[i])) { 391 print("cant stat %s\n", argv[i]); 392 continue; 393 } 394 con_fstat(FID2); 395 } 396 } 397 398 void 399 cmd_create(int argc, char *argv[]) 400 { 401 int uid, gid; 402 long perm; 403 char elem[NAMELEN], *p; 404 405 if(argc < 5) { 406 print("usage: create path uid gid mode [lad]\n"); 407 return; 408 } 409 410 p = utfrrune(argv[1], '/'); 411 if(p) { 412 *p++ = 0; 413 if(walkto(argv[1])) { 414 print("create failed in walkto: %s\n", p); 415 return; 416 } 417 } else { 418 if(walkto("/")) 419 return; 420 p = argv[1]; 421 } 422 if(strlen(p) >= NAMELEN) { 423 print("name too long %s\n", p); 424 return; 425 } 426 427 memset(elem, 0, sizeof(elem)); 428 strcpy(elem, p); 429 430 uid = strtouid(argv[2]); 431 if(uid < -1) 432 uid = number(argv[2], -2, 10); 433 if(uid < -1) { 434 print("bad uid %s\n", argv[2]); 435 return; 436 } 437 438 gid = strtouid(argv[3]); 439 if(gid < -1) 440 gid = number(argv[3], -2, 10); 441 if(gid < -1) { 442 print("bad gid %s\n", argv[3]); 443 return; 444 } 445 446 perm = number(argv[4], 0777, 8) & 0777; 447 448 if(argc > 5) { 449 if(strchr(argv[5], 'l')) 450 perm |= PLOCK; 451 if(strchr(argv[5], 'a')) 452 perm |= PAPND; 453 if(strchr(argv[5], 'd')) 454 perm |= PDIR; 455 } 456 457 if(con_create(FID2, elem, uid, gid, perm, 0)) 458 print("create failed: %s/%s\n", argv[1], p); 459 } 460 461 static void 462 cmd_clri(int argc, char *argv[]) 463 { 464 int i; 465 466 for(i=1; i<argc; i++) { 467 if(walkto(argv[i])) { 468 print("cant remove %s\n", argv[i]); 469 continue; 470 } 471 con_clri(FID2); 472 } 473 } 474 475 static void 476 cmd_allow(int, char**) 477 { 478 wstatallow = writeallow = 1; 479 } 480 481 static void 482 cmd_disallow(int, char**) 483 { 484 wstatallow = writeallow = 0; 485 } 486 487 void 488 ckblock(Device *d, Off a, int typ, Off qpath) 489 { 490 Iobuf *p; 491 492 if(a) { 493 p = getbuf(d, a, Brd); 494 if(p) { 495 checktag(p, typ, qpath); 496 putbuf(p); 497 } 498 } 499 } 500 501 void 502 doclean(Iobuf *p, Dentry *d, int n, Off a) 503 { 504 int i, mod, typ; 505 Off qpath; 506 507 mod = 0; 508 qpath = d->qid.path; 509 typ = Tfile; 510 if(d->mode & DDIR) 511 typ = Tdir; 512 for(i=0; i<NDBLOCK; i++) { 513 print("dblock[%d] = %lld\n", i, (Wideoff)d->dblock[i]); 514 ckblock(p->dev, d->dblock[i], typ, qpath); 515 if(i == n) { 516 d->dblock[i] = a; 517 mod = 1; 518 print("dblock[%d] modified %lld\n", i, (Wideoff)a); 519 } 520 } 521 522 /* add NDBLOCK so user can cite block address by index */ 523 for (i = 0; i < NIBLOCK; i++) { 524 print("iblocks[%d] = %lld\n", NDBLOCK+i, (Wideoff)d->iblocks[i]); 525 ckblock(p->dev, d->iblocks[i], Tind1+i, qpath); 526 if(NDBLOCK+i == n) { 527 d->iblocks[i] = a; 528 mod = 1; 529 print("iblocks[%d] modified %lld\n", NDBLOCK+i, (Wideoff)a); 530 } 531 } 532 533 if(mod) 534 p->flags |= Bmod|Bimm; 535 } 536 537 static void 538 cmd_clean(int argc, char *argv[]) 539 { 540 int n; 541 Off a; 542 Iobuf *p; 543 Dentry *d; 544 File *f; 545 546 p = 0; 547 f = 0; 548 while(argc > 1) { 549 n = -1; 550 if(argc > 2) 551 n = number(argv[2], -1, 10); 552 a = 0; 553 if(argc > 3) 554 a = number(argv[3], 0, 10); 555 if(walkto(argv[1])) { 556 print("cant remove %s\n", argv[1]); 557 break; 558 } 559 f = filep(cons.chan, FID2, 0); 560 if(!f) 561 break; 562 if(n >= 0 && f->fs->dev->type == Devro) { 563 print("readonly %s\n", argv[1]); 564 break; 565 } 566 p = getbuf(f->fs->dev, f->addr, Brd); 567 d = getdir(p, f->slot); 568 if(!d || !(d->mode & DALLOC)) { 569 print("not alloc %s\n", argv[1]); 570 break; 571 } 572 doclean(p, d, n, a); 573 break; 574 } 575 if(f) 576 qunlock(f); 577 if(p) 578 putbuf(p); 579 } 580 581 static void 582 cmd_remove(int argc, char *argv[]) 583 { 584 int i; 585 586 for(i=1; i<argc; i++) { 587 if(walkto(argv[i])) { 588 print("cant remove %s\n", argv[i]); 589 continue; 590 } 591 con_remove(FID2); 592 } 593 } 594 595 static void 596 cmd_version(int, char *[]) 597 { 598 print("%d-bit %s as of %T\n", sizeof(Off)*8 - 1, service, fs_mktime); 599 print("\tlast boot %T\n", boottime); 600 } 601 602 static void 603 cmd_cfs(int argc, char *argv[]) 604 { 605 Filsys *fs; 606 char *name; 607 608 name = "main"; 609 if(argc > 1) 610 name = argv[1]; 611 fs = fsstr(name); 612 if(fs == 0) { 613 print("%s: unknown file system\n", name); 614 if(cons.curfs) 615 return; 616 fs = &filsys[0]; 617 } 618 if(con_attach(FID1, "adm", fs->name)) 619 panic("FID1 attach to root"); 620 cons.curfs = fs; 621 print("current fs is \"%s\"\n", cons.curfs->name); 622 } 623 624 static void 625 cmd_prof(int argc, char *argv[]) 626 { 627 int n; 628 long m, o; 629 char *p; 630 631 if(cons.profbuf == 0) { 632 print("no buffer\n"); 633 return; 634 } 635 n = !cons.profile; 636 if(argc > 1) 637 n = number(argv[1], n, 10); 638 if(n && !cons.profile) { 639 print("clr and start\n"); 640 memset(cons.profbuf, 0, cons.nprofbuf*sizeof(cons.profbuf[0])); 641 cons.profile = 1; 642 return; 643 } 644 if(!n && cons.profile) { 645 cons.profile = 0; 646 print("stop and write\n"); 647 if(walkto("/adm/kprofdata")) 648 goto bad; 649 if(con_open(FID2, OWRITE|OTRUNC)) { 650 bad: 651 print("cant open /adm/kprofdata\n"); 652 return; 653 } 654 p = (char*)cons.profbuf; 655 for(m=0; m<cons.nprofbuf; m++) { 656 n = cons.profbuf[m]; 657 p[0] = n>>24; 658 p[1] = n>>16; 659 p[2] = n>>8; 660 p[3] = n>>0; 661 p += 4; 662 } 663 664 m = cons.nprofbuf*sizeof(cons.profbuf[0]); 665 o = 0; 666 while(m > 0) { 667 n = 8192; 668 if(n > m) 669 n = m; 670 con_write(FID2, (char*)cons.profbuf+o, o, n); 671 m -= n; 672 o += n; 673 } 674 return; 675 } 676 } 677 678 static void 679 cmd_time(int argc, char *argv[]) 680 { 681 int i, len; 682 char *cmd; 683 Timet t1, t2; 684 685 t1 = time(nil); 686 len = 0; 687 for(i=1; i<argc; i++) 688 len += 1 + strlen(argv[i]); 689 cmd = malloc(len + 1); 690 cmd[0] = 0; 691 for(i=1; i<argc; i++) { 692 strcat(cmd, " "); 693 strcat(cmd, argv[i]); 694 } 695 cmd_exec(cmd); 696 t2 = time(nil); 697 free(cmd); 698 print("time = %ld ms\n", TK2MS(t2-t1)); 699 } 700 701 void 702 cmd_noattach(int, char *[]) 703 { 704 noattach = !noattach; 705 if(noattach) 706 print("attaches are DISABLED\n"); 707 } 708 709 void 710 cmd_files(int, char *[]) 711 { 712 long i, n; 713 Chan *cp; 714 715 for(cp = chans; cp; cp = cp->next) 716 cp->nfile = 0; 717 718 lock(&flock); 719 n = 0; 720 for(i=0; i<conf.nfile; i++) 721 if(files[i].cp) { 722 n++; 723 files[i].cp->nfile++; 724 } 725 print("%ld out of %ld files used\n", n, conf.nfile); 726 unlock(&flock); 727 728 n = 0; 729 for(cp = chans; cp; cp = cp->next) 730 if(cp->nfile) { 731 print("%3d: %5d\n", cp->chan, cp->nfile); 732 prflush(); 733 n += cp->nfile; 734 } 735 print("%ld out of %ld files used\n", n, conf.nfile); 736 } 737 738 static void 739 installcmds(void) 740 { 741 cmd_install("allow", "-- disable permission checking", cmd_allow); 742 cmd_install("cfs", "[file] -- set current filesystem", cmd_cfs); 743 cmd_install("clean", "file [bno [addr]] -- block print/fix", cmd_clean); 744 cmd_install("check", "[options]", cmd_check); 745 cmd_install("clri", "[file ...] -- purge files/dirs", cmd_clri); 746 cmd_install("create", "path uid gid perm [lad] -- make a file/dir", cmd_create); 747 cmd_install("disallow", "-- enable permission checking", cmd_disallow); 748 cmd_install("duallow", "uid -- duallow", cmd_duallow); 749 cmd_install("flag", "-- print set flags", cmd_flag); 750 cmd_install("fstat", "path -- print info on a file/dir", cmd_fstat); 751 cmd_install("halt", "-- return to boot rom", cmd_halt); 752 cmd_install("help", "", cmd_help); 753 cmd_install("newuser", "username -- add user to /adm/users", cmd_newuser); 754 cmd_install("profile", "[01] -- fs profile", cmd_prof); 755 cmd_install("remove", "[file ...] -- remove files/dirs", cmd_remove); 756 cmd_install("stata", "-- overall stats", cmd_stata); 757 cmd_install("stats", "[[-]flags ...] -- various stats", cmd_stats); 758 cmd_install("sync", "", cmd_sync); 759 cmd_install("time", "command -- time another command", cmd_time); 760 cmd_install("users", "[file] -- read /adm/users", cmd_users); 761 cmd_install("version", "-- print time of mk and boot", cmd_version); 762 cmd_install("who", "[user ...] -- print attaches", cmd_who); 763 cmd_install("hangup", "chan -- clunk files", cmd_hangup); 764 cmd_install("printconf", "-- print configuration", cmd_printconf); 765 cmd_install("noattach", "toggle noattach flag", cmd_noattach); 766 cmd_install("files", "report on files structure", cmd_files); 767 768 attachflag = flag_install("attach", "-- attach calls"); 769 chatflag = flag_install("chat", "-- verbose"); 770 errorflag = flag_install("error", "-- on errors"); 771 whoflag = flag_install("allchans", "-- on who"); 772 authdebugflag = flag_install("authdebug", "-- report authentications"); 773 authdisableflag = flag_install("authdisable", "-- disable authentication"); 774 } 775 776 int 777 walkto(char *name) 778 { 779 char elem[NAMELEN], *p; 780 int n; 781 782 if(con_clone(FID1, FID2)) 783 return 1; 784 785 for(;;) { 786 p = utfrune(name, '/'); 787 if(p == nil) 788 p = strchr(name, '\0'); 789 if(p == name) { 790 if(*name == '\0') 791 return 0; 792 name = p+1; 793 continue; 794 } 795 n = p-name; 796 if(n > NAMELEN) 797 return 1; 798 memset(elem, 0, sizeof(elem)); 799 memmove(elem, name, n); 800 if(con_walk(FID2, elem)) 801 return 1; 802 name = p; 803 } 804 } 805 806 /* needs to parse and return vlongs to cope with new larger block numbers */ 807 vlong 808 number(char *arg, int def, int base) 809 { 810 int c, sign, any; 811 vlong n; 812 813 if(arg == nil) 814 return def; 815 816 sign = 0; 817 any = 0; 818 n = 0; 819 820 for (c = *arg; isascii(c) && isspace(c) && c != '\n'; c = *arg) 821 arg++; 822 if(c == '-') { 823 sign = 1; 824 arg++; 825 c = *arg; 826 } 827 while (isascii(c) && (isdigit(c) || base == 16 && isxdigit(c))) { 828 n *= base; 829 if(c >= 'a' && c <= 'f') 830 n += c - 'a' + 10; 831 else if(c >= 'A' && c <= 'F') 832 n += c - 'A' + 10; 833 else 834 n += c - '0'; 835 arg++; 836 c = *arg; 837 any = 1; 838 } 839 if(!any) 840 return def; 841 if(sign) 842 n = -n; 843 return n; 844 } 845