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