Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/fossil/9fsys.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
}