1 #include "stdinc.h" 2 #include "dat.h" 3 #include "fns.h" 4 5 #include "9.h" 6 7 typedef struct Fsys Fsys; 8 9 struct Fsys { 10 VtLock* lock; 11 12 char* name; 13 char* dev; 14 char* venti; 15 16 Fs* fs; 17 VtSession* session; 18 int ref; 19 20 int noauth; 21 int noperm; 22 int wstatallow; 23 24 Fsys* next; 25 }; 26 27 static struct { 28 VtLock* lock; 29 Fsys* head; 30 Fsys* tail; 31 32 char* curfsys; 33 } sbox; 34 35 static char *_argv0; 36 #define argv0 _argv0 37 38 static char FsysAll[] = "all"; 39 40 static char EFsysBusy[] = "fsys: '%s' busy"; 41 static char EFsysExists[] = "fsys: '%s' already exists"; 42 static char EFsysNoCurrent[] = "fsys: no current fsys"; 43 static char EFsysNotFound[] = "fsys: '%s' not found"; 44 static char EFsysNotOpen[] = "fsys: '%s' not open"; 45 46 static Fsys* 47 _fsysGet(char* name) 48 { 49 Fsys *fsys; 50 51 if(name == nil || name[0] == '\0') 52 name = "main"; 53 54 vtRLock(sbox.lock); 55 for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ 56 if(strcmp(name, fsys->name) == 0){ 57 fsys->ref++; 58 break; 59 } 60 } 61 vtRUnlock(sbox.lock); 62 if(fsys == nil) 63 vtSetError(EFsysNotFound, name); 64 return fsys; 65 } 66 67 static int 68 cmdPrintConfig(int argc, char* argv[]) 69 { 70 Fsys *fsys; 71 char *usage = "usage: printconfig"; 72 73 ARGBEGIN{ 74 default: 75 return cliError(usage); 76 }ARGEND 77 78 if(argc) 79 return cliError(usage); 80 81 vtRLock(sbox.lock); 82 for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ 83 consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev); 84 if(fsys->venti && fsys->venti[0]) 85 consPrint("\tfsys %s venti %q\n", fsys->name, fsys->venti); 86 } 87 vtRUnlock(sbox.lock); 88 return 1; 89 } 90 91 Fsys* 92 fsysGet(char* name) 93 { 94 Fsys *fsys; 95 96 if((fsys = _fsysGet(name)) == nil) 97 return nil; 98 99 vtLock(fsys->lock); 100 if(fsys->fs == nil){ 101 vtSetError(EFsysNotOpen, fsys->name); 102 vtUnlock(fsys->lock); 103 fsysPut(fsys); 104 return nil; 105 } 106 vtUnlock(fsys->lock); 107 108 return fsys; 109 } 110 111 char* 112 fsysGetName(Fsys* fsys) 113 { 114 return fsys->name; 115 } 116 117 Fsys* 118 fsysIncRef(Fsys* fsys) 119 { 120 vtLock(sbox.lock); 121 fsys->ref++; 122 vtUnlock(sbox.lock); 123 124 return fsys; 125 } 126 127 void 128 fsysPut(Fsys* fsys) 129 { 130 vtLock(sbox.lock); 131 assert(fsys->ref > 0); 132 fsys->ref--; 133 vtUnlock(sbox.lock); 134 } 135 136 Fs* 137 fsysGetFs(Fsys* fsys) 138 { 139 assert(fsys != nil && fsys->fs != nil); 140 141 return fsys->fs; 142 } 143 144 void 145 fsysFsRlock(Fsys* fsys) 146 { 147 vtRLock(fsys->fs->elk); 148 } 149 150 void 151 fsysFsRUnlock(Fsys* fsys) 152 { 153 vtRUnlock(fsys->fs->elk); 154 } 155 156 int 157 fsysNoAuthCheck(Fsys* fsys) 158 { 159 return fsys->noauth; 160 } 161 162 int 163 fsysNoPermCheck(Fsys* fsys) 164 { 165 return fsys->noperm; 166 } 167 168 int 169 fsysWstatAllow(Fsys* fsys) 170 { 171 return fsys->wstatallow; 172 } 173 174 static char modechars[] = "YUGalLdHSATs"; 175 static ulong modebits[] = { 176 ModeSticky, 177 ModeSetUid, 178 ModeSetGid, 179 ModeAppend, 180 ModeExclusive, 181 ModeLink, 182 ModeDir, 183 ModeHidden, 184 ModeSystem, 185 ModeArchive, 186 ModeTemporary, 187 ModeSnapshot, 188 0 189 }; 190 191 char* 192 fsysModeString(ulong mode, char *buf) 193 { 194 int i; 195 char *p; 196 197 p = buf; 198 for(i=0; modebits[i]; i++) 199 if(mode & modebits[i]) 200 *p++ = modechars[i]; 201 sprint(p, "%luo", mode&0777); 202 return buf; 203 } 204 205 int 206 fsysParseMode(char* s, ulong* mode) 207 { 208 ulong x, y; 209 char *p; 210 211 x = 0; 212 for(; *s < '0' || *s > '9'; s++){ 213 if(*s == 0) 214 return 0; 215 p = strchr(modechars, *s); 216 if(p == nil) 217 return 0; 218 x |= modebits[p-modechars]; 219 } 220 y = strtoul(s, &p, 8); 221 if(*p != '\0' || y > 0777) 222 return 0; 223 *mode = x|y; 224 return 1; 225 } 226 227 File* 228 fsysGetRoot(Fsys* fsys, char* name) 229 { 230 File *root, *sub; 231 232 assert(fsys != nil && fsys->fs != nil); 233 234 root = fsGetRoot(fsys->fs); 235 if(name == nil || strcmp(name, "") == 0) 236 return root; 237 238 sub = fileWalk(root, name); 239 fileDecRef(root); 240 241 return sub; 242 } 243 244 static Fsys* 245 fsysAlloc(char* name, char* dev) 246 { 247 Fsys *fsys; 248 249 vtLock(sbox.lock); 250 for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ 251 if(strcmp(fsys->name, name) != 0) 252 continue; 253 vtSetError(EFsysExists, name); 254 vtUnlock(sbox.lock); 255 return nil; 256 } 257 258 fsys = vtMemAllocZ(sizeof(Fsys)); 259 fsys->lock = vtLockAlloc(); 260 fsys->name = vtStrDup(name); 261 fsys->dev = vtStrDup(dev); 262 263 fsys->ref = 1; 264 265 if(sbox.tail != nil) 266 sbox.tail->next = fsys; 267 else 268 sbox.head = fsys; 269 sbox.tail = fsys; 270 vtUnlock(sbox.lock); 271 272 return fsys; 273 } 274 275 static int 276 fsysClose(Fsys* fsys, int argc, char* argv[]) 277 { 278 char *usage = "usage: [fsys name] close"; 279 280 ARGBEGIN{ 281 default: 282 return cliError(usage); 283 }ARGEND 284 if(argc) 285 return cliError(usage); 286 287 return cliError("close isn't working yet; sync and then kill fossil"); 288 289 /* 290 * Oooh. This could be hard. What if fsys->ref != 1? 291 * Also, fsClose() either does the job or panics, can we 292 * gracefully detect it's still busy? 293 * 294 * More thought and care needed here. 295 */ 296 fsClose(fsys->fs); 297 fsys->fs = nil; 298 vtClose(fsys->session); 299 fsys->session = nil; 300 301 if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){ 302 sbox.curfsys = nil; 303 consPrompt(nil); 304 } 305 306 return 1; 307 } 308 309 static int 310 fsysVac(Fsys* fsys, int argc, char* argv[]) 311 { 312 uchar score[VtScoreSize]; 313 char *usage = "usage: [fsys name] vac path"; 314 315 ARGBEGIN{ 316 default: 317 return cliError(usage); 318 }ARGEND 319 if(argc != 1) 320 return cliError(usage); 321 322 if(!fsVac(fsys->fs, argv[0], score)) 323 return 0; 324 325 consPrint("vac:%V\n", score); 326 return 1; 327 } 328 329 static int 330 fsysSnap(Fsys* fsys, int argc, char* argv[]) 331 { 332 int doarchive; 333 char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]"; 334 char *src, *dst; 335 336 src = nil; 337 dst = nil; 338 doarchive = 0; 339 ARGBEGIN{ 340 default: 341 return cliError(usage); 342 case 'a': 343 doarchive = 1; 344 break; 345 case 'd': 346 if((dst = ARGF()) == nil) 347 return cliError(usage); 348 break; 349 case 's': 350 if((src = ARGF()) == nil) 351 return cliError(usage); 352 break; 353 }ARGEND 354 if(argc) 355 return cliError(usage); 356 357 if(!fsSnapshot(fsys->fs, src, dst, doarchive)) 358 return 0; 359 360 return 1; 361 } 362 363 static int 364 fsysSnapClean(Fsys *fsys, int argc, char* argv[]) 365 { 366 u32int arch, snap, life; 367 char *usage = "usage: [fsys name] snapclean [maxminutes]\n"; 368 369 ARGBEGIN{ 370 default: 371 return cliError(usage); 372 }ARGEND 373 374 if(argc > 1) 375 return cliError(usage); 376 if(argc == 1) 377 life = atoi(argv[0]); 378 else 379 snapGetTimes(fsys->fs->snap, &arch, &snap, &life); 380 381 fsSnapshotCleanup(fsys->fs, life); 382 return 1; 383 } 384 385 static int 386 fsysSnapTime(Fsys* fsys, int argc, char* argv[]) 387 { 388 char buf[128], *x; 389 int hh, mm, changed; 390 u32int arch, snap, life; 391 char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]"; 392 393 changed = 0; 394 snapGetTimes(fsys->fs->snap, &arch, &snap, &life); 395 ARGBEGIN{ 396 case 'a': 397 changed = 1; 398 x = ARGF(); 399 if(x == nil) 400 return cliError(usage); 401 if(strcmp(x, "none") == 0){ 402 arch = ~(u32int)0; 403 break; 404 } 405 if(strlen(x) != 4 || strspn(x, "0123456789") != 4) 406 return cliError(usage); 407 hh = (x[0]-'0')*10 + x[1]-'0'; 408 mm = (x[2]-'0')*10 + x[3]-'0'; 409 if(hh >= 24 || mm >= 60) 410 return cliError(usage); 411 arch = hh*60+mm; 412 break; 413 case 's': 414 changed = 1; 415 x = ARGF(); 416 if(x == nil) 417 return cliError(usage); 418 if(strcmp(x, "none") == 0){ 419 snap = ~(u32int)0; 420 break; 421 } 422 snap = atoi(x); 423 break; 424 case 't': 425 changed = 1; 426 x = ARGF(); 427 if(x == nil) 428 return cliError(usage); 429 if(strcmp(x, "none") == 0){ 430 life = ~(u32int)0; 431 break; 432 } 433 life = atoi(x); 434 break; 435 default: 436 return cliError(usage); 437 }ARGEND 438 if(argc > 0) 439 return cliError(usage); 440 441 if(changed){ 442 snapSetTimes(fsys->fs->snap, arch, snap, life); 443 return 1; 444 } 445 snapGetTimes(fsys->fs->snap, &arch, &snap, &life); 446 if(arch != ~(u32int)0) 447 sprint(buf, "-a %02d%02d", arch/60, arch%60); 448 else 449 sprint(buf, "-a none"); 450 if(snap != ~(u32int)0) 451 sprint(buf+strlen(buf), " -s %d", snap); 452 else 453 sprint(buf+strlen(buf), " -s none"); 454 if(life != ~(u32int)0) 455 sprint(buf+strlen(buf), " -t %ud", life); 456 else 457 sprint(buf+strlen(buf), " -t none"); 458 consPrint("\tsnaptime %s\n", buf); 459 return 1; 460 } 461 462 static int 463 fsysSync(Fsys* fsys, int argc, char* argv[]) 464 { 465 char *usage = "usage: [fsys name] sync"; 466 467 ARGBEGIN{ 468 default: 469 return cliError(usage); 470 }ARGEND 471 if(argc > 0) 472 return cliError(usage); 473 474 fsSync(fsys->fs); 475 return 1; 476 } 477 478 static int 479 fsysHalt(Fsys *fsys, int argc, char* argv[]) 480 { 481 char *usage = "usage: [fsys name] halt"; 482 483 ARGBEGIN{ 484 default: 485 return cliError(usage); 486 }ARGEND 487 if(argc > 0) 488 return cliError(usage); 489 490 fsHalt(fsys->fs); 491 return 1; 492 } 493 494 static int 495 fsysUnhalt(Fsys *fsys, int argc, char* argv[]) 496 { 497 char *usage = "usage: [fsys name] unhalt"; 498 499 ARGBEGIN{ 500 default: 501 return cliError(usage); 502 }ARGEND 503 if(argc > 0) 504 return cliError(usage); 505 506 if(!fsys->fs->halted) 507 return cliError("file system %s not halted", fsys->name); 508 509 fsUnhalt(fsys->fs); 510 return 1; 511 } 512 513 static int 514 fsysRemove(Fsys* fsys, int argc, char* argv[]) 515 { 516 File *file; 517 char *usage = "usage: [fsys name] remove path ..."; 518 519 ARGBEGIN{ 520 default: 521 return cliError(usage); 522 }ARGEND 523 if(argc == 0) 524 return cliError(usage); 525 526 vtRLock(fsys->fs->elk); 527 while(argc > 0){ 528 if((file = fileOpen(fsys->fs, argv[0])) == nil) 529 consPrint("%s: %R\n", argv[0]); 530 else{ 531 if(!fileRemove(file, uidadm)) 532 consPrint("%s: %R\n", argv[0]); 533 fileDecRef(file); 534 } 535 argc--; 536 argv++; 537 } 538 vtRUnlock(fsys->fs->elk); 539 540 return 1; 541 } 542 543 static int 544 fsysClri(Fsys* fsys, int argc, char* argv[]) 545 { 546 char *usage = "usage: [fsys name] clri path ..."; 547 548 ARGBEGIN{ 549 default: 550 return cliError(usage); 551 }ARGEND 552 if(argc == 0) 553 return cliError(usage); 554 555 vtRLock(fsys->fs->elk); 556 while(argc > 0){ 557 if(!fileClriPath(fsys->fs, argv[0], uidadm)) 558 consPrint("clri %s: %R\n", argv[0]); 559 argc--; 560 argv++; 561 } 562 vtRUnlock(fsys->fs->elk); 563 564 return 1; 565 } 566 567 /* 568 * Inspect and edit the labels for blocks on disk. 569 */ 570 static int 571 fsysLabel(Fsys* fsys, int argc, char* argv[]) 572 { 573 Fs *fs; 574 Label l; 575 int n, r; 576 u32int addr; 577 Block *b, *bb; 578 char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]"; 579 580 ARGBEGIN{ 581 default: 582 return cliError(usage); 583 }ARGEND 584 if(argc != 1 && argc != 6) 585 return cliError(usage); 586 587 r = 0; 588 vtRLock(fsys->fs->elk); 589 590 fs = fsys->fs; 591 addr = strtoul(argv[0], 0, 0); 592 b = cacheLocal(fs->cache, PartData, addr, OReadOnly); 593 if(b == nil) 594 goto Out0; 595 596 l = b->l; 597 consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n", 598 argc==6 ? "old: " : "", addr, l.type, l.state, 599 l.epoch, l.epochClose, l.tag); 600 601 if(argc == 6){ 602 if(strcmp(argv[1], "-") != 0) 603 l.type = atoi(argv[1]); 604 if(strcmp(argv[2], "-") != 0) 605 l.state = atoi(argv[2]); 606 if(strcmp(argv[3], "-") != 0) 607 l.epoch = strtoul(argv[3], 0, 0); 608 if(strcmp(argv[4], "-") != 0) 609 l.epochClose = strtoul(argv[4], 0, 0); 610 if(strcmp(argv[5], "-") != 0) 611 l.tag = strtoul(argv[5], 0, 0); 612 613 consPrint("new: label %#ux %ud %ud %ud %ud %#x\n", 614 addr, l.type, l.state, l.epoch, l.epochClose, l.tag); 615 bb = _blockSetLabel(b, &l); 616 if(bb == nil) 617 goto Out1; 618 n = 0; 619 for(;;){ 620 if(blockWrite(bb)){ 621 while(bb->iostate != BioClean){ 622 assert(bb->iostate == BioWriting); 623 vtSleep(bb->ioready); 624 } 625 break; 626 } 627 consPrint("blockWrite: %R\n"); 628 if(n++ >= 5){ 629 consPrint("giving up\n"); 630 break; 631 } 632 sleep(5*1000); 633 } 634 blockPut(bb); 635 } 636 r = 1; 637 Out1: 638 blockPut(b); 639 Out0: 640 vtRUnlock(fs->elk); 641 642 return r; 643 } 644 645 /* 646 * Inspect and edit the blocks on disk. 647 */ 648 static int 649 fsysBlock(Fsys* fsys, int argc, char* argv[]) 650 { 651 Fs *fs; 652 char *s; 653 Block *b; 654 uchar *buf; 655 u32int addr; 656 int c, count, i, offset; 657 char *usage = "usage: [fsys name] block addr offset [count [data]]"; 658 659 ARGBEGIN{ 660 default: 661 return cliError(usage); 662 }ARGEND 663 if(argc < 2 || argc > 4) 664 return cliError(usage); 665 666 fs = fsys->fs; 667 addr = strtoul(argv[0], 0, 0); 668 offset = strtoul(argv[1], 0, 0); 669 if(offset < 0 || offset >= fs->blockSize){ 670 vtSetError("bad offset"); 671 return 0; 672 } 673 if(argc > 2) 674 count = strtoul(argv[2], 0, 0); 675 else 676 count = 100000000; 677 if(offset+count > fs->blockSize) 678 count = fs->blockSize - count; 679 680 vtRLock(fs->elk); 681 682 b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly); 683 if(b == nil){ 684 vtSetError("cacheLocal %#ux: %R", addr); 685 vtRUnlock(fs->elk); 686 return 0; 687 } 688 689 consPrint("\t%sblock %#ux %ud %ud %.*H\n", 690 argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset); 691 692 if(argc == 4){ 693 s = argv[3]; 694 if(strlen(s) != 2*count){ 695 vtSetError("bad data count"); 696 goto Out; 697 } 698 buf = vtMemAllocZ(count); 699 for(i = 0; i < count*2; i++){ 700 if(s[i] >= '0' && s[i] <= '9') 701 c = s[i] - '0'; 702 else if(s[i] >= 'a' && s[i] <= 'f') 703 c = s[i] - 'a' + 10; 704 else if(s[i] >= 'A' && s[i] <= 'F') 705 c = s[i] - 'A' + 10; 706 else{ 707 vtSetError("bad hex"); 708 vtMemFree(buf); 709 goto Out; 710 } 711 if((i & 1) == 0) 712 c <<= 4; 713 buf[i>>1] |= c; 714 } 715 memmove(b->data+offset, buf, count); 716 consPrint("\tnew: block %#ux %ud %ud %.*H\n", 717 addr, offset, count, count, b->data+offset); 718 blockDirty(b); 719 } 720 721 Out: 722 blockPut(b); 723 vtRUnlock(fs->elk); 724 725 return 1; 726 } 727 728 /* 729 * Free a disk block. 730 */ 731 static int 732 fsysBfree(Fsys* fsys, int argc, char* argv[]) 733 { 734 Fs *fs; 735 Label l; 736 char *p; 737 Block *b; 738 u32int addr; 739 char *usage = "usage: [fsys name] bfree addr ..."; 740 741 ARGBEGIN{ 742 default: 743 return cliError(usage); 744 }ARGEND 745 if(argc == 0) 746 return cliError(usage); 747 748 fs = fsys->fs; 749 vtRLock(fs->elk); 750 while(argc > 0){ 751 addr = strtoul(argv[0], &p, 0); 752 if(*p != '\0'){ 753 consPrint("bad address - '%s'\n", addr); 754 /* syntax error; let's stop */ 755 vtRUnlock(fs->elk); 756 return 0; 757 } 758 b = cacheLocal(fs->cache, PartData, addr, OReadOnly); 759 if(b == nil){ 760 consPrint("loading %#ux: %R\n", addr); 761 continue; 762 } 763 l = b->l; 764 if(l.state == BsFree) 765 consPrint("%#ux is already free\n", addr); 766 else{ 767 consPrint("label %#ux %ud %ud %ud %ud %#x\n", 768 addr, l.type, l.state, l.epoch, l.epochClose, l.tag); 769 l.state = BsFree; 770 l.type = BtMax; 771 l.tag = 0; 772 l.epoch = 0; 773 l.epochClose = 0; 774 if(!blockSetLabel(b, &l, 0)) 775 consPrint("freeing %#ux: %R\n", addr); 776 } 777 blockPut(b); 778 argc--; 779 argv++; 780 } 781 vtRUnlock(fs->elk); 782 783 return 1; 784 } 785 786 static int 787 fsysDf(Fsys *fsys, int argc, char* argv[]) 788 { 789 char *usage = "usage: [fsys name] df"; 790 u32int used, tot, bsize; 791 Fs *fs; 792 793 ARGBEGIN{ 794 default: 795 return cliError(usage); 796 }ARGEND 797 if(argc != 0) 798 return cliError(usage); 799 800 fs = fsys->fs; 801 cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize); 802 consPrint("\t%s: %,llud used + %,llud free = %,llud (%ud%% used)\n", 803 fsys->name, used*(vlong)bsize, (tot-used)*(vlong)bsize, 804 tot*(vlong)bsize, used*100/tot); 805 return 1; 806 } 807 808 /* 809 * Zero an entry or a pointer. 810 */ 811 static int 812 fsysClrep(Fsys* fsys, int argc, char* argv[], int ch) 813 { 814 Fs *fs; 815 Entry e; 816 Block *b; 817 u32int addr; 818 int i, max, offset, sz; 819 uchar zero[VtEntrySize]; 820 char *usage = "usage: [fsys name] clr%c addr offset ..."; 821 822 ARGBEGIN{ 823 default: 824 return cliError(usage, ch); 825 }ARGEND 826 if(argc < 2) 827 return cliError(usage, ch); 828 829 fs = fsys->fs; 830 vtRLock(fsys->fs->elk); 831 832 addr = strtoul(argv[0], 0, 0); 833 b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly); 834 if(b == nil){ 835 vtSetError("cacheLocal %#ux: %R", addr); 836 Err: 837 vtRUnlock(fsys->fs->elk); 838 return 0; 839 } 840 841 switch(ch){ 842 default: 843 vtSetError("clrep"); 844 goto Err; 845 case 'e': 846 if(b->l.type != BtDir){ 847 vtSetError("wrong block type"); 848 goto Err; 849 } 850 sz = VtEntrySize; 851 memset(&e, 0, sizeof e); 852 entryPack(&e, zero, 0); 853 break; 854 case 'p': 855 if(b->l.type == BtDir || b->l.type == BtData){ 856 vtSetError("wrong block type"); 857 goto Err; 858 } 859 sz = VtScoreSize; 860 memmove(zero, vtZeroScore, VtScoreSize); 861 break; 862 } 863 max = fs->blockSize/sz; 864 865 for(i = 1; i < argc; i++){ 866 offset = atoi(argv[i]); 867 if(offset >= max){ 868 consPrint("\toffset %d too large (>= %d)\n", i, max); 869 continue; 870 } 871 consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz); 872 memmove(b->data+offset*sz, zero, sz); 873 } 874 blockDirty(b); 875 blockPut(b); 876 vtRUnlock(fsys->fs->elk); 877 878 return 1; 879 } 880 881 static int 882 fsysClre(Fsys* fsys, int argc, char* argv[]) 883 { 884 return fsysClrep(fsys, argc, argv, 'e'); 885 } 886 887 static int 888 fsysClrp(Fsys* fsys, int argc, char* argv[]) 889 { 890 return fsysClrep(fsys, argc, argv, 'p'); 891 } 892 893 static int 894 fsysEsearch1(File* f, char* s, u32int elo) 895 { 896 int n, r; 897 DirEntry de; 898 DirEntryEnum *dee; 899 File *ff; 900 Entry e, ee; 901 char *t; 902 903 dee = deeOpen(f); 904 if(dee == nil) 905 return 0; 906 907 n = 0; 908 for(;;){ 909 r = deeRead(dee, &de); 910 if(r < 0){ 911 consPrint("\tdeeRead %s/%s: %R\n", s, de.elem); 912 break; 913 } 914 if(r == 0) 915 break; 916 if(de.mode & ModeSnapshot){ 917 if((ff = fileWalk(f, de.elem)) == nil) 918 consPrint("\tcannot walk %s/%s: %R\n", s, de.elem); 919 else{ 920 if(!fileGetSources(ff, &e, &ee)) 921 consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem); 922 else if(e.snap != 0 && e.snap < elo){ 923 consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem); 924 n++; 925 } 926 fileDecRef(ff); 927 } 928 } 929 else if(de.mode & ModeDir){ 930 if((ff = fileWalk(f, de.elem)) == nil) 931 consPrint("\tcannot walk %s/%s: %R\n", s, de.elem); 932 else{ 933 t = smprint("%s/%s", s, de.elem); 934 n += fsysEsearch1(ff, t, elo); 935 vtMemFree(t); 936 fileDecRef(ff); 937 } 938 } 939 deCleanup(&de); 940 if(r < 0) 941 break; 942 } 943 deeClose(dee); 944 945 return n; 946 } 947 948 static int 949 fsysEsearch(Fs* fs, char* path, u32int elo) 950 { 951 int n; 952 File *f; 953 DirEntry de; 954 955 f = fileOpen(fs, path); 956 if(f == nil) 957 return 0; 958 if(!fileGetDir(f, &de)){ 959 consPrint("\tfileGetDir %s failed: %R\n", path); 960 fileDecRef(f); 961 return 0; 962 } 963 if((de.mode & ModeDir) == 0){ 964 fileDecRef(f); 965 deCleanup(&de); 966 return 0; 967 } 968 deCleanup(&de); 969 n = fsysEsearch1(f, path, elo); 970 fileDecRef(f); 971 return n; 972 } 973 974 static int 975 fsysEpoch(Fsys* fsys, int argc, char* argv[]) 976 { 977 Fs *fs; 978 int force, n, remove; 979 u32int low, old; 980 char *usage = "usage: [fsys name] epoch [[-ry] low]"; 981 982 force = 0; 983 remove = 0; 984 ARGBEGIN{ 985 case 'y': 986 force = 1; 987 break; 988 case 'r': 989 remove = 1; 990 break; 991 default: 992 return cliError(usage); 993 }ARGEND 994 if(argc > 1) 995 return cliError(usage); 996 if(argc > 0) 997 low = strtoul(argv[0], 0, 0); 998 else 999 low = ~(u32int)0; 1000 1001 if(low == 0) 1002 return cliError("low epoch cannot be zero"); 1003 1004 fs = fsys->fs; 1005 1006 vtRLock(fs->elk); 1007 consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi); 1008 n = fsysEsearch(fsys->fs, "/archive", low); 1009 n += fsysEsearch(fsys->fs, "/snapshot", low); 1010 consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low); 1011 vtRUnlock(fs->elk); 1012 1013 /* 1014 * There's a small race here -- a new snapshot with epoch < low might 1015 * get introduced now that we unlocked fs->elk. Low has to 1016 * be <= fs->ehi. Of course, in order for this to happen low has 1017 * to be equal to the current fs->ehi _and_ a snapshot has to 1018 * run right now. This is a small enough window that I don't care. 1019 */ 1020 if(n != 0 && !force){ 1021 consPrint("\tnot setting low epoch\n"); 1022 return 1; 1023 } 1024 old = fs->elo; 1025 if(!fsEpochLow(fs, low)) 1026 consPrint("\tfsEpochLow: %R\n"); 1027 else{ 1028 consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old); 1029 consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo); 1030 if(fs->elo < low) 1031 consPrint("\twarning: new low epoch < old low epoch\n"); 1032 if(force && remove) 1033 fsSnapshotRemove(fs); 1034 } 1035 1036 return 1; 1037 } 1038 1039 static int 1040 fsysCreate(Fsys* fsys, int argc, char* argv[]) 1041 { 1042 int r; 1043 ulong mode; 1044 char *elem, *p, *path; 1045 char *usage = "usage: [fsys name] create path uid gid perm"; 1046 DirEntry de; 1047 File *file, *parent; 1048 1049 ARGBEGIN{ 1050 default: 1051 return cliError(usage); 1052 }ARGEND 1053 if(argc != 4) 1054 return cliError(usage); 1055 1056 if(!fsysParseMode(argv[3], &mode)) 1057 return cliError(usage); 1058 if(mode&ModeSnapshot) 1059 return cliError("create - cannot create with snapshot bit set"); 1060 1061 if(strcmp(argv[1], uidnoworld) == 0) 1062 return cliError("permission denied"); 1063 1064 vtRLock(fsys->fs->elk); 1065 path = vtStrDup(argv[0]); 1066 if((p = strrchr(path, '/')) != nil){ 1067 *p++ = '\0'; 1068 elem = p; 1069 p = path; 1070 if(*p == '\0') 1071 p = "/"; 1072 } 1073 else{ 1074 p = "/"; 1075 elem = path; 1076 } 1077 1078 r = 0; 1079 if((parent = fileOpen(fsys->fs, p)) == nil) 1080 goto out; 1081 1082 file = fileCreate(parent, elem, mode, argv[1]); 1083 fileDecRef(parent); 1084 if(file == nil){ 1085 vtSetError("create %s/%s: %R", p, elem); 1086 goto out; 1087 } 1088 1089 if(!fileGetDir(file, &de)){ 1090 vtSetError("stat failed after create: %R"); 1091 goto out1; 1092 } 1093 1094 if(strcmp(de.gid, argv[2]) != 0){ 1095 vtMemFree(de.gid); 1096 de.gid = vtStrDup(argv[2]); 1097 if(!fileSetDir(file, &de, argv[1])){ 1098 vtSetError("wstat failed after create: %R"); 1099 goto out2; 1100 } 1101 } 1102 r = 1; 1103 1104 out2: 1105 deCleanup(&de); 1106 out1: 1107 fileDecRef(file); 1108 out: 1109 vtMemFree(path); 1110 vtRUnlock(fsys->fs->elk); 1111 1112 return r; 1113 } 1114 1115 static void 1116 fsysPrintStat(char *prefix, char *file, DirEntry *de) 1117 { 1118 char buf[64]; 1119 1120 if(prefix == nil) 1121 prefix = ""; 1122 consPrint("%sstat %q %q %q %q %s %llud\n", prefix, 1123 file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size); 1124 } 1125 1126 static int 1127 fsysStat(Fsys* fsys, int argc, char* argv[]) 1128 { 1129 int i; 1130 File *f; 1131 DirEntry de; 1132 char *usage = "usage: [fsys name] stat files..."; 1133 1134 ARGBEGIN{ 1135 default: 1136 return cliError(usage); 1137 }ARGEND 1138 1139 if(argc == 0) 1140 return cliError(usage); 1141 1142 vtRLock(fsys->fs->elk); 1143 for(i=0; i<argc; i++){ 1144 if((f = fileOpen(fsys->fs, argv[i])) == nil){ 1145 consPrint("%s: %R\n"); 1146 continue; 1147 } 1148 if(!fileGetDir(f, &de)){ 1149 consPrint("%s: %R\n"); 1150 fileDecRef(f); 1151 continue; 1152 } 1153 fsysPrintStat("\t", argv[i], &de); 1154 deCleanup(&de); 1155 fileDecRef(f); 1156 } 1157 vtRUnlock(fsys->fs->elk); 1158 return 1; 1159 } 1160 1161 static int 1162 fsysWstat(Fsys *fsys, int argc, char* argv[]) 1163 { 1164 File *f; 1165 char *p; 1166 DirEntry de; 1167 char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n" 1168 "\tuse - for any field to mean don't change"; 1169 1170 ARGBEGIN{ 1171 default: 1172 return cliError(usage); 1173 }ARGEND 1174 1175 if(argc != 6) 1176 return cliError(usage); 1177 1178 vtRLock(fsys->fs->elk); 1179 if((f = fileOpen(fsys->fs, argv[0])) == nil){ 1180 vtSetError("console wstat - walk - %R"); 1181 vtRUnlock(fsys->fs->elk); 1182 return 0; 1183 } 1184 if(!fileGetDir(f, &de)){ 1185 vtSetError("console wstat - stat - %R"); 1186 fileDecRef(f); 1187 vtRUnlock(fsys->fs->elk); 1188 return 0; 1189 } 1190 fsysPrintStat("\told: w", argv[0], &de); 1191 1192 if(strcmp(argv[1], "-") != 0){ 1193 if(!validFileName(argv[1])){ 1194 vtSetError("console wstat - bad elem"); 1195 goto error; 1196 } 1197 vtMemFree(de.elem); 1198 de.elem = vtStrDup(argv[1]); 1199 } 1200 if(strcmp(argv[2], "-") != 0){ 1201 if(!validUserName(argv[2])){ 1202 vtSetError("console wstat - bad uid"); 1203 goto error; 1204 } 1205 vtMemFree(de.uid); 1206 de.uid = vtStrDup(argv[2]); 1207 } 1208 if(strcmp(argv[3], "-") != 0){ 1209 if(!validUserName(argv[3])){ 1210 vtSetError("console wstat - bad gid"); 1211 goto error; 1212 } 1213 vtMemFree(de.gid); 1214 de.gid = vtStrDup(argv[3]); 1215 } 1216 if(strcmp(argv[4], "-") != 0){ 1217 if(!fsysParseMode(argv[4], &de.mode)){ 1218 vtSetError("console wstat - bad mode"); 1219 goto error; 1220 } 1221 } 1222 if(strcmp(argv[5], "-") != 0){ 1223 de.size = strtoull(argv[5], &p, 0); 1224 if(argv[5][0] == '\0' || *p != '\0' || de.size < 0){ 1225 vtSetError("console wstat - bad length"); 1226 goto error; 1227 } 1228 } 1229 1230 if(!fileSetDir(f, &de, uidadm)){ 1231 vtSetError("console wstat - %R"); 1232 goto error; 1233 } 1234 deCleanup(&de); 1235 1236 if(!fileGetDir(f, &de)){ 1237 vtSetError("console wstat - stat2 - %R"); 1238 goto error; 1239 } 1240 fsysPrintStat("\tnew: w", argv[0], &de); 1241 deCleanup(&de); 1242 fileDecRef(f); 1243 vtRUnlock(fsys->fs->elk); 1244 1245 return 1; 1246 1247 error: 1248 deCleanup(&de); /* okay to do this twice */ 1249 fileDecRef(f); 1250 vtRUnlock(fsys->fs->elk); 1251 return 0; 1252 } 1253 1254 static void 1255 fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b) 1256 { 1257 USED(name); 1258 1259 if((fsck->flags&DoClri) == 0) 1260 return; 1261 1262 mbDelete(mb, i); 1263 mbPack(mb); 1264 blockDirty(b); 1265 } 1266 1267 static void 1268 fsckClose(Fsck *fsck, Block *b, u32int epoch) 1269 { 1270 Label l; 1271 1272 if((fsck->flags&DoClose) == 0) 1273 return; 1274 l = b->l; 1275 if(l.state == BsFree || (l.state&BsClosed)){ 1276 consPrint("%#ux is already closed\n", b->addr); 1277 return; 1278 } 1279 if(epoch){ 1280 l.state |= BsClosed; 1281 l.epochClose = epoch; 1282 }else 1283 l.state = BsFree; 1284 1285 if(!blockSetLabel(b, &l, 0)) 1286 consPrint("%#ux setlabel: %R\n", b->addr); 1287 } 1288 1289 static void 1290 fsckClre(Fsck *fsck, Block *b, int offset) 1291 { 1292 Entry e; 1293 1294 if((fsck->flags&DoClre) == 0) 1295 return; 1296 if(offset<0 || offset*VtEntrySize >= fsck->bsize){ 1297 consPrint("bad clre\n"); 1298 return; 1299 } 1300 memset(&e, 0, sizeof e); 1301 entryPack(&e, b->data, offset); 1302 blockDirty(b); 1303 } 1304 1305 static void 1306 fsckClrp(Fsck *fsck, Block *b, int offset) 1307 { 1308 if((fsck->flags&DoClrp) == 0) 1309 return; 1310 if(offset<0 || offset*VtScoreSize >= fsck->bsize){ 1311 consPrint("bad clre\n"); 1312 return; 1313 } 1314 memmove(b->data+offset*VtScoreSize, vtZeroScore, VtScoreSize); 1315 blockDirty(b); 1316 } 1317 1318 static int 1319 fsysCheck(Fsys *fsys, int argc, char *argv[]) 1320 { 1321 int i, halting; 1322 char *usage = "usage: [fsys name] check [-v] [options]"; 1323 Fsck fsck; 1324 Block *b; 1325 Super super; 1326 1327 memset(&fsck, 0, sizeof fsck); 1328 fsck.fs = fsys->fs; 1329 fsck.clri = fsckClri; 1330 fsck.clre = fsckClre; 1331 fsck.clrp = fsckClrp; 1332 fsck.close = fsckClose; 1333 fsck.print = consPrint; 1334 1335 ARGBEGIN{ 1336 default: 1337 return cliError(usage); 1338 }ARGEND 1339 1340 for(i=0; i<argc; i++){ 1341 if(strcmp(argv[i], "pblock") == 0) 1342 fsck.printblocks = 1; 1343 else if(strcmp(argv[i], "pdir") == 0) 1344 fsck.printdirs = 1; 1345 else if(strcmp(argv[i], "pfile") == 0) 1346 fsck.printfiles = 1; 1347 else if(strcmp(argv[i], "bclose") == 0) 1348 fsck.flags |= DoClose; 1349 else if(strcmp(argv[i], "clri") == 0) 1350 fsck.flags |= DoClri; 1351 else if(strcmp(argv[i], "clre") == 0) 1352 fsck.flags |= DoClre; 1353 else if(strcmp(argv[i], "clrp") == 0) 1354 fsck.flags |= DoClrp; 1355 else if(strcmp(argv[i], "fix") == 0) 1356 fsck.flags |= DoClose|DoClri|DoClre|DoClrp; 1357 else if(strcmp(argv[i], "venti") == 0) 1358 fsck.useventi = 1; 1359 else if(strcmp(argv[i], "snapshot") == 0) 1360 fsck.walksnapshots = 1; 1361 else{ 1362 consPrint("unknown option '%s'\n", argv[i]); 1363 return cliError(usage); 1364 } 1365 } 1366 1367 halting = fsys->fs->halted==0; 1368 if(halting) 1369 fsHalt(fsys->fs); 1370 if(fsys->fs->arch){ 1371 b = superGet(fsys->fs->cache, &super); 1372 if(b == nil){ 1373 consPrint("could not load super block\n"); 1374 goto Out; 1375 } 1376 blockPut(b); 1377 if(super.current != NilBlock){ 1378 consPrint("cannot check fs while archiver is running; wait for it to finish\n"); 1379 goto Out; 1380 } 1381 } 1382 fsCheck(&fsck); 1383 consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n", 1384 fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose); 1385 Out: 1386 if(halting) 1387 fsUnhalt(fsys->fs); 1388 return 1; 1389 } 1390 1391 static int 1392 fsysVenti(char* name, int argc, char* argv[]) 1393 { 1394 int r; 1395 char *host; 1396 char *usage = "usage: [fsys name] venti [address]"; 1397 Fsys *fsys; 1398 1399 ARGBEGIN{ 1400 default: 1401 return cliError(usage); 1402 }ARGEND 1403 1404 if(argc == 0) 1405 host = nil; 1406 else if(argc == 1) 1407 host = argv[0]; 1408 else 1409 return cliError(usage); 1410 1411 if((fsys = _fsysGet(name)) == nil) 1412 return 0; 1413 1414 vtLock(fsys->lock); 1415 if(host == nil) 1416 host = fsys->venti; 1417 else{ 1418 vtMemFree(fsys->venti); 1419 if(host[0]) 1420 fsys->venti = vtStrDup(host); 1421 else{ 1422 host = nil; 1423 fsys->venti = nil; 1424 } 1425 } 1426 1427 /* already open: do a redial */ 1428 if(fsys->fs != nil){ 1429 if(fsys->session == nil){ 1430 vtSetError("file system was opened with -V"); 1431 r = 0; 1432 goto out; 1433 } 1434 r = 1; 1435 if(!vtRedial(fsys->session, host) 1436 || !vtConnect(fsys->session, 0)) 1437 r = 0; 1438 goto out; 1439 } 1440 1441 /* not yet open: try to dial */ 1442 if(fsys->session) 1443 vtClose(fsys->session); 1444 r = 1; 1445 if((fsys->session = vtDial(host, 0)) == nil 1446 || !vtConnect(fsys->session, 0)) 1447 r = 0; 1448 out: 1449 vtUnlock(fsys->lock); 1450 fsysPut(fsys); 1451 return r; 1452 } 1453 1454 static int 1455 fsysOpen(char* name, int argc, char* argv[]) 1456 { 1457 char *p, *host; 1458 Fsys *fsys; 1459 long ncache; 1460 int noauth, noventi, noperm, rflag, wstatallow; 1461 char *usage = "usage: fsys name open [-APVWr] [-c ncache]"; 1462 1463 ncache = 1000; 1464 noauth = noperm = wstatallow = noventi = 0; 1465 rflag = OReadWrite; 1466 1467 ARGBEGIN{ 1468 default: 1469 return cliError(usage); 1470 case 'A': 1471 noauth = 1; 1472 break; 1473 case 'P': 1474 noperm = 1; 1475 break; 1476 case 'V': 1477 noventi = 1; 1478 break; 1479 case 'W': 1480 wstatallow = 1; 1481 break; 1482 case 'c': 1483 p = ARGF(); 1484 if(p == nil) 1485 return cliError(usage); 1486 ncache = strtol(argv[0], &p, 0); 1487 if(ncache <= 0 || p == argv[0] || *p != '\0') 1488 return cliError(usage); 1489 break; 1490 case 'r': 1491 rflag = OReadOnly; 1492 break; 1493 }ARGEND 1494 if(argc) 1495 return cliError(usage); 1496 1497 if((fsys = _fsysGet(name)) == nil) 1498 return 0; 1499 1500 vtLock(fsys->lock); 1501 if(fsys->fs != nil){ 1502 vtSetError(EFsysBusy, fsys->name); 1503 vtUnlock(fsys->lock); 1504 fsysPut(fsys); 1505 return 0; 1506 } 1507 1508 if(noventi){ 1509 if(fsys->session){ 1510 vtClose(fsys->session); 1511 fsys->session = nil; 1512 } 1513 } 1514 else if(fsys->session == nil){ 1515 if(fsys->venti && fsys->venti[0]) 1516 host = fsys->venti; 1517 else 1518 host = nil; 1519 fsys->session = vtDial(host, 1); 1520 if(!vtConnect(fsys->session, nil) && !noventi) 1521 fprint(2, "warning: connecting to venti: %R\n"); 1522 } 1523 if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){ 1524 vtSetError("fsOpen: %R"); 1525 vtUnlock(fsys->lock); 1526 fsysPut(fsys); 1527 return 0; 1528 } 1529 fsys->noauth = noauth; 1530 fsys->noperm = noperm; 1531 fsys->wstatallow = wstatallow; 1532 vtUnlock(fsys->lock); 1533 fsysPut(fsys); 1534 1535 if(strcmp(name, "main") == 0) 1536 usersFileRead(nil); 1537 1538 return 1; 1539 } 1540 1541 static int 1542 fsysUnconfig(char* name, int argc, char* argv[]) 1543 { 1544 Fsys *fsys, **fp; 1545 char *usage = "usage: fsys name unconfig"; 1546 1547 ARGBEGIN{ 1548 default: 1549 return cliError(usage); 1550 }ARGEND 1551 if(argc) 1552 return cliError(usage); 1553 1554 vtLock(sbox.lock); 1555 fp = &sbox.head; 1556 for(fsys = *fp; fsys != nil; fsys = fsys->next){ 1557 if(strcmp(fsys->name, name) == 0) 1558 break; 1559 fp = &fsys->next; 1560 } 1561 if(fsys == nil){ 1562 vtSetError(EFsysNotFound, name); 1563 vtUnlock(sbox.lock); 1564 return 0; 1565 } 1566 if(fsys->ref != 0 || fsys->fs != nil){ 1567 vtSetError(EFsysBusy, fsys->name); 1568 vtUnlock(sbox.lock); 1569 return 0; 1570 } 1571 *fp = fsys->next; 1572 vtUnlock(sbox.lock); 1573 1574 if(fsys->session != nil){ 1575 vtClose(fsys->session); 1576 vtFree(fsys->session); 1577 } 1578 if(fsys->venti != nil) 1579 vtMemFree(fsys->venti); 1580 if(fsys->dev != nil) 1581 vtMemFree(fsys->dev); 1582 if(fsys->name != nil) 1583 vtMemFree(fsys->name); 1584 vtMemFree(fsys); 1585 1586 return 1; 1587 } 1588 1589 static int 1590 fsysConfig(char* name, int argc, char* argv[]) 1591 { 1592 Fsys *fsys; 1593 char *usage = "usage: fsys name config dev"; 1594 1595 ARGBEGIN{ 1596 default: 1597 return cliError(usage); 1598 }ARGEND 1599 if(argc != 1) 1600 return cliError(usage); 1601 1602 if((fsys = _fsysGet(argv[0])) != nil){ 1603 vtLock(fsys->lock); 1604 if(fsys->fs != nil){ 1605 vtSetError(EFsysBusy, fsys->name); 1606 vtUnlock(fsys->lock); 1607 fsysPut(fsys); 1608 return 0; 1609 } 1610 vtMemFree(fsys->dev); 1611 fsys->dev = vtStrDup(argv[0]); 1612 vtUnlock(fsys->lock); 1613 } 1614 else if((fsys = fsysAlloc(name, argv[0])) == nil) 1615 return 0; 1616 1617 fsysPut(fsys); 1618 1619 return 1; 1620 } 1621 1622 static struct { 1623 char* cmd; 1624 int (*f)(Fsys*, int, char**); 1625 int (*f1)(char*, int, char**); 1626 } fsyscmd[] = { 1627 { "close", fsysClose, }, 1628 { "config", nil, fsysConfig, }, 1629 { "open", nil, fsysOpen, }, 1630 { "unconfig", nil, fsysUnconfig, }, 1631 { "venti", nil, fsysVenti, }, 1632 1633 { "bfree", fsysBfree, }, 1634 { "block", fsysBlock, }, 1635 { "check", fsysCheck, }, 1636 { "clre", fsysClre, }, 1637 { "clri", fsysClri, }, 1638 { "clrp", fsysClrp, }, 1639 { "create", fsysCreate, }, 1640 { "df", fsysDf, }, 1641 { "epoch", fsysEpoch, }, 1642 { "halt", fsysHalt, }, 1643 { "label", fsysLabel, }, 1644 { "remove", fsysRemove, }, 1645 { "snap", fsysSnap, }, 1646 { "snaptime", fsysSnapTime, }, 1647 { "snapclean", fsysSnapClean, }, 1648 { "stat", fsysStat, }, 1649 { "sync", fsysSync, }, 1650 { "unhalt", fsysUnhalt, }, 1651 { "wstat", fsysWstat, }, 1652 { "vac", fsysVac, }, 1653 1654 { nil, nil, }, 1655 }; 1656 1657 static int 1658 fsysXXX1(Fsys *fsys, int i, int argc, char* argv[]) 1659 { 1660 int r; 1661 1662 vtLock(fsys->lock); 1663 if(fsys->fs == nil){ 1664 vtUnlock(fsys->lock); 1665 vtSetError(EFsysNotOpen, fsys->name); 1666 return 0; 1667 } 1668 1669 if(fsys->fs->halted 1670 && fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){ 1671 vtSetError("file system %s is halted", fsys->name); 1672 vtUnlock(fsys->lock); 1673 return 0; 1674 } 1675 1676 r = (*fsyscmd[i].f)(fsys, argc, argv); 1677 vtUnlock(fsys->lock); 1678 return r; 1679 } 1680 1681 static int 1682 fsysXXX(char* name, int argc, char* argv[]) 1683 { 1684 int i, r; 1685 Fsys *fsys; 1686 1687 for(i = 0; fsyscmd[i].cmd != nil; i++){ 1688 if(strcmp(fsyscmd[i].cmd, argv[0]) == 0) 1689 break; 1690 } 1691 1692 if(fsyscmd[i].cmd == nil){ 1693 vtSetError("unknown command - '%s'", argv[0]); 1694 return 0; 1695 } 1696 1697 /* some commands want the name... */ 1698 if(fsyscmd[i].f1 != nil){ 1699 if(strcmp(name, FsysAll) == 0){ 1700 vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]); 1701 return 0; 1702 } 1703 return (*fsyscmd[i].f1)(name, argc, argv); 1704 } 1705 1706 /* ... but most commands want the Fsys */ 1707 if(strcmp(name, FsysAll) == 0){ 1708 r = 1; 1709 vtRLock(sbox.lock); 1710 for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ 1711 fsys->ref++; 1712 r = fsysXXX1(fsys, i, argc, argv) && r; 1713 fsys->ref--; 1714 } 1715 vtRUnlock(sbox.lock); 1716 }else{ 1717 if((fsys = _fsysGet(name)) == nil) 1718 return 0; 1719 r = fsysXXX1(fsys, i, argc, argv); 1720 fsysPut(fsys); 1721 } 1722 return r; 1723 } 1724 1725 static int 1726 cmdFsysXXX(int argc, char* argv[]) 1727 { 1728 char *name; 1729 1730 if((name = sbox.curfsys) == nil){ 1731 vtSetError(EFsysNoCurrent, argv[0]); 1732 return 0; 1733 } 1734 1735 return fsysXXX(name, argc, argv); 1736 } 1737 1738 static int 1739 cmdFsys(int argc, char* argv[]) 1740 { 1741 Fsys *fsys; 1742 char *usage = "usage: fsys [name ...]"; 1743 1744 ARGBEGIN{ 1745 default: 1746 return cliError(usage); 1747 }ARGEND 1748 1749 if(argc == 0){ 1750 vtRLock(sbox.lock); 1751 for(fsys = sbox.head; fsys != nil; fsys = fsys->next) 1752 consPrint("\t%s\n", fsys->name); 1753 vtRUnlock(sbox.lock); 1754 return 1; 1755 } 1756 if(argc == 1){ 1757 fsys = nil; 1758 if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil) 1759 return 0; 1760 sbox.curfsys = vtStrDup(argv[0]); 1761 consPrompt(sbox.curfsys); 1762 if(fsys) 1763 fsysPut(fsys); 1764 return 1; 1765 } 1766 1767 return fsysXXX(argv[0], argc-1, argv+1); 1768 } 1769 1770 int 1771 fsysInit(void) 1772 { 1773 int i; 1774 1775 fmtinstall('H', encodefmt); 1776 fmtinstall('V', scoreFmt); 1777 fmtinstall('R', vtErrFmt); 1778 fmtinstall('L', labelFmt); 1779 1780 sbox.lock = vtLockAlloc(); 1781 1782 cliAddCmd("fsys", cmdFsys); 1783 for(i = 0; fsyscmd[i].cmd != nil; i++){ 1784 if(fsyscmd[i].f != nil) 1785 cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX); 1786 } 1787 /* the venti cmd is special: the fs can be either open or closed */ 1788 cliAddCmd("venti", cmdFsysXXX); 1789 cliAddCmd("printconfig", cmdPrintConfig); 1790 1791 return 1; 1792 } 1793