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