1 #include "all.h" 2 #include "9p1.h" 3 4 static char elem[NAMELEN]; 5 static Filsys* cur_fs; 6 static char conline[100]; 7 8 void 9 consserve(void) 10 { 11 con_session(); 12 cmd_exec("cfs"); 13 cmd_exec("user"); 14 } 15 16 int 17 cmd_exec(char *arg) 18 { 19 char *s, *c; 20 int i; 21 22 for(i=0; s = command[i].string; i++) { 23 for(c=arg; *s; c++) 24 if(*c != *s++) 25 goto brk; 26 if(*c == '\0' || *c == ' ' || *c == '\t'){ 27 cons.arg = c; 28 (*command[i].func)(); 29 return 1; 30 } 31 brk:; 32 } 33 return 0; 34 } 35 36 void 37 cmd_check(void) 38 { 39 char *s; 40 int flags; 41 42 flags = 0; 43 for(s = cons.arg; *s; s++){ 44 while(*s == ' ' || *s == '\t') 45 s++; 46 if(*s == '\0') 47 break; 48 switch(*s){ 49 /* rebuild the free list */ 50 case 'f': flags |= Cfree; break; 51 /* fix bad tags */ 52 case 't': flags |= Ctag; break; 53 /* fix bad tags and clear the contents of the block */ 54 case 'c': flags |= Cream; break; 55 /* delete all redundant references to a block */ 56 case 'd': flags |= Cbad; break; 57 /* read and check tags on all blocks */ 58 case 'r': flags |= Crdall; break; 59 /* write all of the blocks you touch */ 60 case 'w': flags |= Ctouch; break; 61 /* print all directories as they are read */ 62 case 'p': flags |= Cpdir; break; 63 /* print all files as they are read */ 64 case 'P': flags |= Cpfile; break; 65 /* quiet, just report really nasty stuff */ 66 case 'q': flags |= Cquiet; break; 67 } 68 } 69 check(cur_fs, flags); 70 } 71 72 enum 73 { 74 Sset = (1<<0), 75 Setc = (1<<1), 76 }; 77 void 78 cmd_stats(void) 79 { 80 cprint("work stats\n"); 81 cprint(" work = %A rps\n", (Filta){&cons.work, 1}); 82 cprint(" rate = %A tBps\n", (Filta){&cons.rate, 1000}); 83 cprint(" hits = %A iops\n", (Filta){&cons.bhit, 1}); 84 cprint(" read = %A iops\n", (Filta){&cons.bread, 1}); 85 cprint(" init = %A iops\n", (Filta){&cons.binit, 1}); 86 /* for(i = 0; i < MAXTAG; i++) 87 cprint(" tag %G = %A iops\n", i, (Filta){&cons.tags[i], 1}); 88 */ 89 } 90 91 void 92 cmd_sync(void) 93 { 94 rlock(&mainlock); 95 syncall(); 96 runlock(&mainlock); 97 } 98 99 void 100 cmd_halt(void) 101 { 102 wlock(&mainlock); 103 syncall(); 104 superok(cur_fs->dev, superaddr(cur_fs->dev), 1); 105 print("kfs: file system halted\n"); 106 } 107 108 void 109 cmd_start(void) 110 { 111 superok(cur_fs->dev, superaddr(cur_fs->dev), 0); 112 wunlock(&mainlock); 113 print("kfs: file system started\n"); 114 } 115 116 void 117 cmd_help(void) 118 { 119 int i; 120 121 for(i=0; command[i].string; i++) 122 cprint(" %s %s\n", command[i].string, command[i].args); 123 cprint("check options:\n" 124 " r read all blocks\n" 125 " f rebuild the free list\n" 126 " t fix all bad tags\n" 127 " c fix bad tags and zero the blocks\n" 128 " d delete all redundant references to blocks\n" 129 " p print directories as they are checked\n" 130 " P print all files as they are checked\n" 131 " w write all blocks that are read\n"); 132 } 133 134 void 135 cmd_create(void) 136 { 137 int uid, gid, err; 138 long perm; 139 char oelem[NAMELEN]; 140 char name[NAMELEN]; 141 142 if(err = con_clone(FID1, FID2)){ 143 cprint("clone failed: %s\n", errstring[err]); 144 return; 145 } 146 if(skipbl(1)){ 147 cprint("skipbl\n"); 148 return; 149 } 150 oelem[0] = 0; 151 while(nextelem()) { 152 if(oelem[0]) 153 if(err = con_walk(FID2, oelem)){ 154 cprint("walk failed: %s\n", errstring[err]); 155 return; 156 } 157 memmove(oelem, elem, NAMELEN); 158 } 159 if(skipbl(1)) 160 return; 161 uid = strtouid(cname(name)); 162 if(uid == 0){ 163 cprint("unknown user %s\n", name); 164 return; 165 } 166 gid = strtouid(cname(name)); 167 if(gid == 0){ 168 cprint("unknown group %s\n", name); 169 return; 170 } 171 perm = number(0777, 8); 172 skipbl(0); 173 for(; *cons.arg; cons.arg++){ 174 if(*cons.arg == 'l') 175 perm |= PLOCK; 176 else 177 if(*cons.arg == 'a') 178 perm |= PAPND; 179 else 180 if(*cons.arg == 'd') 181 perm |= PDIR; 182 else 183 break; 184 } 185 err = con_create(FID2, elem, uid, gid, perm, 0); 186 if(err) 187 cprint("can't create %s: %s\n", elem, errstring[err]); 188 } 189 190 void 191 cmd_clri(void) 192 { 193 if(con_clone(FID1, FID2)) 194 return; 195 if(skipbl(1)) 196 return; 197 while(nextelem()) 198 if(con_walk(FID2, elem)){ 199 cprint("can't walk %s\n", elem); 200 return; 201 } 202 con_clri(FID2); 203 } 204 205 void 206 cmd_rename(void) 207 { 208 ulong perm; 209 Dentry d; 210 char stat[DIRREC]; 211 char oelem[NAMELEN], noelem[NAMELEN], nxelem[NAMELEN]; 212 int err; 213 214 if(con_clone(FID1, FID2)) 215 return; 216 if(skipbl(1)) 217 return; 218 oelem[0] = 0; 219 while(nextelem()) { 220 if(oelem[0]) 221 if(con_walk(FID2, oelem)){ 222 cprint("file does not exits"); 223 return; 224 } 225 memmove(oelem, elem, NAMELEN); 226 } 227 if(skipbl(1)) 228 return; 229 if(cons.arg[0]=='/'){ 230 if(con_clone(FID1, FID3)) 231 return; 232 noelem[0] = 0; 233 while(nextelem()){ 234 if(noelem[0]) 235 if(con_walk(FID3, noelem)){ 236 cprint("target path %s does not exist", noelem); 237 return; 238 } 239 memmove(noelem, elem, NAMELEN); 240 } 241 if(!con_walk(FID3, elem)){ 242 cprint("target %s already exists\n", elem); 243 return; 244 } 245 if(con_walk(FID2, oelem)){ 246 cprint("src %s does not exist\n", oelem); 247 return; 248 } 249 /* 250 * we know the target does not exist, 251 * the source does exist. 252 * to do the rename, create the target and then 253 * copy the directory entry directly. then remove the source. 254 */ 255 if(err = con_stat(FID2, stat)){ 256 cprint("can't stat file: %s\n", errstring[err]); 257 return; 258 } 259 convM2D9p1(stat, &d); 260 perm = (d.mode&0777)|((d.mode&0x7000)<<17); 261 if(err = con_create(FID3, elem, d.uid, d.gid, perm, (d.mode&DDIR)?OREAD:ORDWR)){ 262 cprint("can't create %s: %s\n", elem, errstring[err]); 263 return; 264 } 265 if(err = con_swap(FID2, FID3)){ 266 cprint("can't swap data: %s\n", errstring[err]); 267 return; 268 } 269 if(err = con_remove(FID2)){ 270 cprint("can't remove file: %s\n", errstring[err]); 271 return; 272 } 273 }else{ 274 cname(nxelem); 275 if(strchr(nxelem, '/')){ 276 cprint("bad rename target: not full path, but contains slashes\n"); 277 return; 278 } 279 if(!con_walk(FID2, nxelem)) 280 cprint("file %s already exists\n", nxelem); 281 else if(con_walk(FID2, oelem)) 282 cprint("file does not already exist\n"); 283 else if(err = con_stat(FID2, stat)) 284 cprint("can't stat file: %s\n", errstring[err]); 285 else{ 286 convM2D9p1(stat, &d); 287 strncpy(d.name, nxelem, NAMELEN); 288 convD2M9p1(&d, stat); 289 if(err = con_wstat(FID2, stat)) 290 cprint("can't move file: %s\n", errstring[err]); 291 } 292 } 293 } 294 295 void 296 cmd_remove(void) 297 { 298 if(con_clone(FID1, FID2)) 299 return; 300 if(skipbl(1)) 301 return; 302 while(nextelem()) 303 if(con_walk(FID2, elem)){ 304 cprint("can't walk %s\n", elem); 305 return; 306 } 307 con_remove(FID2); 308 } 309 310 void 311 cmd_cfs(void) 312 { 313 Filsys *fs; 314 315 if(*cons.arg != ' ') { 316 fs = &filesys[0]; /* default */ 317 } else { 318 if(skipbl(1)){ 319 cprint("skipbl\n"); 320 return; 321 } 322 if(!nextelem()) 323 fs = &filesys[0]; /* default */ 324 else 325 fs = fsstr(elem); 326 } 327 if(fs == 0) { 328 cprint("unknown file system %s\n", elem); 329 return; 330 } 331 if(con_attach(FID1, "adm", fs->name)) 332 panic("FID1 attach to root"); 333 cur_fs = fs; 334 } 335 336 /* 337 * find out the length of a file 338 * given the mesg version of a stat buffer 339 * we call this because convM2D is different 340 * for the file system than in the os 341 */ 342 static uvlong 343 statlen(char *ap) 344 { 345 uchar *p; 346 ulong ll, hl; 347 348 p = (uchar*)ap; 349 p += 3*28+5*4; 350 ll = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); 351 hl = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24); 352 return ll | ((uvlong) hl << 32); 353 } 354 355 int 356 adduser(char *user, int isgroup) 357 { 358 char stat[DIRREC]; 359 char msg[100]; 360 Uid *u; 361 int i, c, nu; 362 363 /* 364 * check uniq of name 365 * and get next uid 366 */ 367 cmd_exec("cfs"); 368 cmd_exec("user"); 369 if(isgroup) 370 nu = 9000; 371 else 372 nu = 0; 373 for(i=0, u=uid; i<conf.nuid; i++,u++) { 374 c = u->uid; 375 if(c == 0) 376 break; 377 if(strcmp(uidspace+u->offset, user) == 0) 378 return 1; 379 if(c >= 9000 && !isgroup) 380 continue; 381 if(c > nu) 382 nu = c; 383 } 384 nu++; 385 if(isgroup){ 386 if(nu >= 0x10000) { 387 cprint("out of group ids\n"); 388 return 0; 389 } 390 } else { 391 if(nu >= 9000) { 392 cprint("out of user ids\n"); 393 return 0; 394 } 395 } 396 397 /* 398 * write onto adm/users 399 */ 400 if(con_clone(FID1, FID2) 401 || con_path(FID2, "/adm/users") 402 || con_open(FID2, 1)) { 403 cprint("can't open /adm/users\n"); 404 return 0; 405 } 406 407 sprint(msg, "%d:%s:%s:\n", nu, user, user); 408 cprint("add user %s", msg); 409 c = strlen(msg); 410 i = con_stat(FID2, stat); 411 if(i){ 412 cprint("can't stat /adm/users: %s\n", errstring[i]); 413 return 0; 414 } 415 i = con_write(FID2, msg, statlen(stat), c); 416 if(i != c){ 417 cprint("short write on /adm/users: %d %d\n", c, i); 418 return 0; 419 } 420 return 1; 421 } 422 423 void 424 cmd_newuser(void) 425 { 426 char user[NAMELEN], param[NAMELEN], msg[100]; 427 int i, c; 428 429 /* 430 * get uid 431 */ 432 cname(user); 433 cname(param); 434 for(i=0; i<NAMELEN; i++) { 435 c = user[i]; 436 if(c == 0) 437 break; 438 if(c >= '0' && c <= '9' 439 || c >= 'a' && c <= 'z' 440 || c >= 'A' && c <= 'Z') 441 continue; 442 cprint("bad character in name: 0x%x\n", c); 443 return; 444 } 445 if(i < 2) { 446 cprint("name too short: %s\n", user); 447 return; 448 } 449 if(i >= NAMELEN) { 450 cprint("name too long: %s\n", user); 451 return; 452 } 453 454 switch(param[0]){ 455 case 0: 456 if(!adduser(user, 0)) 457 return; 458 cmd_exec("user"); 459 break; 460 case ':': 461 adduser(user, 1); 462 cmd_exec("user"); 463 return; 464 case '#': 465 adduser(user, 0); 466 cmd_exec("user"); 467 return; 468 } 469 470 /* 471 * create directories 472 */ 473 cmd_exec("user"); 474 sprint(msg, "create /usr/%s %s %s 775 d", user, user, user); 475 cmd_exec(msg); 476 sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user); 477 cmd_exec(msg); 478 sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user); 479 cmd_exec(msg); 480 sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user); 481 cmd_exec(msg); 482 sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user); 483 cmd_exec(msg); 484 sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user); 485 cmd_exec(msg); 486 sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user); 487 cmd_exec(msg); 488 sprint(msg, "create /usr/%s/bin/power %s %s 775 d", user, user, user); 489 cmd_exec(msg); 490 sprint(msg, "create /usr/%s/bin/alpha %s %s 775 d", user, user, user); 491 cmd_exec(msg); 492 } 493 494 void 495 cmd_checkuser(void) 496 { 497 uchar buf[DIRREC], *p; 498 static char utime[4]; 499 500 if(con_clone(FID1, FID2) 501 || con_path(FID2, "/adm/users") 502 || con_open(FID2, 0) 503 || con_stat(FID2, (char*)buf)) 504 return; 505 p = buf + 3*NAMELEN + 4*4; 506 if(memcmp(utime, p, 4) == 0) 507 return; 508 memmove(utime, p, 4); 509 cmd_user(); 510 } 511 512 void 513 cmd_allow(void) 514 { 515 wstatallow = 1; 516 } 517 518 void 519 cmd_disallow(void) 520 { 521 wstatallow = 0; 522 } 523 524 void 525 cmd_chat(void) 526 { 527 chat = 1 - chat; 528 } 529 530 void 531 cmd_atime(void) 532 { 533 noatime = !noatime; 534 if(noatime) 535 cprint("atimes will not be updated\n"); 536 else 537 cprint("atimes will be updated\n"); 538 } 539 540 void 541 cmd_noneattach(void) 542 { 543 allownone = !allownone; 544 if(allownone) 545 cprint("none can attach to new connections\n"); 546 else 547 cprint("none can only attach on authenticated connections\n"); 548 } 549 550 void 551 cmd_listen(void) 552 { 553 char addr[NAMELEN]; 554 555 if(skipbl(0)) 556 strcpy(addr, "il!*!17008"); 557 else 558 cname(addr); 559 560 if(netserve(addr)) 561 cprint("announce %s failed\n", addr); 562 else 563 cprint("announce %s\n", addr); 564 } 565 566 void 567 cmd_nowritegroup(void) 568 { 569 writegroup = 0; 570 } 571 572 Command command[] = 573 { 574 "allow", cmd_allow, "", 575 "allowoff", cmd_disallow, "", 576 "atime", cmd_atime, "", 577 "cfs", cmd_cfs, "[filesys]", 578 "chat", cmd_chat, "", 579 "check", cmd_check, "[cdfpPqrtw]", 580 "clri", cmd_clri, "filename", 581 "create", cmd_create, "filename user group perm [ald]", 582 "disallow", cmd_disallow, "", 583 "halt", cmd_halt, "", 584 "help", cmd_help, "", 585 "listen", cmd_listen, "[address]", 586 "newuser", cmd_newuser, "username", 587 "noneattach", cmd_noneattach, "", 588 "nowritegroup", cmd_nowritegroup, "", 589 "remove", cmd_remove, "filename", 590 "rename", cmd_rename, "file newname", 591 "start", cmd_start, "", 592 "stats", cmd_stats, "[fw]", 593 "sync", cmd_sync, "", 594 "user", cmd_user, "", 595 0 596 }; 597 598 int 599 skipbl(int err) 600 { 601 if(*cons.arg != ' ') { 602 if(err) 603 cprint("syntax error\n"); 604 return 1; 605 } 606 while(*cons.arg == ' ') 607 cons.arg++; 608 return 0; 609 } 610 611 char* 612 _cname(char *name) 613 { 614 int i, c; 615 616 memset(name, 0, NAMELEN); 617 for(i=0;; i++) { 618 c = *cons.arg; 619 switch(c) { 620 case ' ': 621 case '\t': 622 case '\n': 623 case '\0': 624 return name; 625 } 626 if(i < NAMELEN-1) 627 name[i] = c; 628 cons.arg++; 629 } 630 } 631 632 char* 633 cname(char *name) 634 { 635 skipbl(0); 636 return _cname(name); 637 } 638 639 int 640 nextelem(void) 641 { 642 char *e; 643 int i, c; 644 645 e = elem; 646 while(*cons.arg == '/') 647 cons.arg++; 648 c = *cons.arg; 649 if(c == 0 || c == ' ') 650 return 0; 651 for(i = 0; c = *cons.arg; i++) { 652 if(c == ' ' || c == '/') 653 break; 654 if(i == NAMELEN) { 655 cprint("path name component too long\n"); 656 return 0; 657 } 658 *e++ = c; 659 cons.arg++; 660 } 661 *e = 0; 662 return 1; 663 } 664 665 long 666 number(int d, int base) 667 { 668 int c, sign, any; 669 long n; 670 671 sign = 0; 672 any = 0; 673 n = 0; 674 675 c = *cons.arg; 676 while(c == ' ') { 677 cons.arg++; 678 c = *cons.arg; 679 } 680 if(c == '-') { 681 sign = 1; 682 cons.arg++; 683 c = *cons.arg; 684 } 685 while((c >= '0' && c <= '9') || 686 (base == 16 && c >= 'a' && c <= 'f') || 687 (base == 16 && c >= 'A' && c <= 'F')) { 688 n *= base; 689 if(c >= 'a' && c <= 'f') 690 n += c - 'a' + 10; 691 else 692 if(c >= 'A' && c <= 'F') 693 n += c - 'A' + 10; 694 else 695 n += c - '0'; 696 cons.arg++; 697 c = *cons.arg; 698 any = 1; 699 } 700 if(!any) 701 return d; 702 if(sign) 703 n = -n; 704 return n; 705 } 706