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