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 *
ventihost(char * host)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
prventihost(char * host)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 *
myDial(char * host,int canfail)71 myDial(char *host, int canfail)
72 {
73 prventihost(host);
74 return vtDial(host, canfail);
75 }
76
77 static int
myRedial(VtSession * z,char * host)78 myRedial(VtSession *z, char *host)
79 {
80 prventihost(host);
81 return vtRedial(z, host);
82 }
83
84 static Fsys*
_fsysGet(char * name)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
cmdPrintConfig(int argc,char * argv[])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*
fsysGet(char * name)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*
fsysGetName(Fsys * fsys)151 fsysGetName(Fsys* fsys)
152 {
153 return fsys->name;
154 }
155
156 Fsys*
fsysIncRef(Fsys * 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
fsysPut(Fsys * fsys)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*
fsysGetFs(Fsys * fsys)176 fsysGetFs(Fsys* fsys)
177 {
178 assert(fsys != nil && fsys->fs != nil);
179
180 return fsys->fs;
181 }
182
183 void
fsysFsRlock(Fsys * fsys)184 fsysFsRlock(Fsys* fsys)
185 {
186 vtRLock(fsys->fs->elk);
187 }
188
189 void
fsysFsRUnlock(Fsys * fsys)190 fsysFsRUnlock(Fsys* fsys)
191 {
192 vtRUnlock(fsys->fs->elk);
193 }
194
195 int
fsysNoAuthCheck(Fsys * fsys)196 fsysNoAuthCheck(Fsys* fsys)
197 {
198 return fsys->noauth;
199 }
200
201 int
fsysNoPermCheck(Fsys * fsys)202 fsysNoPermCheck(Fsys* fsys)
203 {
204 return fsys->noperm;
205 }
206
207 int
fsysWstatAllow(Fsys * fsys)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*
fsysModeString(ulong mode,char * buf)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
fsysParseMode(char * s,ulong * mode)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*
fsysGetRoot(Fsys * fsys,char * name)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*
fsysAlloc(char * name,char * dev)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
fsysClose(Fsys * fsys,int argc,char * argv[])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
fsysVac(Fsys * fsys,int argc,char * argv[])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
fsysSnap(Fsys * fsys,int argc,char * argv[])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
fsysSnapClean(Fsys * fsys,int argc,char * argv[])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
fsysSnapTime(Fsys * fsys,int argc,char * argv[])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
fsysSync(Fsys * fsys,int argc,char * argv[])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
fsysHalt(Fsys * fsys,int argc,char * argv[])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
fsysUnhalt(Fsys * fsys,int argc,char * argv[])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
fsysRemove(Fsys * fsys,int argc,char * argv[])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
fsysClri(Fsys * fsys,int argc,char * argv[])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
fsysLabel(Fsys * fsys,int argc,char * argv[])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
fsysBlock(Fsys * fsys,int argc,char * argv[])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
fsysBfree(Fsys * fsys,int argc,char * argv[])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
fsysDf(Fsys * fsys,int argc,char * argv[])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
fsysClrep(Fsys * fsys,int argc,char * argv[],int ch)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
fsysClre(Fsys * fsys,int argc,char * argv[])925 fsysClre(Fsys* fsys, int argc, char* argv[])
926 {
927 return fsysClrep(fsys, argc, argv, 'e');
928 }
929
930 static int
fsysClrp(Fsys * fsys,int argc,char * argv[])931 fsysClrp(Fsys* fsys, int argc, char* argv[])
932 {
933 return fsysClrep(fsys, argc, argv, 'p');
934 }
935
936 static int
fsysEsearch1(File * f,char * s,u32int elo)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
fsysEsearch(Fs * fs,char * path,u32int elo)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
fsysEpoch(Fsys * fsys,int argc,char * argv[])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
fsysCreate(Fsys * fsys,int argc,char * argv[])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
fsysPrintStat(char * prefix,char * file,DirEntry * de)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
fsysStat(Fsys * fsys,int argc,char * argv[])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
fsysWstat(Fsys * fsys,int argc,char * argv[])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
fsckClri(Fsck * fsck,char * name,MetaBlock * mb,int i,Block * b)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
fsckClose(Fsck * fsck,Block * b,u32int epoch)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
fsckClre(Fsck * fsck,Block * b,int offset)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
fsckClrp(Fsck * fsck,Block * b,int offset)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
fsysCheck(Fsys * fsys,int argc,char * argv[])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
fsysVenti(char * name,int argc,char * argv[])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
freemem(void)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
fsysOpen(char * name,int argc,char * argv[])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
fsysUnconfig(char * name,int argc,char * argv[])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
fsysConfig(char * name,int argc,char * argv[])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
fsysXXX1(Fsys * fsys,int i,int argc,char * argv[])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
fsysXXX(char * name,int argc,char * argv[])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
cmdFsysXXX(int argc,char * argv[])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
cmdFsys(int argc,char * argv[])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
fsysInit(void)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