xref: /plan9/sys/src/cmd/fossil/9fsys.c (revision 81cf874224a4620dc66ce2d894718f8bb735f81d)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier #include "dat.h"
35e96a66cSDavid du Colombier #include "fns.h"
45e96a66cSDavid du Colombier 
55e96a66cSDavid du Colombier #include "9.h"
65e96a66cSDavid du Colombier 
75e96a66cSDavid du Colombier typedef struct Fsys Fsys;
85e96a66cSDavid du Colombier 
97abd426fSDavid du Colombier struct Fsys {
105e96a66cSDavid du Colombier 	VtLock* lock;
115e96a66cSDavid du Colombier 
125e96a66cSDavid du Colombier 	char*	name;
135e96a66cSDavid du Colombier 	char*	dev;
145e96a66cSDavid du Colombier 	char*	venti;
155e96a66cSDavid du Colombier 
165e96a66cSDavid du Colombier 	Fs*	fs;
175e96a66cSDavid du Colombier 	VtSession* session;
185e96a66cSDavid du Colombier 	int	ref;
195e96a66cSDavid du Colombier 
205e96a66cSDavid du Colombier 	int	noauth;
215e96a66cSDavid du Colombier 	int	noperm;
225e96a66cSDavid du Colombier 	int	wstatallow;
235e96a66cSDavid du Colombier 
245e96a66cSDavid du Colombier 	Fsys*	next;
257abd426fSDavid du Colombier };
265e96a66cSDavid du Colombier 
275e96a66cSDavid du Colombier static struct {
285e96a66cSDavid du Colombier 	VtLock*	lock;
295e96a66cSDavid du Colombier 	Fsys*	head;
305e96a66cSDavid du Colombier 	Fsys*	tail;
315e96a66cSDavid du Colombier 
325e96a66cSDavid du Colombier 	char*	curfsys;
335e96a66cSDavid du Colombier } sbox;
345e96a66cSDavid du Colombier 
355e96a66cSDavid du Colombier static char *_argv0;
365e96a66cSDavid du Colombier #define argv0 _argv0
375e96a66cSDavid du Colombier 
38*81cf8742SDavid du Colombier static char FsysAll[] = "all";
39*81cf8742SDavid du Colombier 
405e96a66cSDavid du Colombier static char EFsysBusy[] = "fsys: '%s' busy";
415e96a66cSDavid du Colombier static char EFsysExists[] = "fsys: '%s' already exists";
425e96a66cSDavid du Colombier static char EFsysNoCurrent[] = "fsys: no current fsys";
435e96a66cSDavid du Colombier static char EFsysNotFound[] = "fsys: '%s' not found";
445e96a66cSDavid du Colombier static char EFsysNotOpen[] = "fsys: '%s' not open";
455e96a66cSDavid du Colombier 
465e96a66cSDavid du Colombier static Fsys*
475e96a66cSDavid du Colombier _fsysGet(char* name)
485e96a66cSDavid du Colombier {
495e96a66cSDavid du Colombier 	Fsys *fsys;
505e96a66cSDavid du Colombier 
515e96a66cSDavid du Colombier 	if(name == nil || name[0] == '\0')
525e96a66cSDavid du Colombier 		name = "main";
535e96a66cSDavid du Colombier 
545e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
555e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
565e96a66cSDavid du Colombier 		if(strcmp(name, fsys->name) == 0){
575e96a66cSDavid du Colombier 			fsys->ref++;
585e96a66cSDavid du Colombier 			break;
595e96a66cSDavid du Colombier 		}
605e96a66cSDavid du Colombier 	}
615e96a66cSDavid du Colombier 	if(fsys == nil)
625e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
635e96a66cSDavid du Colombier 	vtRUnlock(sbox.lock);
645e96a66cSDavid du Colombier 
655e96a66cSDavid du Colombier 	return fsys;
665e96a66cSDavid du Colombier }
675e96a66cSDavid du Colombier 
685e96a66cSDavid du Colombier static int
695e96a66cSDavid du Colombier cmdPrintConfig(int argc, char* argv[])
705e96a66cSDavid du Colombier {
715e96a66cSDavid du Colombier 	Fsys *fsys;
725e96a66cSDavid du Colombier 	char *usage = "usage: printconfig";
735e96a66cSDavid du Colombier 
745e96a66cSDavid du Colombier 	ARGBEGIN{
755e96a66cSDavid du Colombier 	default:
765e96a66cSDavid du Colombier 		return cliError(usage);
775e96a66cSDavid du Colombier 	}ARGEND
785e96a66cSDavid du Colombier 
795e96a66cSDavid du Colombier 	if(argc)
805e96a66cSDavid du Colombier 		return cliError(usage);
815e96a66cSDavid du Colombier 
825e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
835e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
845e96a66cSDavid du Colombier 		consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev);
855e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
865e96a66cSDavid du Colombier 			consPrint("\tfsys %s venti %q\n", fsys->name, fsys->venti);
875e96a66cSDavid du Colombier 	}
885e96a66cSDavid du Colombier 	vtRUnlock(sbox.lock);
895e96a66cSDavid du Colombier 	return 1;
905e96a66cSDavid du Colombier }
915e96a66cSDavid du Colombier 
925e96a66cSDavid du Colombier Fsys*
935e96a66cSDavid du Colombier fsysGet(char* name)
945e96a66cSDavid du Colombier {
955e96a66cSDavid du Colombier 	Fsys *fsys;
965e96a66cSDavid du Colombier 
975e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
985e96a66cSDavid du Colombier 		return nil;
995e96a66cSDavid du Colombier 
1005e96a66cSDavid du Colombier 	vtLock(fsys->lock);
1015e96a66cSDavid du Colombier 	if(fsys->fs == nil){
1025e96a66cSDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
1035e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
1045e96a66cSDavid du Colombier 		fsysPut(fsys);
1055e96a66cSDavid du Colombier 		return nil;
1065e96a66cSDavid du Colombier 	}
1075e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
1085e96a66cSDavid du Colombier 
1095e96a66cSDavid du Colombier 	return fsys;
1105e96a66cSDavid du Colombier }
1115e96a66cSDavid du Colombier 
11261201b97SDavid du Colombier char*
11361201b97SDavid du Colombier fsysGetName(Fsys* fsys)
11461201b97SDavid du Colombier {
11561201b97SDavid du Colombier 	return fsys->name;
11661201b97SDavid du Colombier }
11761201b97SDavid du Colombier 
1185e96a66cSDavid du Colombier Fsys*
1195e96a66cSDavid du Colombier fsysIncRef(Fsys* fsys)
1205e96a66cSDavid du Colombier {
1215e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1225e96a66cSDavid du Colombier 	fsys->ref++;
1235e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1245e96a66cSDavid du Colombier 
1255e96a66cSDavid du Colombier 	return fsys;
1265e96a66cSDavid du Colombier }
1275e96a66cSDavid du Colombier 
1285e96a66cSDavid du Colombier void
1295e96a66cSDavid du Colombier fsysPut(Fsys* fsys)
1305e96a66cSDavid du Colombier {
1315e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1325e96a66cSDavid du Colombier 	assert(fsys->ref > 0);
1335e96a66cSDavid du Colombier 	fsys->ref--;
1345e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1355e96a66cSDavid du Colombier }
1365e96a66cSDavid du Colombier 
1375e96a66cSDavid du Colombier Fs*
1385e96a66cSDavid du Colombier fsysGetFs(Fsys* fsys)
1395e96a66cSDavid du Colombier {
1405e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
1415e96a66cSDavid du Colombier 
1425e96a66cSDavid du Colombier 	return fsys->fs;
1435e96a66cSDavid du Colombier }
1445e96a66cSDavid du Colombier 
1455e96a66cSDavid du Colombier void
1465e96a66cSDavid du Colombier fsysFsRlock(Fsys* fsys)
1475e96a66cSDavid du Colombier {
1485e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
1495e96a66cSDavid du Colombier }
1505e96a66cSDavid du Colombier 
1515e96a66cSDavid du Colombier void
1525e96a66cSDavid du Colombier fsysFsRUnlock(Fsys* fsys)
1535e96a66cSDavid du Colombier {
1545e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
1555e96a66cSDavid du Colombier }
1565e96a66cSDavid du Colombier 
1575e96a66cSDavid du Colombier int
1585e96a66cSDavid du Colombier fsysNoAuthCheck(Fsys* fsys)
1595e96a66cSDavid du Colombier {
1605e96a66cSDavid du Colombier 	return fsys->noauth;
1615e96a66cSDavid du Colombier }
1625e96a66cSDavid du Colombier 
1635e96a66cSDavid du Colombier int
1645e96a66cSDavid du Colombier fsysNoPermCheck(Fsys* fsys)
1655e96a66cSDavid du Colombier {
1665e96a66cSDavid du Colombier 	return fsys->noperm;
1675e96a66cSDavid du Colombier }
1685e96a66cSDavid du Colombier 
1695e96a66cSDavid du Colombier int
1705e96a66cSDavid du Colombier fsysWstatAllow(Fsys* fsys)
1715e96a66cSDavid du Colombier {
1725e96a66cSDavid du Colombier 	return fsys->wstatallow;
1735e96a66cSDavid du Colombier }
1745e96a66cSDavid du Colombier 
1755e96a66cSDavid du Colombier static char modechars[] = "YUGalLdHSATs";
1765e96a66cSDavid du Colombier static ulong modebits[] = {
1775e96a66cSDavid du Colombier 	ModeSticky,
1785e96a66cSDavid du Colombier 	ModeSetUid,
1795e96a66cSDavid du Colombier 	ModeSetGid,
1805e96a66cSDavid du Colombier 	ModeAppend,
1815e96a66cSDavid du Colombier 	ModeExclusive,
1825e96a66cSDavid du Colombier 	ModeLink,
1835e96a66cSDavid du Colombier 	ModeDir,
1845e96a66cSDavid du Colombier 	ModeHidden,
1855e96a66cSDavid du Colombier 	ModeSystem,
1865e96a66cSDavid du Colombier 	ModeArchive,
1875e96a66cSDavid du Colombier 	ModeTemporary,
1885e96a66cSDavid du Colombier 	ModeSnapshot,
1895e96a66cSDavid du Colombier 	0
1905e96a66cSDavid du Colombier };
1915e96a66cSDavid du Colombier 
1925e96a66cSDavid du Colombier char*
1935e96a66cSDavid du Colombier fsysModeString(ulong mode, char *buf)
1945e96a66cSDavid du Colombier {
1955e96a66cSDavid du Colombier 	int i;
1965e96a66cSDavid du Colombier 	char *p;
1975e96a66cSDavid du Colombier 
1985e96a66cSDavid du Colombier 	p = buf;
1995e96a66cSDavid du Colombier 	for(i=0; modebits[i]; i++)
2005e96a66cSDavid du Colombier 		if(mode & modebits[i])
2015e96a66cSDavid du Colombier 			*p++ = modechars[i];
2025e96a66cSDavid du Colombier 	sprint(p, "%luo", mode&0777);
2035e96a66cSDavid du Colombier 	return buf;
2045e96a66cSDavid du Colombier }
2055e96a66cSDavid du Colombier 
2065e96a66cSDavid du Colombier int
2075e96a66cSDavid du Colombier fsysParseMode(char* s, ulong* mode)
2085e96a66cSDavid du Colombier {
2095e96a66cSDavid du Colombier 	ulong x, y;
2105e96a66cSDavid du Colombier 	char *p;
2115e96a66cSDavid du Colombier 
2125e96a66cSDavid du Colombier 	x = 0;
2135e96a66cSDavid du Colombier 	for(; *s < '0' || *s > '9'; s++){
2145e96a66cSDavid du Colombier 		if(*s == 0)
2155e96a66cSDavid du Colombier 			return 0;
2165e96a66cSDavid du Colombier 		p = strchr(modechars, *s);
2175e96a66cSDavid du Colombier 		if(p == nil)
2185e96a66cSDavid du Colombier 			return 0;
2195e96a66cSDavid du Colombier 		x |= modebits[p-modechars];
2205e96a66cSDavid du Colombier 	}
2215e96a66cSDavid du Colombier 	y = strtoul(s, &p, 8);
2225e96a66cSDavid du Colombier 	if(*p != '\0' || y > 0777)
2235e96a66cSDavid du Colombier 		return 0;
2245e96a66cSDavid du Colombier 	*mode = x|y;
2255e96a66cSDavid du Colombier 	return 1;
2265e96a66cSDavid du Colombier }
2275e96a66cSDavid du Colombier 
2285e96a66cSDavid du Colombier File*
2295e96a66cSDavid du Colombier fsysGetRoot(Fsys* fsys, char* name)
2305e96a66cSDavid du Colombier {
2315e96a66cSDavid du Colombier 	File *root, *sub;
2325e96a66cSDavid du Colombier 
2335e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
2345e96a66cSDavid du Colombier 
2355e96a66cSDavid du Colombier 	root = fsGetRoot(fsys->fs);
2365e96a66cSDavid du Colombier 	if(name == nil || strcmp(name, "") == 0)
2375e96a66cSDavid du Colombier 		return root;
2385e96a66cSDavid du Colombier 
2395e96a66cSDavid du Colombier 	sub = fileWalk(root, name);
2405e96a66cSDavid du Colombier 	fileDecRef(root);
2415e96a66cSDavid du Colombier 
2425e96a66cSDavid du Colombier 	return sub;
2435e96a66cSDavid du Colombier }
2445e96a66cSDavid du Colombier 
2455e96a66cSDavid du Colombier static Fsys*
2465e96a66cSDavid du Colombier fsysAlloc(char* name, char* dev)
2475e96a66cSDavid du Colombier {
2485e96a66cSDavid du Colombier 	Fsys *fsys;
2495e96a66cSDavid du Colombier 
2505e96a66cSDavid du Colombier 	vtLock(sbox.lock);
2515e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
2525e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) != 0)
2535e96a66cSDavid du Colombier 			continue;
2545e96a66cSDavid du Colombier 		vtSetError(EFsysExists, name);
2555e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
2565e96a66cSDavid du Colombier 		return nil;
2575e96a66cSDavid du Colombier 	}
2585e96a66cSDavid du Colombier 
2595e96a66cSDavid du Colombier 	fsys = vtMemAllocZ(sizeof(Fsys));
2605e96a66cSDavid du Colombier 	fsys->lock = vtLockAlloc();
2615e96a66cSDavid du Colombier 	fsys->name = vtStrDup(name);
2625e96a66cSDavid du Colombier 	fsys->dev = vtStrDup(dev);
2635e96a66cSDavid du Colombier 
2645e96a66cSDavid du Colombier 	fsys->ref = 1;
2655e96a66cSDavid du Colombier 
2665e96a66cSDavid du Colombier 	if(sbox.tail != nil)
2675e96a66cSDavid du Colombier 		sbox.tail->next = fsys;
2685e96a66cSDavid du Colombier 	else
2695e96a66cSDavid du Colombier 		sbox.head = fsys;
2705e96a66cSDavid du Colombier 	sbox.tail = fsys;
2715e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
2725e96a66cSDavid du Colombier 
2735e96a66cSDavid du Colombier 	return fsys;
2745e96a66cSDavid du Colombier }
2755e96a66cSDavid du Colombier 
2765e96a66cSDavid du Colombier static int
2775e96a66cSDavid du Colombier fsysClose(Fsys* fsys, int argc, char* argv[])
2785e96a66cSDavid du Colombier {
2795e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] close";
2805e96a66cSDavid du Colombier 
2815e96a66cSDavid du Colombier 	ARGBEGIN{
2825e96a66cSDavid du Colombier 	default:
2835e96a66cSDavid du Colombier 		return cliError(usage);
2845e96a66cSDavid du Colombier 	}ARGEND
2855e96a66cSDavid du Colombier 	if(argc)
2865e96a66cSDavid du Colombier 		return cliError(usage);
2875e96a66cSDavid du Colombier 
2885e96a66cSDavid du Colombier 	return cliError("close isn't working yet; sync and then kill fossil");
2895e96a66cSDavid du Colombier 
2905e96a66cSDavid du Colombier 	/*
2915e96a66cSDavid du Colombier 	 * Oooh. This could be hard. What if fsys->ref != 1?
2925e96a66cSDavid du Colombier 	 * Also, fsClose() either does the job or panics, can we
2935e96a66cSDavid du Colombier 	 * gracefully detect it's still busy?
2945e96a66cSDavid du Colombier 	 *
2955e96a66cSDavid du Colombier 	 * More thought and care needed here.
2965e96a66cSDavid du Colombier 	 */
2975e96a66cSDavid du Colombier 	fsClose(fsys->fs);
2985e96a66cSDavid du Colombier 	fsys->fs = nil;
2995e96a66cSDavid du Colombier 	vtClose(fsys->session);
3005e96a66cSDavid du Colombier 	fsys->session = nil;
3015e96a66cSDavid du Colombier 
3025e96a66cSDavid du Colombier 	if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){
3035e96a66cSDavid du Colombier 		sbox.curfsys = nil;
3045e96a66cSDavid du Colombier 		consPrompt(nil);
3055e96a66cSDavid du Colombier 	}
3065e96a66cSDavid du Colombier 
3075e96a66cSDavid du Colombier 	return 1;
3085e96a66cSDavid du Colombier }
3095e96a66cSDavid du Colombier 
3105e96a66cSDavid du Colombier static int
3115e96a66cSDavid du Colombier fsysVac(Fsys* fsys, int argc, char* argv[])
3125e96a66cSDavid du Colombier {
3135e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
3145e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] vac path";
3155e96a66cSDavid du Colombier 
3165e96a66cSDavid du Colombier 	ARGBEGIN{
3175e96a66cSDavid du Colombier 	default:
3185e96a66cSDavid du Colombier 		return cliError(usage);
3195e96a66cSDavid du Colombier 	}ARGEND
3205e96a66cSDavid du Colombier 	if(argc != 1)
3215e96a66cSDavid du Colombier 		return cliError(usage);
3225e96a66cSDavid du Colombier 
3235e96a66cSDavid du Colombier 	if(!fsVac(fsys->fs, argv[0], score))
3245e96a66cSDavid du Colombier 		return 0;
3255e96a66cSDavid du Colombier 
3265e96a66cSDavid du Colombier 	consPrint("vac:%V\n", score);
3275e96a66cSDavid du Colombier 	return 1;
3285e96a66cSDavid du Colombier }
3295e96a66cSDavid du Colombier 
3305e96a66cSDavid du Colombier static int
3315e96a66cSDavid du Colombier fsysSnap(Fsys* fsys, int argc, char* argv[])
3325e96a66cSDavid du Colombier {
3335e96a66cSDavid du Colombier 	int doarchive;
3345e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] snap [-a]";
3355e96a66cSDavid du Colombier 
3365e96a66cSDavid du Colombier 	doarchive = 0;
3375e96a66cSDavid du Colombier 	ARGBEGIN{
3385e96a66cSDavid du Colombier 	default:
3395e96a66cSDavid du Colombier 		return cliError(usage);
3405e96a66cSDavid du Colombier 	case 'a':
3415e96a66cSDavid du Colombier 		doarchive = 1;
3425e96a66cSDavid du Colombier 		break;
3435e96a66cSDavid du Colombier 	}ARGEND
3445e96a66cSDavid du Colombier 	if(argc)
3455e96a66cSDavid du Colombier 		return cliError(usage);
3465e96a66cSDavid du Colombier 
3475e96a66cSDavid du Colombier 	if(!fsSnapshot(fsys->fs, doarchive))
3485e96a66cSDavid du Colombier 		return 0;
3495e96a66cSDavid du Colombier 
3505e96a66cSDavid du Colombier 	return 1;
3515e96a66cSDavid du Colombier }
3525e96a66cSDavid du Colombier 
3535e96a66cSDavid du Colombier static int
3545e96a66cSDavid du Colombier fsysSnapTime(Fsys* fsys, int argc, char* argv[])
3555e96a66cSDavid du Colombier {
3565e96a66cSDavid du Colombier 	char buf[40], *x;
3575e96a66cSDavid du Colombier 	int hh, mm;
3585e96a66cSDavid du Colombier 	u32int arch, snap;
3595e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s minutes]";
3605e96a66cSDavid du Colombier 
3615e96a66cSDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap);
3625e96a66cSDavid du Colombier 	ARGBEGIN{
3635e96a66cSDavid du Colombier 	case 'a':
3645e96a66cSDavid du Colombier 		x = ARGF();
3655e96a66cSDavid du Colombier 		if(x == nil)
3665e96a66cSDavid du Colombier 			return cliError(usage);
3675e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
3685e96a66cSDavid du Colombier 			arch = ~(u32int)0;
3695e96a66cSDavid du Colombier 			break;
3705e96a66cSDavid du Colombier 		}
3715e96a66cSDavid du Colombier 		if(strlen(x) != 4 || strspn(x, "0123456789") != 4)
3725e96a66cSDavid du Colombier 			return cliError(usage);
3735e96a66cSDavid du Colombier 		hh = (x[0]-'0')*10 + x[1]-'0';
3745e96a66cSDavid du Colombier 		mm = (x[2]-'0')*10 + x[3]-'0';
3755e96a66cSDavid du Colombier 		if(hh >= 24 || mm >= 60)
3765e96a66cSDavid du Colombier 			return cliError(usage);
3775e96a66cSDavid du Colombier 		arch = hh*60+mm;
3785e96a66cSDavid du Colombier 		break;
3795e96a66cSDavid du Colombier 	case 's':
3805e96a66cSDavid du Colombier 		x = ARGF();
3815e96a66cSDavid du Colombier 		if(x == nil)
3825e96a66cSDavid du Colombier 			return cliError(usage);
3835e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
3845e96a66cSDavid du Colombier 			snap = ~(u32int)0;
3855e96a66cSDavid du Colombier 			break;
3865e96a66cSDavid du Colombier 		}
3875e96a66cSDavid du Colombier 		snap = atoi(x);
3885e96a66cSDavid du Colombier 		break;
3895e96a66cSDavid du Colombier 	default:
3905e96a66cSDavid du Colombier 		return cliError(usage);
3915e96a66cSDavid du Colombier 	}ARGEND
3925e96a66cSDavid du Colombier 	if(argc > 0)
3935e96a66cSDavid du Colombier 		return cliError(usage);
3945e96a66cSDavid du Colombier 
3955e96a66cSDavid du Colombier 	snapSetTimes(fsys->fs->snap, arch, snap);
3965e96a66cSDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap);
3975e96a66cSDavid du Colombier 	if(arch != ~(u32int)0)
3985e96a66cSDavid du Colombier 		sprint(buf, "-a %02d%02d", arch/60, arch%60);
3995e96a66cSDavid du Colombier 	else
4005e96a66cSDavid du Colombier 		sprint(buf, "-a none");
4015e96a66cSDavid du Colombier 	if(snap != ~(u32int)0)
4025e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s %d", snap);
4035e96a66cSDavid du Colombier 	else
4045e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s none");
4055e96a66cSDavid du Colombier 	consPrint("\tsnaptime %s\n", buf);
4065e96a66cSDavid du Colombier 	return 1;
4075e96a66cSDavid du Colombier }
4085e96a66cSDavid du Colombier 
4095e96a66cSDavid du Colombier static int
4105e96a66cSDavid du Colombier fsysSync(Fsys* fsys, int argc, char* argv[])
4115e96a66cSDavid du Colombier {
4125e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] sync";
4135e96a66cSDavid du Colombier 
4145e96a66cSDavid du Colombier 	ARGBEGIN{
4155e96a66cSDavid du Colombier 	default:
4165e96a66cSDavid du Colombier 		return cliError(usage);
4175e96a66cSDavid du Colombier 	}ARGEND
4185e96a66cSDavid du Colombier 	if(argc > 0)
4195e96a66cSDavid du Colombier 		return cliError(usage);
4205e96a66cSDavid du Colombier 
4215e96a66cSDavid du Colombier 	fsSync(fsys->fs);
422*81cf8742SDavid du Colombier 	return 1;
423*81cf8742SDavid du Colombier }
4245e96a66cSDavid du Colombier 
425*81cf8742SDavid du Colombier static int
426*81cf8742SDavid du Colombier fsysHalt(Fsys *fsys, int argc, char* argv[])
427*81cf8742SDavid du Colombier {
428*81cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] halt";
429*81cf8742SDavid du Colombier 
430*81cf8742SDavid du Colombier 	ARGBEGIN{
431*81cf8742SDavid du Colombier 	default:
432*81cf8742SDavid du Colombier 		return cliError(usage);
433*81cf8742SDavid du Colombier 	}ARGEND
434*81cf8742SDavid du Colombier 	if(argc > 0)
435*81cf8742SDavid du Colombier 		return cliError(usage);
436*81cf8742SDavid du Colombier 
437*81cf8742SDavid du Colombier 	fsHalt(fsys->fs);
438*81cf8742SDavid du Colombier 	return 1;
439*81cf8742SDavid du Colombier }
440*81cf8742SDavid du Colombier 
441*81cf8742SDavid du Colombier static int
442*81cf8742SDavid du Colombier fsysUnhalt(Fsys *fsys, int argc, char* argv[])
443*81cf8742SDavid du Colombier {
444*81cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] unhalt";
445*81cf8742SDavid du Colombier 
446*81cf8742SDavid du Colombier 	ARGBEGIN{
447*81cf8742SDavid du Colombier 	default:
448*81cf8742SDavid du Colombier 		return cliError(usage);
449*81cf8742SDavid du Colombier 	}ARGEND
450*81cf8742SDavid du Colombier 	if(argc > 0)
451*81cf8742SDavid du Colombier 		return cliError(usage);
452*81cf8742SDavid du Colombier 
453*81cf8742SDavid du Colombier 	if(!fsys->fs->halted)
454*81cf8742SDavid du Colombier 		return cliError("file system %s not halted", fsys->name);
455*81cf8742SDavid du Colombier 
456*81cf8742SDavid du Colombier 	fsUnhalt(fsys->fs);
4575e96a66cSDavid du Colombier 	return 1;
4585e96a66cSDavid du Colombier }
4595e96a66cSDavid du Colombier 
4605e96a66cSDavid du Colombier static int
4615e96a66cSDavid du Colombier fsysRemove(Fsys* fsys, int argc, char* argv[])
4625e96a66cSDavid du Colombier {
4635e96a66cSDavid du Colombier 	File *file;
4645e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] remove path ...";
4655e96a66cSDavid du Colombier 
4665e96a66cSDavid du Colombier 	ARGBEGIN{
4675e96a66cSDavid du Colombier 	default:
4685e96a66cSDavid du Colombier 		return cliError(usage);
4695e96a66cSDavid du Colombier 	}ARGEND
4705e96a66cSDavid du Colombier 	if(argc == 0)
4715e96a66cSDavid du Colombier 		return cliError(usage);
4725e96a66cSDavid du Colombier 
4735e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
4745e96a66cSDavid du Colombier 	while(argc > 0){
4755e96a66cSDavid du Colombier 		if((file = fileOpen(fsys->fs, argv[0])) == nil)
4765e96a66cSDavid du Colombier 			consPrint("%s: %R\n", argv[0]);
4775e96a66cSDavid du Colombier 		else{
4785e96a66cSDavid du Colombier 			if(!fileRemove(file, uidadm))
4795e96a66cSDavid du Colombier 				consPrint("%s: %R\n", argv[0]);
4805e96a66cSDavid du Colombier 			fileDecRef(file);
4815e96a66cSDavid du Colombier 		}
4825e96a66cSDavid du Colombier 		argc--;
4835e96a66cSDavid du Colombier 		argv++;
4845e96a66cSDavid du Colombier 	}
4855e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
4865e96a66cSDavid du Colombier 
4875e96a66cSDavid du Colombier 	return 1;
4885e96a66cSDavid du Colombier }
4895e96a66cSDavid du Colombier 
4905e96a66cSDavid du Colombier static int
4915e96a66cSDavid du Colombier fsysClri(Fsys* fsys, int argc, char* argv[])
4925e96a66cSDavid du Colombier {
4935e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clri path ...";
4945e96a66cSDavid du Colombier 
4955e96a66cSDavid du Colombier 	ARGBEGIN{
4965e96a66cSDavid du Colombier 	default:
4975e96a66cSDavid du Colombier 		return cliError(usage);
4985e96a66cSDavid du Colombier 	}ARGEND
4995e96a66cSDavid du Colombier 	if(argc == 0)
5005e96a66cSDavid du Colombier 		return cliError(usage);
5015e96a66cSDavid du Colombier 
5025e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5035e96a66cSDavid du Colombier 	while(argc > 0){
5045e96a66cSDavid du Colombier 		if(!fileClri(fsys->fs, argv[0], uidadm))
5055e96a66cSDavid du Colombier 			consPrint("clri %s: %R\n", argv[0]);
5065e96a66cSDavid du Colombier 		argc--;
5075e96a66cSDavid du Colombier 		argv++;
5085e96a66cSDavid du Colombier 	}
5095e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
5105e96a66cSDavid du Colombier 
5115e96a66cSDavid du Colombier 	return 1;
5125e96a66cSDavid du Colombier }
5135e96a66cSDavid du Colombier 
5145e96a66cSDavid du Colombier /*
5155e96a66cSDavid du Colombier  * Inspect and edit the labels for blocks on disk.
5165e96a66cSDavid du Colombier  */
5175e96a66cSDavid du Colombier static int
5185e96a66cSDavid du Colombier fsysLabel(Fsys* fsys, int argc, char* argv[])
5195e96a66cSDavid du Colombier {
5205e96a66cSDavid du Colombier 	Fs *fs;
5215e96a66cSDavid du Colombier 	Label l;
5225e96a66cSDavid du Colombier 	int n, r;
5235e96a66cSDavid du Colombier 	u32int addr;
5245e96a66cSDavid du Colombier 	Block *b, *bb;
5255e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]";
5265e96a66cSDavid du Colombier 
5275e96a66cSDavid du Colombier 	ARGBEGIN{
5285e96a66cSDavid du Colombier 	default:
5295e96a66cSDavid du Colombier 		return cliError(usage);
5305e96a66cSDavid du Colombier 	}ARGEND
5315e96a66cSDavid du Colombier 	if(argc != 1 && argc != 6)
5325e96a66cSDavid du Colombier 		return cliError(usage);
5335e96a66cSDavid du Colombier 
5345e96a66cSDavid du Colombier 	r = 0;
5355e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5365e96a66cSDavid du Colombier 
5375e96a66cSDavid du Colombier 	fs = fsys->fs;
5385e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
5395e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
5405e96a66cSDavid du Colombier 	if(b == nil)
5415e96a66cSDavid du Colombier 		goto Out0;
5425e96a66cSDavid du Colombier 
5435e96a66cSDavid du Colombier 	l = b->l;
5445e96a66cSDavid du Colombier 	consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n",
5455e96a66cSDavid du Colombier 		argc==6 ? "old: " : "", addr, l.type, l.state,
5465e96a66cSDavid du Colombier 		l.epoch, l.epochClose, l.tag);
5475e96a66cSDavid du Colombier 
5485e96a66cSDavid du Colombier 	if(argc == 6){
5495e96a66cSDavid du Colombier 		if(strcmp(argv[1], "-") != 0)
5505e96a66cSDavid du Colombier 			l.type = atoi(argv[1]);
5515e96a66cSDavid du Colombier 		if(strcmp(argv[2], "-") != 0)
5525e96a66cSDavid du Colombier 			l.state = atoi(argv[2]);
5535e96a66cSDavid du Colombier 		if(strcmp(argv[3], "-") != 0)
5545e96a66cSDavid du Colombier 			l.epoch = strtoul(argv[3], 0, 0);
5555e96a66cSDavid du Colombier 		if(strcmp(argv[4], "-") != 0)
5565e96a66cSDavid du Colombier 			l.epochClose = strtoul(argv[4], 0, 0);
5575e96a66cSDavid du Colombier 		if(strcmp(argv[5], "-") != 0)
5585e96a66cSDavid du Colombier 			l.tag = strtoul(argv[5], 0, 0);
5595e96a66cSDavid du Colombier 
5605e96a66cSDavid du Colombier 		consPrint("new: label %#ux %ud %ud %ud %ud %#x\n",
5615e96a66cSDavid du Colombier 			addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
5625e96a66cSDavid du Colombier 		bb = _blockSetLabel(b, &l);
5635e96a66cSDavid du Colombier 		if(bb == nil)
5645e96a66cSDavid du Colombier 			goto Out1;
5655e96a66cSDavid du Colombier 		n = 0;
5665e96a66cSDavid du Colombier 		for(;;){
5675e96a66cSDavid du Colombier 			if(blockWrite(bb)){
5685e96a66cSDavid du Colombier 				while(bb->iostate != BioClean){
5695e96a66cSDavid du Colombier 					assert(bb->iostate == BioWriting);
5705e96a66cSDavid du Colombier 					vtSleep(bb->ioready);
5715e96a66cSDavid du Colombier 				}
5725e96a66cSDavid du Colombier 				break;
5735e96a66cSDavid du Colombier 			}
5745e96a66cSDavid du Colombier 			consPrint("blockWrite: %R\n");
5755e96a66cSDavid du Colombier 			if(n++ >= 5){
5765e96a66cSDavid du Colombier 				consPrint("giving up\n");
5775e96a66cSDavid du Colombier 				break;
5785e96a66cSDavid du Colombier 			}
5795e96a66cSDavid du Colombier 			sleep(5*1000);
5805e96a66cSDavid du Colombier 		}
5815e96a66cSDavid du Colombier 		blockPut(bb);
5825e96a66cSDavid du Colombier 	}
5835e96a66cSDavid du Colombier 	r = 1;
5845e96a66cSDavid du Colombier Out1:
5855e96a66cSDavid du Colombier 	blockPut(b);
5865e96a66cSDavid du Colombier Out0:
5875e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
5885e96a66cSDavid du Colombier 
5895e96a66cSDavid du Colombier 	return r;
5905e96a66cSDavid du Colombier }
5915e96a66cSDavid du Colombier 
5925e96a66cSDavid du Colombier /*
5935e96a66cSDavid du Colombier  * Inspect and edit the blocks on disk.
5945e96a66cSDavid du Colombier  */
5955e96a66cSDavid du Colombier static int
5965e96a66cSDavid du Colombier fsysBlock(Fsys* fsys, int argc, char* argv[])
5975e96a66cSDavid du Colombier {
5985e96a66cSDavid du Colombier 	Fs *fs;
5995e96a66cSDavid du Colombier 	char *s;
6005e96a66cSDavid du Colombier 	Block *b;
6015e96a66cSDavid du Colombier 	uchar *buf;
6025e96a66cSDavid du Colombier 	u32int addr;
6035e96a66cSDavid du Colombier 	int c, count, i, offset;
6045e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] block addr offset [count [data]]";
6055e96a66cSDavid du Colombier 
6065e96a66cSDavid du Colombier 	ARGBEGIN{
6075e96a66cSDavid du Colombier 	default:
6085e96a66cSDavid du Colombier 		return cliError(usage);
6095e96a66cSDavid du Colombier 	}ARGEND
6105e96a66cSDavid du Colombier 	if(argc < 2 || argc > 4)
6115e96a66cSDavid du Colombier 		return cliError(usage);
6125e96a66cSDavid du Colombier 
6135e96a66cSDavid du Colombier 	fs = fsys->fs;
6145e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
6155e96a66cSDavid du Colombier 	offset = strtoul(argv[1], 0, 0);
6165e96a66cSDavid du Colombier 	if(offset < 0 || offset >= fs->blockSize){
6175e96a66cSDavid du Colombier 		vtSetError("bad offset");
6185e96a66cSDavid du Colombier 		return 0;
6195e96a66cSDavid du Colombier 	}
6205e96a66cSDavid du Colombier 	if(argc > 2)
6215e96a66cSDavid du Colombier 		count = strtoul(argv[2], 0, 0);
6225e96a66cSDavid du Colombier 	else
6235e96a66cSDavid du Colombier 		count = 100000000;
6245e96a66cSDavid du Colombier 	if(offset+count > fs->blockSize)
6255e96a66cSDavid du Colombier 		count = fs->blockSize - count;
6265e96a66cSDavid du Colombier 
6275e96a66cSDavid du Colombier 	vtRLock(fs->elk);
6285e96a66cSDavid du Colombier 
6295e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
6305e96a66cSDavid du Colombier 	if(b == nil){
6315e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
6325e96a66cSDavid du Colombier 		vtRUnlock(fs->elk);
6335e96a66cSDavid du Colombier 		return 0;
6345e96a66cSDavid du Colombier 	}
6355e96a66cSDavid du Colombier 
6365e96a66cSDavid du Colombier 	consPrint("\t%sblock %#ux %ud %ud %.*H\n",
6375e96a66cSDavid du Colombier 		argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset);
6385e96a66cSDavid du Colombier 
6395e96a66cSDavid du Colombier 	if(argc == 4){
6405e96a66cSDavid du Colombier 		s = argv[3];
6415e96a66cSDavid du Colombier 		if(strlen(s) != 2*count){
6425e96a66cSDavid du Colombier 			vtSetError("bad data count");
6435e96a66cSDavid du Colombier 			goto Out;
6445e96a66cSDavid du Colombier 		}
6455e96a66cSDavid du Colombier 		buf = vtMemAllocZ(count);
6465e96a66cSDavid du Colombier 		for(i = 0; i < count*2; i++){
6475e96a66cSDavid du Colombier 			if(s[i] >= '0' && s[i] <= '9')
6485e96a66cSDavid du Colombier 				c = s[i] - '0';
6495e96a66cSDavid du Colombier 			else if(s[i] >= 'a' && s[i] <= 'f')
6505e96a66cSDavid du Colombier 				c = s[i] - 'a' + 10;
6515e96a66cSDavid du Colombier 			else if(s[i] >= 'A' && s[i] <= 'F')
6525e96a66cSDavid du Colombier 				c = s[i] - 'A' + 10;
6535e96a66cSDavid du Colombier 			else{
6545e96a66cSDavid du Colombier 				vtSetError("bad hex");
6555e96a66cSDavid du Colombier 				vtMemFree(buf);
6565e96a66cSDavid du Colombier 				goto Out;
6575e96a66cSDavid du Colombier 			}
6585e96a66cSDavid du Colombier 			if((i & 1) == 0)
6595e96a66cSDavid du Colombier 				c <<= 4;
6605e96a66cSDavid du Colombier 			buf[i>>1] |= c;
6615e96a66cSDavid du Colombier 		}
6625e96a66cSDavid du Colombier 		memmove(b->data+offset, buf, count);
6635e96a66cSDavid du Colombier 		consPrint("\tnew: block %#ux %ud %ud %.*H\n",
6645e96a66cSDavid du Colombier 			addr, offset, count, count, b->data+offset);
6655e96a66cSDavid du Colombier 		blockDirty(b);
6665e96a66cSDavid du Colombier 	}
6675e96a66cSDavid du Colombier 
6685e96a66cSDavid du Colombier Out:
6695e96a66cSDavid du Colombier 	blockPut(b);
6705e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
6715e96a66cSDavid du Colombier 
6725e96a66cSDavid du Colombier 	return 1;
6735e96a66cSDavid du Colombier }
6745e96a66cSDavid du Colombier 
6755e96a66cSDavid du Colombier /*
6765e96a66cSDavid du Colombier  * Free a disk block.
6775e96a66cSDavid du Colombier  */
6785e96a66cSDavid du Colombier static int
6795e96a66cSDavid du Colombier fsysBfree(Fsys* fsys, int argc, char* argv[])
6805e96a66cSDavid du Colombier {
6815e96a66cSDavid du Colombier 	Fs *fs;
6825e96a66cSDavid du Colombier 	Label l;
6835e96a66cSDavid du Colombier 	char *p;
6845e96a66cSDavid du Colombier 	Block *b;
6855e96a66cSDavid du Colombier 	u32int addr;
6865e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] bfree addr ...";
6875e96a66cSDavid du Colombier 
6885e96a66cSDavid du Colombier 	ARGBEGIN{
6895e96a66cSDavid du Colombier 	default:
6905e96a66cSDavid du Colombier 		return cliError(usage);
6915e96a66cSDavid du Colombier 	}ARGEND
6925e96a66cSDavid du Colombier 	if(argc == 0)
6935e96a66cSDavid du Colombier 		return cliError(usage);
6945e96a66cSDavid du Colombier 
6955e96a66cSDavid du Colombier 	fs = fsys->fs;
6965e96a66cSDavid du Colombier 	vtRLock(fs->elk);
6975e96a66cSDavid du Colombier 	while(argc > 0){
6985e96a66cSDavid du Colombier 		addr = strtoul(argv[0], &p, 0);
6995e96a66cSDavid du Colombier 		if(*p != '\0'){
7005e96a66cSDavid du Colombier 			consPrint("bad address - '%s'\n", addr);
7015e96a66cSDavid du Colombier 			/* syntax error; let's stop */
7025e96a66cSDavid du Colombier 			vtRUnlock(fs->elk);
7035e96a66cSDavid du Colombier 			return 0;
7045e96a66cSDavid du Colombier 		}
7055e96a66cSDavid du Colombier 		b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
7065e96a66cSDavid du Colombier 		if(b == nil){
7075e96a66cSDavid du Colombier 			consPrint("loading %#ux: %R\n", addr);
7085e96a66cSDavid du Colombier 			continue;
7095e96a66cSDavid du Colombier 		}
7105e96a66cSDavid du Colombier 		l = b->l;
7115e96a66cSDavid du Colombier 		consPrint("label %#ux %ud %ud %ud %ud %#x\n",
7125e96a66cSDavid du Colombier 			addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
7135e96a66cSDavid du Colombier 		l.state = BsFree;
7145e96a66cSDavid du Colombier 		l.type = BtMax;
7155e96a66cSDavid du Colombier 		l.tag = 0;
7165e96a66cSDavid du Colombier 		l.epoch = 0;
7175e96a66cSDavid du Colombier 		l.epochClose = 0;
7185e96a66cSDavid du Colombier 		if(!blockSetLabel(b, &l))
7195e96a66cSDavid du Colombier 			consPrint("freeing %#ux: %R\n", addr);
7205e96a66cSDavid du Colombier 		blockPut(b);
7215e96a66cSDavid du Colombier 		argc--;
7225e96a66cSDavid du Colombier 		argv++;
7235e96a66cSDavid du Colombier 	}
7245e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
7255e96a66cSDavid du Colombier 
7265e96a66cSDavid du Colombier 	return 1;
7275e96a66cSDavid du Colombier }
7285e96a66cSDavid du Colombier 
7297abd426fSDavid du Colombier static int
7307abd426fSDavid du Colombier fsysDf(Fsys *fsys, int argc, char* argv[])
7317abd426fSDavid du Colombier {
7327abd426fSDavid du Colombier 	char *usage = "usage: [fsys name] df";
7337abd426fSDavid du Colombier 	u32int used, tot, bsize;
7347abd426fSDavid du Colombier 	Fs *fs;
7357abd426fSDavid du Colombier 
7367abd426fSDavid du Colombier 	ARGBEGIN{
7377abd426fSDavid du Colombier 	default:
7387abd426fSDavid du Colombier 		return cliError(usage);
7397abd426fSDavid du Colombier 	}ARGEND
7407abd426fSDavid du Colombier 	if(argc != 0)
7417abd426fSDavid du Colombier 		return cliError(usage);
7427abd426fSDavid du Colombier 
7437abd426fSDavid du Colombier 	fs = fsys->fs;
7447abd426fSDavid du Colombier 	cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize);
7457abd426fSDavid du Colombier 	consPrint("%lud/%lud blocks used (%,llud/%,llud bytes)\n",
7467abd426fSDavid du Colombier 		used, tot, used*(vlong)bsize, tot*(vlong)bsize);
7477abd426fSDavid du Colombier 	return 1;
7487abd426fSDavid du Colombier }
7497abd426fSDavid du Colombier 
7505e96a66cSDavid du Colombier /*
7515e96a66cSDavid du Colombier  * Zero an entry or a pointer.
7525e96a66cSDavid du Colombier  */
7535e96a66cSDavid du Colombier static int
7545e96a66cSDavid du Colombier fsysClrep(Fsys* fsys, int argc, char* argv[], int ch)
7555e96a66cSDavid du Colombier {
7565e96a66cSDavid du Colombier 	Fs *fs;
7575e96a66cSDavid du Colombier 	Entry e;
7585e96a66cSDavid du Colombier 	Block *b;
7595e96a66cSDavid du Colombier 	u32int addr;
7605e96a66cSDavid du Colombier 	int i, max, offset, sz;
7615e96a66cSDavid du Colombier 	uchar zero[VtEntrySize];
7625e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clr%c addr offset ...";
7635e96a66cSDavid du Colombier 
7645e96a66cSDavid du Colombier 	ARGBEGIN{
7655e96a66cSDavid du Colombier 	default:
7665e96a66cSDavid du Colombier 		return cliError(usage, ch);
7675e96a66cSDavid du Colombier 	}ARGEND
7685e96a66cSDavid du Colombier 	if(argc < 2)
7695e96a66cSDavid du Colombier 		return cliError(usage, ch);
7705e96a66cSDavid du Colombier 
7715e96a66cSDavid du Colombier 	fs = fsys->fs;
7725e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
7735e96a66cSDavid du Colombier 
7745e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
7755e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
7765e96a66cSDavid du Colombier 	if(b == nil){
7775e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
7785e96a66cSDavid du Colombier 	Err:
7795e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
7805e96a66cSDavid du Colombier 		return 0;
7815e96a66cSDavid du Colombier 	}
7825e96a66cSDavid du Colombier 
7835e96a66cSDavid du Colombier 	switch(ch){
7845e96a66cSDavid du Colombier 	default:
7855e96a66cSDavid du Colombier 		vtSetError("clrep");
7865e96a66cSDavid du Colombier 		goto Err;
7875e96a66cSDavid du Colombier 	case 'e':
7885e96a66cSDavid du Colombier 		if(b->l.type != BtDir){
7895e96a66cSDavid du Colombier 			vtSetError("wrong block type");
7905e96a66cSDavid du Colombier 			goto Err;
7915e96a66cSDavid du Colombier 		}
7925e96a66cSDavid du Colombier 		sz = VtEntrySize;
7935e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
7945e96a66cSDavid du Colombier 		entryPack(&e, zero, 0);
7955e96a66cSDavid du Colombier 		break;
7965e96a66cSDavid du Colombier 	case 'p':
7975e96a66cSDavid du Colombier 		if(b->l.type == BtDir || b->l.type == BtData){
7985e96a66cSDavid du Colombier 			vtSetError("wrong block type");
7995e96a66cSDavid du Colombier 			goto Err;
8005e96a66cSDavid du Colombier 		}
8015e96a66cSDavid du Colombier 		sz = VtScoreSize;
8025e96a66cSDavid du Colombier 		memmove(zero, vtZeroScore, VtScoreSize);
8035e96a66cSDavid du Colombier 		break;
8045e96a66cSDavid du Colombier 	}
8055e96a66cSDavid du Colombier 	max = fs->blockSize/sz;
8065e96a66cSDavid du Colombier 
8075e96a66cSDavid du Colombier 	for(i = 1; i < argc; i++){
8085e96a66cSDavid du Colombier 		offset = atoi(argv[i]);
8095e96a66cSDavid du Colombier 		if(offset >= max){
8105e96a66cSDavid du Colombier 			consPrint("\toffset %d too large (>= %d)\n", i, max);
8115e96a66cSDavid du Colombier 			continue;
8125e96a66cSDavid du Colombier 		}
8135e96a66cSDavid du Colombier 		consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz);
8145e96a66cSDavid du Colombier 		memmove(b->data+offset*sz, zero, sz);
8155e96a66cSDavid du Colombier 	}
8165e96a66cSDavid du Colombier 	blockDirty(b);
8175e96a66cSDavid du Colombier 	blockPut(b);
8185e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
8195e96a66cSDavid du Colombier 
8205e96a66cSDavid du Colombier 	return 1;
8215e96a66cSDavid du Colombier }
8225e96a66cSDavid du Colombier 
8235e96a66cSDavid du Colombier static int
8245e96a66cSDavid du Colombier fsysClre(Fsys* fsys, int argc, char* argv[])
8255e96a66cSDavid du Colombier {
8265e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'e');
8275e96a66cSDavid du Colombier }
8285e96a66cSDavid du Colombier 
8295e96a66cSDavid du Colombier static int
8305e96a66cSDavid du Colombier fsysClrp(Fsys* fsys, int argc, char* argv[])
8315e96a66cSDavid du Colombier {
8325e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'p');
8335e96a66cSDavid du Colombier }
8345e96a66cSDavid du Colombier 
8355e96a66cSDavid du Colombier static int
8365e96a66cSDavid du Colombier fsysEsearch1(File* f, char* s, u32int elo)
8375e96a66cSDavid du Colombier {
8385e96a66cSDavid du Colombier 	int n, r;
8395e96a66cSDavid du Colombier 	DirEntry de;
8405e96a66cSDavid du Colombier 	DirEntryEnum *dee;
8415e96a66cSDavid du Colombier 	File *ff;
8425e96a66cSDavid du Colombier 	Entry e, ee;
8435e96a66cSDavid du Colombier 	char *t;
8445e96a66cSDavid du Colombier 
8455e96a66cSDavid du Colombier 	dee = deeOpen(f);
8465e96a66cSDavid du Colombier 	if(dee == nil)
8475e96a66cSDavid du Colombier 		return 0;
8485e96a66cSDavid du Colombier 
8495e96a66cSDavid du Colombier 	n = 0;
8505e96a66cSDavid du Colombier 	for(;;){
8515e96a66cSDavid du Colombier 		r = deeRead(dee, &de);
8525e96a66cSDavid du Colombier 		if(r < 0){
8535e96a66cSDavid du Colombier 			consPrint("\tdeeRead %s/%s: %R\n", s, de.elem);
8545e96a66cSDavid du Colombier 			break;
8555e96a66cSDavid du Colombier 		}
8565e96a66cSDavid du Colombier 		if(r == 0)
8575e96a66cSDavid du Colombier 			break;
8585e96a66cSDavid du Colombier 		if(de.mode & ModeSnapshot){
8595e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
8605e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
8615e96a66cSDavid du Colombier 			else{
8625e96a66cSDavid du Colombier 				if(!fileGetSources(ff, &e, &ee, 0))
8635e96a66cSDavid du Colombier 					consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem);
8645e96a66cSDavid du Colombier 				else if(e.snap != 0 && e.snap < elo){
8655e96a66cSDavid du Colombier 					consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem);
8665e96a66cSDavid du Colombier 					n++;
8675e96a66cSDavid du Colombier 				}
8685e96a66cSDavid du Colombier 				fileDecRef(ff);
8695e96a66cSDavid du Colombier 			}
8705e96a66cSDavid du Colombier 		}
8715e96a66cSDavid du Colombier 		else if(de.mode & ModeDir){
8725e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
8735e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
8745e96a66cSDavid du Colombier 			else{
875f8e525acSDavid du Colombier 				t = smprint("%s/%s", s, de.elem);
8765e96a66cSDavid du Colombier 				n += fsysEsearch1(ff, t, elo);
8775e96a66cSDavid du Colombier 				vtMemFree(t);
8785e96a66cSDavid du Colombier 				fileDecRef(ff);
8795e96a66cSDavid du Colombier 			}
8805e96a66cSDavid du Colombier 		}
8815e96a66cSDavid du Colombier 		deCleanup(&de);
8825e96a66cSDavid du Colombier 		if(r < 0)
8835e96a66cSDavid du Colombier 			break;
8845e96a66cSDavid du Colombier 	}
8855e96a66cSDavid du Colombier 	deeClose(dee);
8865e96a66cSDavid du Colombier 
8875e96a66cSDavid du Colombier 	return n;
8885e96a66cSDavid du Colombier }
8895e96a66cSDavid du Colombier 
8905e96a66cSDavid du Colombier static int
8915e96a66cSDavid du Colombier fsysEsearch(Fs* fs, char* path, u32int elo)
8925e96a66cSDavid du Colombier {
8935e96a66cSDavid du Colombier 	int n;
8945e96a66cSDavid du Colombier 	File *f;
8955e96a66cSDavid du Colombier 	DirEntry de;
8965e96a66cSDavid du Colombier 
8975e96a66cSDavid du Colombier 	f = fileOpen(fs, path);
8985e96a66cSDavid du Colombier 	if(f == nil)
8995e96a66cSDavid du Colombier 		return 0;
9005e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
9015e96a66cSDavid du Colombier 		consPrint("\tfileGetDir %s failed: %R\n", path);
9025e96a66cSDavid du Colombier 		fileDecRef(f);
9035e96a66cSDavid du Colombier 		return 0;
9045e96a66cSDavid du Colombier 	}
9055e96a66cSDavid du Colombier 	if((de.mode & ModeDir) == 0){
9065e96a66cSDavid du Colombier 		fileDecRef(f);
9075e96a66cSDavid du Colombier 		deCleanup(&de);
9085e96a66cSDavid du Colombier 		return 0;
9095e96a66cSDavid du Colombier 	}
9105e96a66cSDavid du Colombier 	deCleanup(&de);
9115e96a66cSDavid du Colombier 	n = fsysEsearch1(f, path, elo);
9125e96a66cSDavid du Colombier 	fileDecRef(f);
9135e96a66cSDavid du Colombier 	return n;
9145e96a66cSDavid du Colombier }
9155e96a66cSDavid du Colombier 
9165e96a66cSDavid du Colombier static int
9175e96a66cSDavid du Colombier fsysEpoch(Fsys* fsys, int argc, char* argv[])
9185e96a66cSDavid du Colombier {
9195e96a66cSDavid du Colombier 	Fs *fs;
9205e96a66cSDavid du Colombier 	int force, n;
9215e96a66cSDavid du Colombier 	u32int low, old;
9225e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] epoch [[-y] low]";
9235e96a66cSDavid du Colombier 
9245e96a66cSDavid du Colombier 	force = 0;
9255e96a66cSDavid du Colombier 	ARGBEGIN{
9265e96a66cSDavid du Colombier 	case 'y':
9275e96a66cSDavid du Colombier 		force = 1;
9285e96a66cSDavid du Colombier 		break;
9295e96a66cSDavid du Colombier 	default:
9305e96a66cSDavid du Colombier 		return cliError(usage);
9315e96a66cSDavid du Colombier 	}ARGEND
9325e96a66cSDavid du Colombier 	if(argc > 1)
9335e96a66cSDavid du Colombier 		return cliError(usage);
9345e96a66cSDavid du Colombier 	if(argc > 0)
9355e96a66cSDavid du Colombier 		low = strtoul(argv[0], 0, 0);
9365e96a66cSDavid du Colombier 	else
9375e96a66cSDavid du Colombier 		low = ~(u32int)0;
9385e96a66cSDavid du Colombier 
9395e96a66cSDavid du Colombier 	fs = fsys->fs;
9405e96a66cSDavid du Colombier 
9415e96a66cSDavid du Colombier 	vtRLock(fs->elk);
9425e96a66cSDavid du Colombier 	consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi);
9435e96a66cSDavid du Colombier 	n = fsysEsearch(fsys->fs, "/archive", low);
9445e96a66cSDavid du Colombier 	n += fsysEsearch(fsys->fs, "/snapshot", low);
9455e96a66cSDavid du Colombier 	consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low);
9465e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
9475e96a66cSDavid du Colombier 
9485e96a66cSDavid du Colombier 	/*
9495e96a66cSDavid du Colombier 	 * There's a small race here -- a new snapshot with epoch < low might
9505e96a66cSDavid du Colombier 	 * get introduced now that we unlocked fs->elk.  Low has to
9515e96a66cSDavid du Colombier 	 * be <= fs->ehi.  Of course, in order for this to happen low has
9525e96a66cSDavid du Colombier 	 * to be equal to the current fs->ehi _and_ a snapshot has to
9535e96a66cSDavid du Colombier 	 * run right now.  This is a small enough window that I don't care.
9545e96a66cSDavid du Colombier 	 */
9555e96a66cSDavid du Colombier 	if(n != 0 && !force){
9565e96a66cSDavid du Colombier 		consPrint("\tnot setting low epoch\n");
9575e96a66cSDavid du Colombier 		return 1;
9585e96a66cSDavid du Colombier 	}
9595e96a66cSDavid du Colombier 	old = fs->elo;
9605e96a66cSDavid du Colombier 	if(!fsEpochLow(fs, low))
9615e96a66cSDavid du Colombier 		consPrint("\tfsEpochLow: %R\n");
9625e96a66cSDavid du Colombier 	else{
9635e96a66cSDavid du Colombier 		consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old);
9645e96a66cSDavid du Colombier 		consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo);
9655e96a66cSDavid du Colombier 		if(fs->elo < low)
9665e96a66cSDavid du Colombier 			consPrint("\twarning: new low epoch < old low epoch\n");
9675e96a66cSDavid du Colombier 	}
9685e96a66cSDavid du Colombier 
9695e96a66cSDavid du Colombier 	return 1;
9705e96a66cSDavid du Colombier }
9715e96a66cSDavid du Colombier 
9725e96a66cSDavid du Colombier static int
9735e96a66cSDavid du Colombier fsysCreate(Fsys* fsys, int argc, char* argv[])
9745e96a66cSDavid du Colombier {
9755e96a66cSDavid du Colombier 	int r;
9765e96a66cSDavid du Colombier 	ulong mode;
9775e96a66cSDavid du Colombier 	char *elem, *p, *path;
9785e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] create path uid gid perm";
9795e96a66cSDavid du Colombier 	DirEntry de;
9805e96a66cSDavid du Colombier 	File *file, *parent;
9815e96a66cSDavid du Colombier 
9825e96a66cSDavid du Colombier 	ARGBEGIN{
9835e96a66cSDavid du Colombier 	default:
9845e96a66cSDavid du Colombier 		return cliError(usage);
9855e96a66cSDavid du Colombier 	}ARGEND
9865e96a66cSDavid du Colombier 	if(argc != 4)
9875e96a66cSDavid du Colombier 		return cliError(usage);
9885e96a66cSDavid du Colombier 
9895e96a66cSDavid du Colombier 	if(!fsysParseMode(argv[3], &mode))
9905e96a66cSDavid du Colombier 		return cliError(usage);
9915e96a66cSDavid du Colombier 	if(mode&ModeSnapshot)
9925e96a66cSDavid du Colombier 		return cliError("create - cannot create with snapshot bit set");
9935e96a66cSDavid du Colombier 
9945e96a66cSDavid du Colombier 	if(strcmp(argv[1], uidnoworld) == 0)
9955e96a66cSDavid du Colombier 		return cliError("permission denied");
9965e96a66cSDavid du Colombier 
9975e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
9985e96a66cSDavid du Colombier 	path = vtStrDup(argv[0]);
9995e96a66cSDavid du Colombier 	if((p = strrchr(path, '/')) != nil){
10005e96a66cSDavid du Colombier 		*p++ = '\0';
10015e96a66cSDavid du Colombier 		elem = p;
10025e96a66cSDavid du Colombier 		p = path;
10035e96a66cSDavid du Colombier 		if(*p == '\0')
10045e96a66cSDavid du Colombier 			p = "/";
10055e96a66cSDavid du Colombier 	}
10065e96a66cSDavid du Colombier 	else{
10075e96a66cSDavid du Colombier 		p = "/";
10085e96a66cSDavid du Colombier 		elem = path;
10095e96a66cSDavid du Colombier 	}
1010f8e525acSDavid du Colombier 
10115e96a66cSDavid du Colombier 	r = 0;
1012f8e525acSDavid du Colombier 	if((parent = fileOpen(fsys->fs, p)) == nil)
1013f8e525acSDavid du Colombier 		goto out;
1014f8e525acSDavid du Colombier 
10155e96a66cSDavid du Colombier 	file = fileCreate(parent, elem, mode, argv[1]);
10165e96a66cSDavid du Colombier 	fileDecRef(parent);
1017f8e525acSDavid du Colombier 	if(file == nil){
1018f8e525acSDavid du Colombier 		vtSetError("create %s/%s: %R", p, elem);
1019f8e525acSDavid du Colombier 		goto out;
1020f8e525acSDavid du Colombier 	}
1021f8e525acSDavid du Colombier 
1022f8e525acSDavid du Colombier 	if(!fileGetDir(file, &de)){
1023f8e525acSDavid du Colombier 		vtSetError("stat failed after create: %R");
1024f8e525acSDavid du Colombier 		goto out1;
1025f8e525acSDavid du Colombier 	}
1026f8e525acSDavid du Colombier 
10275e96a66cSDavid du Colombier 	if(strcmp(de.gid, argv[2]) != 0){
10285e96a66cSDavid du Colombier 		vtMemFree(de.gid);
10295e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[2]);
1030f8e525acSDavid du Colombier 		if(!fileSetDir(file, &de, argv[1])){
1031f8e525acSDavid du Colombier 			vtSetError("wstat failed after create: %R");
1032f8e525acSDavid du Colombier 			goto out2;
10335e96a66cSDavid du Colombier 		}
1034f8e525acSDavid du Colombier 	}
1035f8e525acSDavid du Colombier 	r = 1;
1036f8e525acSDavid du Colombier 
1037f8e525acSDavid du Colombier out2:
10385e96a66cSDavid du Colombier 	deCleanup(&de);
1039f8e525acSDavid du Colombier out1:
10405e96a66cSDavid du Colombier 	fileDecRef(file);
1041f8e525acSDavid du Colombier out:
10425e96a66cSDavid du Colombier 	vtMemFree(path);
10435e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
10445e96a66cSDavid du Colombier 
10455e96a66cSDavid du Colombier 	return r;
10465e96a66cSDavid du Colombier }
10475e96a66cSDavid du Colombier 
10485e96a66cSDavid du Colombier static void
10495e96a66cSDavid du Colombier fsysPrintStat(char *prefix, char *file, DirEntry *de)
10505e96a66cSDavid du Colombier {
10515e96a66cSDavid du Colombier 	char buf[64];
10525e96a66cSDavid du Colombier 
10535e96a66cSDavid du Colombier 	if(prefix == nil)
10545e96a66cSDavid du Colombier 		prefix = "";
10555e96a66cSDavid du Colombier 	consPrint("%sstat %q %q %q %q %s %llud\n", prefix,
10565e96a66cSDavid du Colombier 		file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size);
10575e96a66cSDavid du Colombier }
10585e96a66cSDavid du Colombier 
10595e96a66cSDavid du Colombier static int
10605e96a66cSDavid du Colombier fsysStat(Fsys* fsys, int argc, char* argv[])
10615e96a66cSDavid du Colombier {
10625e96a66cSDavid du Colombier 	int i;
10635e96a66cSDavid du Colombier 	File *f;
10645e96a66cSDavid du Colombier 	DirEntry de;
10655e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] stat files...";
10665e96a66cSDavid du Colombier 
10675e96a66cSDavid du Colombier 	ARGBEGIN{
10685e96a66cSDavid du Colombier 	default:
10695e96a66cSDavid du Colombier 		return cliError(usage);
10705e96a66cSDavid du Colombier 	}ARGEND
10715e96a66cSDavid du Colombier 
10725e96a66cSDavid du Colombier 	if(argc == 0)
10735e96a66cSDavid du Colombier 		return cliError(usage);
10745e96a66cSDavid du Colombier 
10755e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
10765e96a66cSDavid du Colombier 	for(i=0; i<argc; i++){
10775e96a66cSDavid du Colombier 		if((f = fileOpen(fsys->fs, argv[i])) == nil){
10785e96a66cSDavid du Colombier 			consPrint("%s: %R\n");
10795e96a66cSDavid du Colombier 			continue;
10805e96a66cSDavid du Colombier 		}
10815e96a66cSDavid du Colombier 		if(!fileGetDir(f, &de)){
10825e96a66cSDavid du Colombier 			consPrint("%s: %R\n");
10835e96a66cSDavid du Colombier 			fileDecRef(f);
10845e96a66cSDavid du Colombier 			continue;
10855e96a66cSDavid du Colombier 		}
10865e96a66cSDavid du Colombier 		fsysPrintStat("\t", argv[i], &de);
10875e96a66cSDavid du Colombier 		deCleanup(&de);
10885e96a66cSDavid du Colombier 		fileDecRef(f);
10895e96a66cSDavid du Colombier 	}
10905e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
10915e96a66cSDavid du Colombier 	return 1;
10925e96a66cSDavid du Colombier }
10935e96a66cSDavid du Colombier 
10945e96a66cSDavid du Colombier static int
10955e96a66cSDavid du Colombier fsysWstat(Fsys *fsys, int argc, char* argv[])
10965e96a66cSDavid du Colombier {
10975e96a66cSDavid du Colombier 	File *f;
10985e96a66cSDavid du Colombier 	char *p;
10995e96a66cSDavid du Colombier 	DirEntry de;
11005e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n"
11015e96a66cSDavid du Colombier 		"\tuse - for any field to mean don't change";
11025e96a66cSDavid du Colombier 
11035e96a66cSDavid du Colombier 	ARGBEGIN{
11045e96a66cSDavid du Colombier 	default:
11055e96a66cSDavid du Colombier 		return cliError(usage);
11065e96a66cSDavid du Colombier 	}ARGEND
11075e96a66cSDavid du Colombier 
11085e96a66cSDavid du Colombier 	if(argc != 6)
11095e96a66cSDavid du Colombier 		return cliError(usage);
11105e96a66cSDavid du Colombier 
11115e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
11125e96a66cSDavid du Colombier 	if((f = fileOpen(fsys->fs, argv[0])) == nil){
11135e96a66cSDavid du Colombier 		vtSetError("console wstat - walk - %R");
11145e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
11155e96a66cSDavid du Colombier 		return 0;
11165e96a66cSDavid du Colombier 	}
11175e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
11185e96a66cSDavid du Colombier 		vtSetError("console wstat - stat - %R");
11195e96a66cSDavid du Colombier 		fileDecRef(f);
11205e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
11215e96a66cSDavid du Colombier 		return 0;
11225e96a66cSDavid du Colombier 	}
11235e96a66cSDavid du Colombier 	fsysPrintStat("\told: w", argv[0], &de);
11245e96a66cSDavid du Colombier 
11255e96a66cSDavid du Colombier 	if(strcmp(argv[1], "-") != 0){
11265e96a66cSDavid du Colombier 		if(!validFileName(argv[1])){
11275e96a66cSDavid du Colombier 			vtSetError("console wstat - bad elem");
11285e96a66cSDavid du Colombier 			goto error;
11295e96a66cSDavid du Colombier 		}
11305e96a66cSDavid du Colombier 		vtMemFree(de.elem);
11315e96a66cSDavid du Colombier 		de.elem = vtStrDup(argv[1]);
11325e96a66cSDavid du Colombier 	}
11335e96a66cSDavid du Colombier 	if(strcmp(argv[2], "-") != 0){
11345e96a66cSDavid du Colombier 		if(!validUserName(argv[2])){
11355e96a66cSDavid du Colombier 			vtSetError("console wstat - bad uid");
11365e96a66cSDavid du Colombier 			goto error;
11375e96a66cSDavid du Colombier 		}
11385e96a66cSDavid du Colombier 		vtMemFree(de.uid);
11395e96a66cSDavid du Colombier 		de.uid = vtStrDup(argv[2]);
11405e96a66cSDavid du Colombier 	}
11415e96a66cSDavid du Colombier 	if(strcmp(argv[3], "-") != 0){
11425e96a66cSDavid du Colombier 		if(!validUserName(argv[3])){
11435e96a66cSDavid du Colombier 			vtSetError("console wstat - bad gid");
11445e96a66cSDavid du Colombier 			goto error;
11455e96a66cSDavid du Colombier 		}
11465e96a66cSDavid du Colombier 		vtMemFree(de.gid);
11475e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[3]);
11485e96a66cSDavid du Colombier 	}
11495e96a66cSDavid du Colombier 	if(strcmp(argv[4], "-") != 0){
11505e96a66cSDavid du Colombier 		if(!fsysParseMode(argv[4], &de.mode)){
11515e96a66cSDavid du Colombier 			vtSetError("console wstat - bad mode");
11525e96a66cSDavid du Colombier 			goto error;
11535e96a66cSDavid du Colombier 		}
11545e96a66cSDavid du Colombier 	}
11555e96a66cSDavid du Colombier 	if(strcmp(argv[5], "-") != 0){
11565e96a66cSDavid du Colombier 		de.size = strtoull(argv[5], &p, 0);
11575e96a66cSDavid du Colombier 		if(argv[5][0] == '\0' || *p != '\0' || de.size < 0){
11585e96a66cSDavid du Colombier 			vtSetError("console wstat - bad length");
11595e96a66cSDavid du Colombier 			goto error;
11605e96a66cSDavid du Colombier 		}
11615e96a66cSDavid du Colombier 	}
11625e96a66cSDavid du Colombier 
11635e96a66cSDavid du Colombier 	if(!fileSetDir(f, &de, uidadm)){
11645e96a66cSDavid du Colombier 		vtSetError("console wstat - %R");
11655e96a66cSDavid du Colombier 		goto error;
11665e96a66cSDavid du Colombier 	}
11675e96a66cSDavid du Colombier 	deCleanup(&de);
11685e96a66cSDavid du Colombier 
11695e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
11705e96a66cSDavid du Colombier 		vtSetError("console wstat - stat2 - %R");
11715e96a66cSDavid du Colombier 		goto error;
11725e96a66cSDavid du Colombier 	}
11735e96a66cSDavid du Colombier 	fsysPrintStat("\tnew: w", argv[0], &de);
11745e96a66cSDavid du Colombier 	deCleanup(&de);
11755e96a66cSDavid du Colombier 	fileDecRef(f);
11765e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
11775e96a66cSDavid du Colombier 
11785e96a66cSDavid du Colombier 	return 1;
11795e96a66cSDavid du Colombier 
11805e96a66cSDavid du Colombier error:
11815e96a66cSDavid du Colombier 	deCleanup(&de);	/* okay to do this twice */
11825e96a66cSDavid du Colombier 	fileDecRef(f);
11835e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
11845e96a66cSDavid du Colombier 	return 0;
11855e96a66cSDavid du Colombier }
11865e96a66cSDavid du Colombier 
11875e96a66cSDavid du Colombier static int
11885e96a66cSDavid du Colombier fsysVenti(char* name, int argc, char* argv[])
11895e96a66cSDavid du Colombier {
11905e96a66cSDavid du Colombier 	int r;
11915e96a66cSDavid du Colombier 	char *host;
11925e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] venti [address]";
11935e96a66cSDavid du Colombier 	Fsys *fsys;
11945e96a66cSDavid du Colombier 
11955e96a66cSDavid du Colombier 	ARGBEGIN{
11965e96a66cSDavid du Colombier 	default:
11975e96a66cSDavid du Colombier 		return cliError(usage);
11985e96a66cSDavid du Colombier 	}ARGEND
11995e96a66cSDavid du Colombier 
12005e96a66cSDavid du Colombier 	if(argc == 0)
12015e96a66cSDavid du Colombier 		host = nil;
12025e96a66cSDavid du Colombier 	else if(argc == 1)
12035e96a66cSDavid du Colombier 		host = argv[0];
12045e96a66cSDavid du Colombier 	else
12055e96a66cSDavid du Colombier 		return cliError(usage);
12065e96a66cSDavid du Colombier 
12075e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
12085e96a66cSDavid du Colombier 		return 0;
12095e96a66cSDavid du Colombier 
12105e96a66cSDavid du Colombier 	vtLock(fsys->lock);
12115e96a66cSDavid du Colombier 	if(host == nil)
12125e96a66cSDavid du Colombier 		host = fsys->venti;
12135e96a66cSDavid du Colombier 	else{
12145e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
12155e96a66cSDavid du Colombier 		if(host[0])
12165e96a66cSDavid du Colombier 			fsys->venti = vtStrDup(host);
12175e96a66cSDavid du Colombier 		else{
12185e96a66cSDavid du Colombier 			host = nil;
12195e96a66cSDavid du Colombier 			fsys->venti = nil;
12205e96a66cSDavid du Colombier 		}
12215e96a66cSDavid du Colombier 	}
12225e96a66cSDavid du Colombier 
12235e96a66cSDavid du Colombier 	/* already open: do a redial */
12245e96a66cSDavid du Colombier 	if(fsys->fs != nil){
12255e96a66cSDavid du Colombier 		r = 1;
12265e96a66cSDavid du Colombier 		if(!vtRedial(fsys->session, host)
12275e96a66cSDavid du Colombier 		|| !vtConnect(fsys->session, 0))
12285e96a66cSDavid du Colombier 			r = 0;
12295e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
12305e96a66cSDavid du Colombier 		fsysPut(fsys);
12315e96a66cSDavid du Colombier 		return r;
12325e96a66cSDavid du Colombier 	}
12335e96a66cSDavid du Colombier 
12345e96a66cSDavid du Colombier 	/* not yet open: try to dial */
12355e96a66cSDavid du Colombier 	if(fsys->session)
12365e96a66cSDavid du Colombier 		vtClose(fsys->session);
12375e96a66cSDavid du Colombier 	r = 1;
12385e96a66cSDavid du Colombier 	if((fsys->session = vtDial(host, 0)) == nil
12395e96a66cSDavid du Colombier 	|| !vtConnect(fsys->session, 0))
12405e96a66cSDavid du Colombier 		r = 0;
12415e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
12425e96a66cSDavid du Colombier 	fsysPut(fsys);
12435e96a66cSDavid du Colombier 	return r;
12445e96a66cSDavid du Colombier }
12455e96a66cSDavid du Colombier 
12465e96a66cSDavid du Colombier static int
12475e96a66cSDavid du Colombier fsysOpen(char* name, int argc, char* argv[])
12485e96a66cSDavid du Colombier {
12495e96a66cSDavid du Colombier 	char *p, *host;
12505e96a66cSDavid du Colombier 	Fsys *fsys;
12515e96a66cSDavid du Colombier 	long ncache;
12525e96a66cSDavid du Colombier 	int noauth, noperm, rflag, wstatallow;
12535e96a66cSDavid du Colombier 	char *usage = "usage: fsys name open [-APWr] [-c ncache]";
12545e96a66cSDavid du Colombier 
12555e96a66cSDavid du Colombier 	ncache = 1000;
12565e96a66cSDavid du Colombier 	noauth = noperm = wstatallow = 0;
12575e96a66cSDavid du Colombier 	rflag = OReadWrite;
12585e96a66cSDavid du Colombier 
12595e96a66cSDavid du Colombier 	ARGBEGIN{
12605e96a66cSDavid du Colombier 	default:
12615e96a66cSDavid du Colombier 		return cliError(usage);
12625e96a66cSDavid du Colombier 	case 'A':
12635e96a66cSDavid du Colombier 		noauth = 1;
12645e96a66cSDavid du Colombier 		break;
12655e96a66cSDavid du Colombier 	case 'P':
12665e96a66cSDavid du Colombier 		noperm = 1;
12675e96a66cSDavid du Colombier 		break;
12685e96a66cSDavid du Colombier 	case 'W':
12695e96a66cSDavid du Colombier 		wstatallow = 1;
12705e96a66cSDavid du Colombier 		break;
12715e96a66cSDavid du Colombier 	case 'c':
12725e96a66cSDavid du Colombier 		p = ARGF();
12735e96a66cSDavid du Colombier 		if(p == nil)
12745e96a66cSDavid du Colombier 			return cliError(usage);
12755e96a66cSDavid du Colombier 		ncache = strtol(argv[0], &p, 0);
12765e96a66cSDavid du Colombier 		if(ncache <= 0 || p == argv[0] || *p != '\0')
12775e96a66cSDavid du Colombier 			return cliError(usage);
12785e96a66cSDavid du Colombier 		break;
12795e96a66cSDavid du Colombier 	case 'r':
12805e96a66cSDavid du Colombier 		rflag = OReadOnly;
12815e96a66cSDavid du Colombier 		break;
12825e96a66cSDavid du Colombier 	}ARGEND
12835e96a66cSDavid du Colombier 	if(argc)
12845e96a66cSDavid du Colombier 		return cliError(usage);
12855e96a66cSDavid du Colombier 
12865e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
12875e96a66cSDavid du Colombier 		return 0;
12885e96a66cSDavid du Colombier 
12895e96a66cSDavid du Colombier 	vtLock(fsys->lock);
12905e96a66cSDavid du Colombier 	if(fsys->fs != nil){
12915e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
12925e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
12935e96a66cSDavid du Colombier 		fsysPut(fsys);
12945e96a66cSDavid du Colombier 		return 0;
12955e96a66cSDavid du Colombier 	}
12965e96a66cSDavid du Colombier 
12975e96a66cSDavid du Colombier 	if(fsys->session == nil){
12985e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
12995e96a66cSDavid du Colombier 			host = fsys->venti;
13005e96a66cSDavid du Colombier 		else
13015e96a66cSDavid du Colombier 			host = nil;
13025e96a66cSDavid du Colombier 		fsys->session = vtDial(host, 1);
13035e96a66cSDavid du Colombier 		if(!vtConnect(fsys->session, nil))
130461201b97SDavid du Colombier 			fprint(2, "warning: connecting to venti: %R\n");
13055e96a66cSDavid du Colombier 	}
13065e96a66cSDavid du Colombier 	if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
13075e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
13085e96a66cSDavid du Colombier 		fsysPut(fsys);
13095e96a66cSDavid du Colombier 		return 0;
13105e96a66cSDavid du Colombier 	}
13115e96a66cSDavid du Colombier 	fsys->noauth = noauth;
13125e96a66cSDavid du Colombier 	fsys->noperm = noperm;
13135e96a66cSDavid du Colombier 	fsys->wstatallow = wstatallow;
13145e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
13155e96a66cSDavid du Colombier 	fsysPut(fsys);
13165e96a66cSDavid du Colombier 
1317*81cf8742SDavid du Colombier 	if(strcmp(name, "main") == 0)
1318*81cf8742SDavid du Colombier 		usersFileRead(nil);
1319*81cf8742SDavid du Colombier 
13205e96a66cSDavid du Colombier 	return 1;
13215e96a66cSDavid du Colombier }
13225e96a66cSDavid du Colombier 
13235e96a66cSDavid du Colombier static int
13245e96a66cSDavid du Colombier fsysUnconfig(char* name, int argc, char* argv[])
13255e96a66cSDavid du Colombier {
13265e96a66cSDavid du Colombier 	Fsys *fsys, **fp;
13275e96a66cSDavid du Colombier 	char *usage = "usage: fsys name unconfig";
13285e96a66cSDavid du Colombier 
13295e96a66cSDavid du Colombier 	ARGBEGIN{
13305e96a66cSDavid du Colombier 	default:
13315e96a66cSDavid du Colombier 		return cliError(usage);
13325e96a66cSDavid du Colombier 	}ARGEND
13335e96a66cSDavid du Colombier 	if(argc)
13345e96a66cSDavid du Colombier 		return cliError(usage);
13355e96a66cSDavid du Colombier 
13365e96a66cSDavid du Colombier 	vtLock(sbox.lock);
13375e96a66cSDavid du Colombier 	fp = &sbox.head;
13385e96a66cSDavid du Colombier 	for(fsys = *fp; fsys != nil; fsys = fsys->next){
13395e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) == 0)
13405e96a66cSDavid du Colombier 			break;
13415e96a66cSDavid du Colombier 		fp = &fsys->next;
13425e96a66cSDavid du Colombier 	}
13435e96a66cSDavid du Colombier 	if(fsys == nil){
13445e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
13455e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
13465e96a66cSDavid du Colombier 		return 0;
13475e96a66cSDavid du Colombier 	}
13485e96a66cSDavid du Colombier 	if(fsys->ref != 0 || fsys->fs != nil){
13495e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
13505e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
13515e96a66cSDavid du Colombier 		return 0;
13525e96a66cSDavid du Colombier 	}
13535e96a66cSDavid du Colombier 	*fp = fsys->next;
13545e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
13555e96a66cSDavid du Colombier 
13565e96a66cSDavid du Colombier 	if(fsys->session != nil){
13575e96a66cSDavid du Colombier 		vtClose(fsys->session);
13585e96a66cSDavid du Colombier 		vtFree(fsys->session);
13595e96a66cSDavid du Colombier 	}
13605e96a66cSDavid du Colombier 	if(fsys->venti != nil)
13615e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
13625e96a66cSDavid du Colombier 	if(fsys->dev != nil)
13635e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
13645e96a66cSDavid du Colombier 	if(fsys->name != nil)
13655e96a66cSDavid du Colombier 		vtMemFree(fsys->name);
13665e96a66cSDavid du Colombier 	vtMemFree(fsys);
13675e96a66cSDavid du Colombier 
13685e96a66cSDavid du Colombier 	return 1;
13695e96a66cSDavid du Colombier }
13705e96a66cSDavid du Colombier 
13715e96a66cSDavid du Colombier static int
13725e96a66cSDavid du Colombier fsysConfig(char* name, int argc, char* argv[])
13735e96a66cSDavid du Colombier {
13745e96a66cSDavid du Colombier 	Fsys *fsys;
13755e96a66cSDavid du Colombier 	char *usage = "usage: fsys name config dev";
13765e96a66cSDavid du Colombier 
13775e96a66cSDavid du Colombier 	ARGBEGIN{
13785e96a66cSDavid du Colombier 	default:
13795e96a66cSDavid du Colombier 		return cliError(usage);
13805e96a66cSDavid du Colombier 	}ARGEND
13815e96a66cSDavid du Colombier 	if(argc != 1)
13825e96a66cSDavid du Colombier 		return cliError(usage);
13835e96a66cSDavid du Colombier 
13845e96a66cSDavid du Colombier 	if((fsys = _fsysGet(argv[0])) != nil){
13855e96a66cSDavid du Colombier 		vtLock(fsys->lock);
13865e96a66cSDavid du Colombier 		if(fsys->fs != nil){
13875e96a66cSDavid du Colombier 			vtSetError(EFsysBusy, fsys->name);
13885e96a66cSDavid du Colombier 			vtUnlock(fsys->lock);
13895e96a66cSDavid du Colombier 			fsysPut(fsys);
13905e96a66cSDavid du Colombier 			return 0;
13915e96a66cSDavid du Colombier 		}
13925e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
13935e96a66cSDavid du Colombier 		fsys->dev = vtStrDup(argv[0]);
13945e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
13955e96a66cSDavid du Colombier 	}
13965e96a66cSDavid du Colombier 	else if((fsys = fsysAlloc(name, argv[0])) == nil)
13975e96a66cSDavid du Colombier 		return 0;
13985e96a66cSDavid du Colombier 
13995e96a66cSDavid du Colombier 	fsysPut(fsys);
14005e96a66cSDavid du Colombier 
14015e96a66cSDavid du Colombier 	return 1;
14025e96a66cSDavid du Colombier }
14035e96a66cSDavid du Colombier 
14045e96a66cSDavid du Colombier static struct {
14055e96a66cSDavid du Colombier 	char*	cmd;
14065e96a66cSDavid du Colombier 	int	(*f)(Fsys*, int, char**);
14075e96a66cSDavid du Colombier 	int	(*f1)(char*, int, char**);
14085e96a66cSDavid du Colombier } fsyscmd[] = {
14095e96a66cSDavid du Colombier 	{ "close",	fsysClose, },
14105e96a66cSDavid du Colombier 	{ "config",	nil, fsysConfig, },
14115e96a66cSDavid du Colombier 	{ "open",	nil, fsysOpen, },
14125e96a66cSDavid du Colombier 	{ "unconfig",	nil, fsysUnconfig, },
14135e96a66cSDavid du Colombier 	{ "venti",	nil, fsysVenti, },
14145e96a66cSDavid du Colombier 
14155e96a66cSDavid du Colombier 	{ "bfree",	fsysBfree, },
14165e96a66cSDavid du Colombier 	{ "block",	fsysBlock, },
14175e96a66cSDavid du Colombier 	{ "clre",	fsysClre, },
14185e96a66cSDavid du Colombier 	{ "clri",	fsysClri, },
14195e96a66cSDavid du Colombier 	{ "clrp",	fsysClrp, },
14205e96a66cSDavid du Colombier 	{ "create",	fsysCreate, },
14217abd426fSDavid du Colombier 	{ "df",	fsysDf, },
14225e96a66cSDavid du Colombier 	{ "epoch",	fsysEpoch, },
1423*81cf8742SDavid du Colombier 	{ "halt",	fsysHalt, },
14245e96a66cSDavid du Colombier 	{ "label",	fsysLabel, },
14255e96a66cSDavid du Colombier 	{ "remove",	fsysRemove, },
14265e96a66cSDavid du Colombier 	{ "snap",	fsysSnap, },
14275e96a66cSDavid du Colombier 	{ "snaptime",	fsysSnapTime, },
14285e96a66cSDavid du Colombier 	{ "stat",	fsysStat, },
14295e96a66cSDavid du Colombier 	{ "sync",	fsysSync, },
1430*81cf8742SDavid du Colombier 	{ "unhalt",	fsysUnhalt, },
14315e96a66cSDavid du Colombier 	{ "wstat",	fsysWstat, },
14325e96a66cSDavid du Colombier 	{ "vac",	fsysVac, },
14335e96a66cSDavid du Colombier 
14345e96a66cSDavid du Colombier 	{ nil,		nil, },
14355e96a66cSDavid du Colombier };
14365e96a66cSDavid du Colombier 
14375e96a66cSDavid du Colombier static int
1438*81cf8742SDavid du Colombier fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
1439*81cf8742SDavid du Colombier {
1440*81cf8742SDavid du Colombier 	int r;
1441*81cf8742SDavid du Colombier 
1442*81cf8742SDavid du Colombier 	vtLock(fsys->lock);
1443*81cf8742SDavid du Colombier 	if(fsys->fs == nil){
1444*81cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
1445*81cf8742SDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
1446*81cf8742SDavid du Colombier 		return 0;
1447*81cf8742SDavid du Colombier 	}
1448*81cf8742SDavid du Colombier 
1449*81cf8742SDavid du Colombier 	if(fsys->fs->halted && fsyscmd[i].f != fsysUnhalt){
1450*81cf8742SDavid du Colombier 		vtSetError("file system %s is halted", fsys->name);
1451*81cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
1452*81cf8742SDavid du Colombier 		return 0;
1453*81cf8742SDavid du Colombier 	}
1454*81cf8742SDavid du Colombier 
1455*81cf8742SDavid du Colombier 	r = (*fsyscmd[i].f)(fsys, argc, argv);
1456*81cf8742SDavid du Colombier 	vtUnlock(fsys->lock);
1457*81cf8742SDavid du Colombier 	return r;
1458*81cf8742SDavid du Colombier }
1459*81cf8742SDavid du Colombier 
1460*81cf8742SDavid du Colombier static int
14615e96a66cSDavid du Colombier fsysXXX(char* name, int argc, char* argv[])
14625e96a66cSDavid du Colombier {
14635e96a66cSDavid du Colombier 	int i, r;
14645e96a66cSDavid du Colombier 	Fsys *fsys;
14655e96a66cSDavid du Colombier 
14665e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
14675e96a66cSDavid du Colombier 		if(strcmp(fsyscmd[i].cmd, argv[0]) == 0)
14685e96a66cSDavid du Colombier 			break;
14695e96a66cSDavid du Colombier 	}
14705e96a66cSDavid du Colombier 
14715e96a66cSDavid du Colombier 	if(fsyscmd[i].cmd == nil){
14725e96a66cSDavid du Colombier 		vtSetError("unknown command - '%s'", argv[0]);
14735e96a66cSDavid du Colombier 		return 0;
14745e96a66cSDavid du Colombier 	}
14755e96a66cSDavid du Colombier 
14765e96a66cSDavid du Colombier 	/* some commands want the name... */
1477*81cf8742SDavid du Colombier 	if(fsyscmd[i].f1 != nil){
1478*81cf8742SDavid du Colombier 		if(strcmp(name, FsysAll) == 0){
1479*81cf8742SDavid du Colombier 			vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
14805e96a66cSDavid du Colombier 			return 0;
14815e96a66cSDavid du Colombier 		}
1482*81cf8742SDavid du Colombier 		return (*fsyscmd[i].f1)(name, argc, argv);
1483*81cf8742SDavid du Colombier 	}
14845e96a66cSDavid du Colombier 
1485*81cf8742SDavid du Colombier 	/* ... but most commands want the Fsys */
1486*81cf8742SDavid du Colombier 	if(strcmp(name, FsysAll) == 0){
1487*81cf8742SDavid du Colombier 		r = 1;
1488*81cf8742SDavid du Colombier 		vtRLock(sbox.lock);
1489*81cf8742SDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
1490*81cf8742SDavid du Colombier 			fsys->ref++;
1491*81cf8742SDavid du Colombier 			r = fsysXXX1(fsys, i, argc, argv) && r;
1492*81cf8742SDavid du Colombier 			fsys->ref--;
1493*81cf8742SDavid du Colombier 		}
1494*81cf8742SDavid du Colombier 		vtRUnlock(sbox.lock);
1495*81cf8742SDavid du Colombier 	}else{
1496*81cf8742SDavid du Colombier 		if((fsys = _fsysGet(name)) == nil)
1497*81cf8742SDavid du Colombier 			return 0;
1498*81cf8742SDavid du Colombier 		r = fsysXXX1(fsys, i, argc, argv);
14995e96a66cSDavid du Colombier 		fsysPut(fsys);
1500*81cf8742SDavid du Colombier 	}
15015e96a66cSDavid du Colombier 	return r;
15025e96a66cSDavid du Colombier }
15035e96a66cSDavid du Colombier 
15045e96a66cSDavid du Colombier static int
15055e96a66cSDavid du Colombier cmdFsysXXX(int argc, char* argv[])
15065e96a66cSDavid du Colombier {
15075e96a66cSDavid du Colombier 	char *name;
15085e96a66cSDavid du Colombier 
15095e96a66cSDavid du Colombier 	if((name = sbox.curfsys) == nil){
15105e96a66cSDavid du Colombier 		vtSetError(EFsysNoCurrent, argv[0]);
15115e96a66cSDavid du Colombier 		return 0;
15125e96a66cSDavid du Colombier 	}
15135e96a66cSDavid du Colombier 
15145e96a66cSDavid du Colombier 	return fsysXXX(name, argc, argv);
15155e96a66cSDavid du Colombier }
15165e96a66cSDavid du Colombier 
15175e96a66cSDavid du Colombier static int
15185e96a66cSDavid du Colombier cmdFsys(int argc, char* argv[])
15195e96a66cSDavid du Colombier {
15205e96a66cSDavid du Colombier 	Fsys *fsys;
15215e96a66cSDavid du Colombier 	char *usage = "usage: fsys [name ...]";
15225e96a66cSDavid du Colombier 
15235e96a66cSDavid du Colombier 	ARGBEGIN{
15245e96a66cSDavid du Colombier 	default:
15255e96a66cSDavid du Colombier 		return cliError(usage);
15265e96a66cSDavid du Colombier 	}ARGEND
15275e96a66cSDavid du Colombier 
15285e96a66cSDavid du Colombier 	if(argc == 0){
15295e96a66cSDavid du Colombier 		vtRLock(sbox.lock);
15305e96a66cSDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next)
15315e96a66cSDavid du Colombier 			consPrint("\t%s\n", fsys->name);
15325e96a66cSDavid du Colombier 		vtRUnlock(sbox.lock);
15335e96a66cSDavid du Colombier 		return 1;
15345e96a66cSDavid du Colombier 	}
15355e96a66cSDavid du Colombier 	if(argc == 1){
1536*81cf8742SDavid du Colombier 		fsys = nil;
1537*81cf8742SDavid du Colombier 		if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
15385e96a66cSDavid du Colombier 			return 0;
1539*81cf8742SDavid du Colombier 		sbox.curfsys = vtStrDup(argv[0]);
15405e96a66cSDavid du Colombier 		consPrompt(sbox.curfsys);
1541*81cf8742SDavid du Colombier 		if(fsys)
15425e96a66cSDavid du Colombier 			fsysPut(fsys);
15435e96a66cSDavid du Colombier 		return 1;
15445e96a66cSDavid du Colombier 	}
15455e96a66cSDavid du Colombier 
15465e96a66cSDavid du Colombier 	return fsysXXX(argv[0], argc-1, argv+1);
15475e96a66cSDavid du Colombier }
15485e96a66cSDavid du Colombier 
15495e96a66cSDavid du Colombier int
15505e96a66cSDavid du Colombier fsysInit(void)
15515e96a66cSDavid du Colombier {
15525e96a66cSDavid du Colombier 	int i;
15535e96a66cSDavid du Colombier 
15545e96a66cSDavid du Colombier 	fmtinstall('H', encodefmt);
15555e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
15565e96a66cSDavid du Colombier 	fmtinstall('R', vtErrFmt);
15575e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
15585e96a66cSDavid du Colombier 
15595e96a66cSDavid du Colombier 	sbox.lock = vtLockAlloc();
15605e96a66cSDavid du Colombier 
15615e96a66cSDavid du Colombier 	cliAddCmd("fsys", cmdFsys);
15625e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
15635e96a66cSDavid du Colombier 		if(fsyscmd[i].f != nil)
15645e96a66cSDavid du Colombier 			cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX);
15655e96a66cSDavid du Colombier 	}
15665e96a66cSDavid du Colombier 	/* the venti cmd is special: the fs can be either open or closed */
15675e96a66cSDavid du Colombier 	cliAddCmd("venti", cmdFsysXXX);
15685e96a66cSDavid du Colombier 	cliAddCmd("printconfig", cmdPrintConfig);
15695e96a66cSDavid du Colombier 
15705e96a66cSDavid du Colombier 	return 1;
15715e96a66cSDavid du Colombier }
1572