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