xref: /plan9/sys/src/cmd/fossil/9fsys.c (revision 0c6300e705c776baceaa75d1b64fc63b9564225a)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier #include "dat.h"
35e96a66cSDavid du Colombier #include "fns.h"
45e96a66cSDavid du Colombier #include "9.h"
55e96a66cSDavid du Colombier 
65e96a66cSDavid du Colombier typedef struct Fsys Fsys;
75e96a66cSDavid du Colombier 
87abd426fSDavid du Colombier struct Fsys {
95e96a66cSDavid du Colombier 	VtLock* lock;
105e96a66cSDavid du Colombier 
11*0c6300e7SDavid du Colombier 	char*	name;		/* copy here & Fs to ease error reporting */
125e96a66cSDavid du Colombier 	char*	dev;
135e96a66cSDavid du Colombier 	char*	venti;
145e96a66cSDavid du Colombier 
155e96a66cSDavid du Colombier 	Fs*	fs;
165e96a66cSDavid du Colombier 	VtSession* session;
175e96a66cSDavid du Colombier 	int	ref;
185e96a66cSDavid du Colombier 
195e96a66cSDavid du Colombier 	int	noauth;
205e96a66cSDavid du Colombier 	int	noperm;
215e96a66cSDavid du Colombier 	int	wstatallow;
225e96a66cSDavid du Colombier 
235e96a66cSDavid du Colombier 	Fsys*	next;
247abd426fSDavid du Colombier };
255e96a66cSDavid du Colombier 
265e96a66cSDavid du Colombier static struct {
275e96a66cSDavid du Colombier 	VtLock*	lock;
285e96a66cSDavid du Colombier 	Fsys*	head;
295e96a66cSDavid du Colombier 	Fsys*	tail;
305e96a66cSDavid du Colombier 
315e96a66cSDavid du Colombier 	char*	curfsys;
325e96a66cSDavid du Colombier } sbox;
335e96a66cSDavid du Colombier 
345e96a66cSDavid du Colombier static char *_argv0;
355e96a66cSDavid du Colombier #define argv0 _argv0
365e96a66cSDavid du Colombier 
3781cf8742SDavid du Colombier static char FsysAll[] = "all";
3881cf8742SDavid du Colombier 
395e96a66cSDavid du Colombier static char EFsysBusy[] = "fsys: '%s' busy";
405e96a66cSDavid du Colombier static char EFsysExists[] = "fsys: '%s' already exists";
415e96a66cSDavid du Colombier static char EFsysNoCurrent[] = "fsys: no current fsys";
425e96a66cSDavid du Colombier static char EFsysNotFound[] = "fsys: '%s' not found";
435e96a66cSDavid du Colombier static char EFsysNotOpen[] = "fsys: '%s' not open";
445e96a66cSDavid du Colombier 
455e96a66cSDavid du Colombier static Fsys*
465e96a66cSDavid du Colombier _fsysGet(char* name)
475e96a66cSDavid du Colombier {
485e96a66cSDavid du Colombier 	Fsys *fsys;
495e96a66cSDavid du Colombier 
505e96a66cSDavid du Colombier 	if(name == nil || name[0] == '\0')
515e96a66cSDavid du Colombier 		name = "main";
525e96a66cSDavid du Colombier 
535e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
545e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
555e96a66cSDavid du Colombier 		if(strcmp(name, fsys->name) == 0){
565e96a66cSDavid du Colombier 			fsys->ref++;
575e96a66cSDavid du Colombier 			break;
585e96a66cSDavid du Colombier 		}
595e96a66cSDavid du Colombier 	}
60dc5a79c1SDavid du Colombier 	vtRUnlock(sbox.lock);
615e96a66cSDavid du Colombier 	if(fsys == nil)
625e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
635e96a66cSDavid du Colombier 	return fsys;
645e96a66cSDavid du Colombier }
655e96a66cSDavid du Colombier 
665e96a66cSDavid du Colombier static int
675e96a66cSDavid du Colombier cmdPrintConfig(int argc, char* argv[])
685e96a66cSDavid du Colombier {
695e96a66cSDavid du Colombier 	Fsys *fsys;
705e96a66cSDavid du Colombier 	char *usage = "usage: printconfig";
715e96a66cSDavid du Colombier 
725e96a66cSDavid du Colombier 	ARGBEGIN{
735e96a66cSDavid du Colombier 	default:
745e96a66cSDavid du Colombier 		return cliError(usage);
755e96a66cSDavid du Colombier 	}ARGEND
765e96a66cSDavid du Colombier 
775e96a66cSDavid du Colombier 	if(argc)
785e96a66cSDavid du Colombier 		return cliError(usage);
795e96a66cSDavid du Colombier 
805e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
815e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
825e96a66cSDavid du Colombier 		consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev);
835e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
84*0c6300e7SDavid du Colombier 			consPrint("\tfsys %s venti %q\n", fsys->name,
85*0c6300e7SDavid du Colombier 				fsys->venti);
865e96a66cSDavid du Colombier 	}
875e96a66cSDavid du Colombier 	vtRUnlock(sbox.lock);
885e96a66cSDavid du Colombier 	return 1;
895e96a66cSDavid du Colombier }
905e96a66cSDavid du Colombier 
915e96a66cSDavid du Colombier Fsys*
925e96a66cSDavid du Colombier fsysGet(char* name)
935e96a66cSDavid du Colombier {
945e96a66cSDavid du Colombier 	Fsys *fsys;
955e96a66cSDavid du Colombier 
965e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
975e96a66cSDavid du Colombier 		return nil;
985e96a66cSDavid du Colombier 
995e96a66cSDavid du Colombier 	vtLock(fsys->lock);
1005e96a66cSDavid du Colombier 	if(fsys->fs == nil){
1015e96a66cSDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
1025e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
1035e96a66cSDavid du Colombier 		fsysPut(fsys);
1045e96a66cSDavid du Colombier 		return nil;
1055e96a66cSDavid du Colombier 	}
1065e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
1075e96a66cSDavid du Colombier 
1085e96a66cSDavid du Colombier 	return fsys;
1095e96a66cSDavid du Colombier }
1105e96a66cSDavid du Colombier 
11161201b97SDavid du Colombier char*
11261201b97SDavid du Colombier fsysGetName(Fsys* fsys)
11361201b97SDavid du Colombier {
11461201b97SDavid du Colombier 	return fsys->name;
11561201b97SDavid du Colombier }
11661201b97SDavid du Colombier 
1175e96a66cSDavid du Colombier Fsys*
1185e96a66cSDavid du Colombier fsysIncRef(Fsys* fsys)
1195e96a66cSDavid du Colombier {
1205e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1215e96a66cSDavid du Colombier 	fsys->ref++;
1225e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1235e96a66cSDavid du Colombier 
1245e96a66cSDavid du Colombier 	return fsys;
1255e96a66cSDavid du Colombier }
1265e96a66cSDavid du Colombier 
1275e96a66cSDavid du Colombier void
1285e96a66cSDavid du Colombier fsysPut(Fsys* fsys)
1295e96a66cSDavid du Colombier {
1305e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1315e96a66cSDavid du Colombier 	assert(fsys->ref > 0);
1325e96a66cSDavid du Colombier 	fsys->ref--;
1335e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1345e96a66cSDavid du Colombier }
1355e96a66cSDavid du Colombier 
1365e96a66cSDavid du Colombier Fs*
1375e96a66cSDavid du Colombier fsysGetFs(Fsys* fsys)
1385e96a66cSDavid du Colombier {
1395e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
1405e96a66cSDavid du Colombier 
1415e96a66cSDavid du Colombier 	return fsys->fs;
1425e96a66cSDavid du Colombier }
1435e96a66cSDavid du Colombier 
1445e96a66cSDavid du Colombier void
1455e96a66cSDavid du Colombier fsysFsRlock(Fsys* fsys)
1465e96a66cSDavid du Colombier {
1475e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
1485e96a66cSDavid du Colombier }
1495e96a66cSDavid du Colombier 
1505e96a66cSDavid du Colombier void
1515e96a66cSDavid du Colombier fsysFsRUnlock(Fsys* fsys)
1525e96a66cSDavid du Colombier {
1535e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
1545e96a66cSDavid du Colombier }
1555e96a66cSDavid du Colombier 
1565e96a66cSDavid du Colombier int
1575e96a66cSDavid du Colombier fsysNoAuthCheck(Fsys* fsys)
1585e96a66cSDavid du Colombier {
1595e96a66cSDavid du Colombier 	return fsys->noauth;
1605e96a66cSDavid du Colombier }
1615e96a66cSDavid du Colombier 
1625e96a66cSDavid du Colombier int
1635e96a66cSDavid du Colombier fsysNoPermCheck(Fsys* fsys)
1645e96a66cSDavid du Colombier {
1655e96a66cSDavid du Colombier 	return fsys->noperm;
1665e96a66cSDavid du Colombier }
1675e96a66cSDavid du Colombier 
1685e96a66cSDavid du Colombier int
1695e96a66cSDavid du Colombier fsysWstatAllow(Fsys* fsys)
1705e96a66cSDavid du Colombier {
1715e96a66cSDavid du Colombier 	return fsys->wstatallow;
1725e96a66cSDavid du Colombier }
1735e96a66cSDavid du Colombier 
1745e96a66cSDavid du Colombier static char modechars[] = "YUGalLdHSATs";
1755e96a66cSDavid du Colombier static ulong modebits[] = {
1765e96a66cSDavid du Colombier 	ModeSticky,
1775e96a66cSDavid du Colombier 	ModeSetUid,
1785e96a66cSDavid du Colombier 	ModeSetGid,
1795e96a66cSDavid du Colombier 	ModeAppend,
1805e96a66cSDavid du Colombier 	ModeExclusive,
1815e96a66cSDavid du Colombier 	ModeLink,
1825e96a66cSDavid du Colombier 	ModeDir,
1835e96a66cSDavid du Colombier 	ModeHidden,
1845e96a66cSDavid du Colombier 	ModeSystem,
1855e96a66cSDavid du Colombier 	ModeArchive,
1865e96a66cSDavid du Colombier 	ModeTemporary,
1875e96a66cSDavid du Colombier 	ModeSnapshot,
1885e96a66cSDavid du Colombier 	0
1895e96a66cSDavid du Colombier };
1905e96a66cSDavid du Colombier 
1915e96a66cSDavid du Colombier char*
1925e96a66cSDavid du Colombier fsysModeString(ulong mode, char *buf)
1935e96a66cSDavid du Colombier {
1945e96a66cSDavid du Colombier 	int i;
1955e96a66cSDavid du Colombier 	char *p;
1965e96a66cSDavid du Colombier 
1975e96a66cSDavid du Colombier 	p = buf;
1985e96a66cSDavid du Colombier 	for(i=0; modebits[i]; i++)
1995e96a66cSDavid du Colombier 		if(mode & modebits[i])
2005e96a66cSDavid du Colombier 			*p++ = modechars[i];
2015e96a66cSDavid du Colombier 	sprint(p, "%luo", mode&0777);
2025e96a66cSDavid du Colombier 	return buf;
2035e96a66cSDavid du Colombier }
2045e96a66cSDavid du Colombier 
2055e96a66cSDavid du Colombier int
2065e96a66cSDavid du Colombier fsysParseMode(char* s, ulong* mode)
2075e96a66cSDavid du Colombier {
2085e96a66cSDavid du Colombier 	ulong x, y;
2095e96a66cSDavid du Colombier 	char *p;
2105e96a66cSDavid du Colombier 
2115e96a66cSDavid du Colombier 	x = 0;
2125e96a66cSDavid du Colombier 	for(; *s < '0' || *s > '9'; s++){
2135e96a66cSDavid du Colombier 		if(*s == 0)
2145e96a66cSDavid du Colombier 			return 0;
2155e96a66cSDavid du Colombier 		p = strchr(modechars, *s);
2165e96a66cSDavid du Colombier 		if(p == nil)
2175e96a66cSDavid du Colombier 			return 0;
2185e96a66cSDavid du Colombier 		x |= modebits[p-modechars];
2195e96a66cSDavid du Colombier 	}
2205e96a66cSDavid du Colombier 	y = strtoul(s, &p, 8);
2215e96a66cSDavid du Colombier 	if(*p != '\0' || y > 0777)
2225e96a66cSDavid du Colombier 		return 0;
2235e96a66cSDavid du Colombier 	*mode = x|y;
2245e96a66cSDavid du Colombier 	return 1;
2255e96a66cSDavid du Colombier }
2265e96a66cSDavid du Colombier 
2275e96a66cSDavid du Colombier File*
2285e96a66cSDavid du Colombier fsysGetRoot(Fsys* fsys, char* name)
2295e96a66cSDavid du Colombier {
2305e96a66cSDavid du Colombier 	File *root, *sub;
2315e96a66cSDavid du Colombier 
2325e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
2335e96a66cSDavid du Colombier 
2345e96a66cSDavid du Colombier 	root = fsGetRoot(fsys->fs);
2355e96a66cSDavid du Colombier 	if(name == nil || strcmp(name, "") == 0)
2365e96a66cSDavid du Colombier 		return root;
2375e96a66cSDavid du Colombier 
2385e96a66cSDavid du Colombier 	sub = fileWalk(root, name);
2395e96a66cSDavid du Colombier 	fileDecRef(root);
2405e96a66cSDavid du Colombier 
2415e96a66cSDavid du Colombier 	return sub;
2425e96a66cSDavid du Colombier }
2435e96a66cSDavid du Colombier 
2445e96a66cSDavid du Colombier static Fsys*
2455e96a66cSDavid du Colombier fsysAlloc(char* name, char* dev)
2465e96a66cSDavid du Colombier {
2475e96a66cSDavid du Colombier 	Fsys *fsys;
2485e96a66cSDavid du Colombier 
2495e96a66cSDavid du Colombier 	vtLock(sbox.lock);
2505e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
2515e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) != 0)
2525e96a66cSDavid du Colombier 			continue;
2535e96a66cSDavid du Colombier 		vtSetError(EFsysExists, name);
2545e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
2555e96a66cSDavid du Colombier 		return nil;
2565e96a66cSDavid du Colombier 	}
2575e96a66cSDavid du Colombier 
2585e96a66cSDavid du Colombier 	fsys = vtMemAllocZ(sizeof(Fsys));
2595e96a66cSDavid du Colombier 	fsys->lock = vtLockAlloc();
2605e96a66cSDavid du Colombier 	fsys->name = vtStrDup(name);
2615e96a66cSDavid du Colombier 	fsys->dev = vtStrDup(dev);
2625e96a66cSDavid du Colombier 
2635e96a66cSDavid du Colombier 	fsys->ref = 1;
2645e96a66cSDavid du Colombier 
2655e96a66cSDavid du Colombier 	if(sbox.tail != nil)
2665e96a66cSDavid du Colombier 		sbox.tail->next = fsys;
2675e96a66cSDavid du Colombier 	else
2685e96a66cSDavid du Colombier 		sbox.head = fsys;
2695e96a66cSDavid du Colombier 	sbox.tail = fsys;
2705e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
2715e96a66cSDavid du Colombier 
2725e96a66cSDavid du Colombier 	return fsys;
2735e96a66cSDavid du Colombier }
2745e96a66cSDavid du Colombier 
2755e96a66cSDavid du Colombier static int
2765e96a66cSDavid du Colombier fsysClose(Fsys* fsys, int argc, char* argv[])
2775e96a66cSDavid du Colombier {
2785e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] close";
2795e96a66cSDavid du Colombier 
2805e96a66cSDavid du Colombier 	ARGBEGIN{
2815e96a66cSDavid du Colombier 	default:
2825e96a66cSDavid du Colombier 		return cliError(usage);
2835e96a66cSDavid du Colombier 	}ARGEND
2845e96a66cSDavid du Colombier 	if(argc)
2855e96a66cSDavid du Colombier 		return cliError(usage);
2865e96a66cSDavid du Colombier 
28768412abfSDavid du Colombier 	return cliError("close isn't working yet; halt %s and then kill fossil",
28868412abfSDavid du Colombier 		fsys->name);
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 	fsClose(fsys->fs);
2975e96a66cSDavid du Colombier 	fsys->fs = nil;
2985e96a66cSDavid du Colombier 	vtClose(fsys->session);
2995e96a66cSDavid du Colombier 	fsys->session = nil;
3005e96a66cSDavid du Colombier 
3015e96a66cSDavid du Colombier 	if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){
3025e96a66cSDavid du Colombier 		sbox.curfsys = nil;
3035e96a66cSDavid du Colombier 		consPrompt(nil);
3045e96a66cSDavid du Colombier 	}
3055e96a66cSDavid du Colombier 
3065e96a66cSDavid du Colombier 	return 1;
30768412abfSDavid du Colombier 	 */
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;
334c3c4501eSDavid du Colombier 	char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]";
335c3c4501eSDavid du Colombier 	char *src, *dst;
3365e96a66cSDavid du Colombier 
337c3c4501eSDavid du Colombier 	src = nil;
338c3c4501eSDavid du Colombier 	dst = nil;
3395e96a66cSDavid du Colombier 	doarchive = 0;
3405e96a66cSDavid du Colombier 	ARGBEGIN{
3415e96a66cSDavid du Colombier 	default:
3425e96a66cSDavid du Colombier 		return cliError(usage);
3435e96a66cSDavid du Colombier 	case 'a':
3445e96a66cSDavid du Colombier 		doarchive = 1;
3455e96a66cSDavid du Colombier 		break;
346c3c4501eSDavid du Colombier 	case 'd':
347c3c4501eSDavid du Colombier 		if((dst = ARGF()) == nil)
348c3c4501eSDavid du Colombier 			return cliError(usage);
349c3c4501eSDavid du Colombier 		break;
350c3c4501eSDavid du Colombier 	case 's':
351c3c4501eSDavid du Colombier 		if((src = ARGF()) == nil)
352c3c4501eSDavid du Colombier 			return cliError(usage);
353c3c4501eSDavid du Colombier 		break;
3545e96a66cSDavid du Colombier 	}ARGEND
3555e96a66cSDavid du Colombier 	if(argc)
3565e96a66cSDavid du Colombier 		return cliError(usage);
3575e96a66cSDavid du Colombier 
358c3c4501eSDavid du Colombier 	if(!fsSnapshot(fsys->fs, src, dst, doarchive))
3595e96a66cSDavid du Colombier 		return 0;
3605e96a66cSDavid du Colombier 
3615e96a66cSDavid du Colombier 	return 1;
3625e96a66cSDavid du Colombier }
3635e96a66cSDavid du Colombier 
3645e96a66cSDavid du Colombier static int
365dc5a79c1SDavid du Colombier fsysSnapClean(Fsys *fsys, int argc, char* argv[])
366dc5a79c1SDavid du Colombier {
367dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
368dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snapclean [maxminutes]\n";
369dc5a79c1SDavid du Colombier 
370dc5a79c1SDavid du Colombier 	ARGBEGIN{
371dc5a79c1SDavid du Colombier 	default:
372dc5a79c1SDavid du Colombier 		return cliError(usage);
373dc5a79c1SDavid du Colombier 	}ARGEND
374dc5a79c1SDavid du Colombier 
375dc5a79c1SDavid du Colombier 	if(argc > 1)
376dc5a79c1SDavid du Colombier 		return cliError(usage);
377dc5a79c1SDavid du Colombier 	if(argc == 1)
378f83f9c78SDavid du Colombier 		life = atoi(argv[0]);
379dc5a79c1SDavid du Colombier 	else
380dc5a79c1SDavid du Colombier 		snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
381dc5a79c1SDavid du Colombier 
382dc5a79c1SDavid du Colombier 	fsSnapshotCleanup(fsys->fs, life);
383dc5a79c1SDavid du Colombier 	return 1;
384dc5a79c1SDavid du Colombier }
385dc5a79c1SDavid du Colombier 
386dc5a79c1SDavid du Colombier static int
3875e96a66cSDavid du Colombier fsysSnapTime(Fsys* fsys, int argc, char* argv[])
3885e96a66cSDavid du Colombier {
389dc5a79c1SDavid du Colombier 	char buf[128], *x;
390dc5a79c1SDavid du Colombier 	int hh, mm, changed;
391dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
392dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]";
3935e96a66cSDavid du Colombier 
394dc5a79c1SDavid du Colombier 	changed = 0;
395dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
3965e96a66cSDavid du Colombier 	ARGBEGIN{
3975e96a66cSDavid du Colombier 	case 'a':
398dc5a79c1SDavid du Colombier 		changed = 1;
3995e96a66cSDavid du Colombier 		x = ARGF();
4005e96a66cSDavid du Colombier 		if(x == nil)
4015e96a66cSDavid du Colombier 			return cliError(usage);
4025e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4035e96a66cSDavid du Colombier 			arch = ~(u32int)0;
4045e96a66cSDavid du Colombier 			break;
4055e96a66cSDavid du Colombier 		}
4065e96a66cSDavid du Colombier 		if(strlen(x) != 4 || strspn(x, "0123456789") != 4)
4075e96a66cSDavid du Colombier 			return cliError(usage);
4085e96a66cSDavid du Colombier 		hh = (x[0]-'0')*10 + x[1]-'0';
4095e96a66cSDavid du Colombier 		mm = (x[2]-'0')*10 + x[3]-'0';
4105e96a66cSDavid du Colombier 		if(hh >= 24 || mm >= 60)
4115e96a66cSDavid du Colombier 			return cliError(usage);
4125e96a66cSDavid du Colombier 		arch = hh*60+mm;
4135e96a66cSDavid du Colombier 		break;
4145e96a66cSDavid du Colombier 	case 's':
415dc5a79c1SDavid du Colombier 		changed = 1;
4165e96a66cSDavid du Colombier 		x = ARGF();
4175e96a66cSDavid du Colombier 		if(x == nil)
4185e96a66cSDavid du Colombier 			return cliError(usage);
4195e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4205e96a66cSDavid du Colombier 			snap = ~(u32int)0;
4215e96a66cSDavid du Colombier 			break;
4225e96a66cSDavid du Colombier 		}
4235e96a66cSDavid du Colombier 		snap = atoi(x);
4245e96a66cSDavid du Colombier 		break;
425dc5a79c1SDavid du Colombier 	case 't':
426dc5a79c1SDavid du Colombier 		changed = 1;
427dc5a79c1SDavid du Colombier 		x = ARGF();
428dc5a79c1SDavid du Colombier 		if(x == nil)
429dc5a79c1SDavid du Colombier 			return cliError(usage);
430dc5a79c1SDavid du Colombier 		if(strcmp(x, "none") == 0){
431dc5a79c1SDavid du Colombier 			life = ~(u32int)0;
432dc5a79c1SDavid du Colombier 			break;
433dc5a79c1SDavid du Colombier 		}
434dc5a79c1SDavid du Colombier 		life = atoi(x);
435dc5a79c1SDavid du Colombier 		break;
4365e96a66cSDavid du Colombier 	default:
4375e96a66cSDavid du Colombier 		return cliError(usage);
4385e96a66cSDavid du Colombier 	}ARGEND
4395e96a66cSDavid du Colombier 	if(argc > 0)
4405e96a66cSDavid du Colombier 		return cliError(usage);
4415e96a66cSDavid du Colombier 
442dc5a79c1SDavid du Colombier 	if(changed){
443dc5a79c1SDavid du Colombier 		snapSetTimes(fsys->fs->snap, arch, snap, life);
444dc5a79c1SDavid du Colombier 		return 1;
445dc5a79c1SDavid du Colombier 	}
446dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
4475e96a66cSDavid du Colombier 	if(arch != ~(u32int)0)
4485e96a66cSDavid du Colombier 		sprint(buf, "-a %02d%02d", arch/60, arch%60);
4495e96a66cSDavid du Colombier 	else
4505e96a66cSDavid du Colombier 		sprint(buf, "-a none");
4515e96a66cSDavid du Colombier 	if(snap != ~(u32int)0)
4525e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s %d", snap);
4535e96a66cSDavid du Colombier 	else
4545e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s none");
455dc5a79c1SDavid du Colombier 	if(life != ~(u32int)0)
456dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t %ud", life);
457dc5a79c1SDavid du Colombier 	else
458dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t none");
4595e96a66cSDavid du Colombier 	consPrint("\tsnaptime %s\n", buf);
4605e96a66cSDavid du Colombier 	return 1;
4615e96a66cSDavid du Colombier }
4625e96a66cSDavid du Colombier 
4635e96a66cSDavid du Colombier static int
4645e96a66cSDavid du Colombier fsysSync(Fsys* fsys, int argc, char* argv[])
4655e96a66cSDavid du Colombier {
4665e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] sync";
4670b9a5132SDavid du Colombier 	int n;
4685e96a66cSDavid du Colombier 
4695e96a66cSDavid du Colombier 	ARGBEGIN{
4705e96a66cSDavid du Colombier 	default:
4715e96a66cSDavid du Colombier 		return cliError(usage);
4725e96a66cSDavid du Colombier 	}ARGEND
4735e96a66cSDavid du Colombier 	if(argc > 0)
4745e96a66cSDavid du Colombier 		return cliError(usage);
4755e96a66cSDavid du Colombier 
4760b9a5132SDavid du Colombier 	n = cacheDirty(fsys->fs->cache);
4775e96a66cSDavid du Colombier 	fsSync(fsys->fs);
4780b9a5132SDavid du Colombier 	consPrint("\t%s sync: wrote %d blocks\n", fsys->name, n);
47981cf8742SDavid du Colombier 	return 1;
48081cf8742SDavid du Colombier }
4815e96a66cSDavid du Colombier 
48281cf8742SDavid du Colombier static int
48381cf8742SDavid du Colombier fsysHalt(Fsys *fsys, int argc, char* argv[])
48481cf8742SDavid du Colombier {
48581cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] halt";
48681cf8742SDavid du Colombier 
48781cf8742SDavid du Colombier 	ARGBEGIN{
48881cf8742SDavid du Colombier 	default:
48981cf8742SDavid du Colombier 		return cliError(usage);
49081cf8742SDavid du Colombier 	}ARGEND
49181cf8742SDavid du Colombier 	if(argc > 0)
49281cf8742SDavid du Colombier 		return cliError(usage);
49381cf8742SDavid du Colombier 
49481cf8742SDavid du Colombier 	fsHalt(fsys->fs);
49581cf8742SDavid du Colombier 	return 1;
49681cf8742SDavid du Colombier }
49781cf8742SDavid du Colombier 
49881cf8742SDavid du Colombier static int
49981cf8742SDavid du Colombier fsysUnhalt(Fsys *fsys, int argc, char* argv[])
50081cf8742SDavid du Colombier {
50181cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] unhalt";
50281cf8742SDavid du Colombier 
50381cf8742SDavid du Colombier 	ARGBEGIN{
50481cf8742SDavid du Colombier 	default:
50581cf8742SDavid du Colombier 		return cliError(usage);
50681cf8742SDavid du Colombier 	}ARGEND
50781cf8742SDavid du Colombier 	if(argc > 0)
50881cf8742SDavid du Colombier 		return cliError(usage);
50981cf8742SDavid du Colombier 
51081cf8742SDavid du Colombier 	if(!fsys->fs->halted)
51181cf8742SDavid du Colombier 		return cliError("file system %s not halted", fsys->name);
51281cf8742SDavid du Colombier 
51381cf8742SDavid du Colombier 	fsUnhalt(fsys->fs);
5145e96a66cSDavid du Colombier 	return 1;
5155e96a66cSDavid du Colombier }
5165e96a66cSDavid du Colombier 
5175e96a66cSDavid du Colombier static int
5185e96a66cSDavid du Colombier fsysRemove(Fsys* fsys, int argc, char* argv[])
5195e96a66cSDavid du Colombier {
5205e96a66cSDavid du Colombier 	File *file;
5215e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] remove path ...";
5225e96a66cSDavid du Colombier 
5235e96a66cSDavid du Colombier 	ARGBEGIN{
5245e96a66cSDavid du Colombier 	default:
5255e96a66cSDavid du Colombier 		return cliError(usage);
5265e96a66cSDavid du Colombier 	}ARGEND
5275e96a66cSDavid du Colombier 	if(argc == 0)
5285e96a66cSDavid du Colombier 		return cliError(usage);
5295e96a66cSDavid du Colombier 
5305e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5315e96a66cSDavid du Colombier 	while(argc > 0){
5325e96a66cSDavid du Colombier 		if((file = fileOpen(fsys->fs, argv[0])) == nil)
5335e96a66cSDavid du Colombier 			consPrint("%s: %R\n", argv[0]);
5345e96a66cSDavid du Colombier 		else{
5355e96a66cSDavid du Colombier 			if(!fileRemove(file, uidadm))
5365e96a66cSDavid du Colombier 				consPrint("%s: %R\n", argv[0]);
5375e96a66cSDavid du Colombier 			fileDecRef(file);
5385e96a66cSDavid du Colombier 		}
5395e96a66cSDavid du Colombier 		argc--;
5405e96a66cSDavid du Colombier 		argv++;
5415e96a66cSDavid du Colombier 	}
5425e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
5435e96a66cSDavid du Colombier 
5445e96a66cSDavid du Colombier 	return 1;
5455e96a66cSDavid du Colombier }
5465e96a66cSDavid du Colombier 
5475e96a66cSDavid du Colombier static int
5485e96a66cSDavid du Colombier fsysClri(Fsys* fsys, int argc, char* argv[])
5495e96a66cSDavid du Colombier {
5505e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clri path ...";
5515e96a66cSDavid du Colombier 
5525e96a66cSDavid du Colombier 	ARGBEGIN{
5535e96a66cSDavid du Colombier 	default:
5545e96a66cSDavid du Colombier 		return cliError(usage);
5555e96a66cSDavid du Colombier 	}ARGEND
5565e96a66cSDavid du Colombier 	if(argc == 0)
5575e96a66cSDavid du Colombier 		return cliError(usage);
5585e96a66cSDavid du Colombier 
5595e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5605e96a66cSDavid du Colombier 	while(argc > 0){
561dc5a79c1SDavid du Colombier 		if(!fileClriPath(fsys->fs, argv[0], uidadm))
5625e96a66cSDavid du Colombier 			consPrint("clri %s: %R\n", argv[0]);
5635e96a66cSDavid du Colombier 		argc--;
5645e96a66cSDavid du Colombier 		argv++;
5655e96a66cSDavid du Colombier 	}
5665e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
5675e96a66cSDavid du Colombier 
5685e96a66cSDavid du Colombier 	return 1;
5695e96a66cSDavid du Colombier }
5705e96a66cSDavid du Colombier 
5715e96a66cSDavid du Colombier /*
5725e96a66cSDavid du Colombier  * Inspect and edit the labels for blocks on disk.
5735e96a66cSDavid du Colombier  */
5745e96a66cSDavid du Colombier static int
5755e96a66cSDavid du Colombier fsysLabel(Fsys* fsys, int argc, char* argv[])
5765e96a66cSDavid du Colombier {
5775e96a66cSDavid du Colombier 	Fs *fs;
5785e96a66cSDavid du Colombier 	Label l;
5795e96a66cSDavid du Colombier 	int n, r;
5805e96a66cSDavid du Colombier 	u32int addr;
5815e96a66cSDavid du Colombier 	Block *b, *bb;
5825e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]";
5835e96a66cSDavid du Colombier 
5845e96a66cSDavid du Colombier 	ARGBEGIN{
5855e96a66cSDavid du Colombier 	default:
5865e96a66cSDavid du Colombier 		return cliError(usage);
5875e96a66cSDavid du Colombier 	}ARGEND
5885e96a66cSDavid du Colombier 	if(argc != 1 && argc != 6)
5895e96a66cSDavid du Colombier 		return cliError(usage);
5905e96a66cSDavid du Colombier 
5915e96a66cSDavid du Colombier 	r = 0;
5925e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5935e96a66cSDavid du Colombier 
5945e96a66cSDavid du Colombier 	fs = fsys->fs;
5955e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
5965e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
5975e96a66cSDavid du Colombier 	if(b == nil)
5985e96a66cSDavid du Colombier 		goto Out0;
5995e96a66cSDavid du Colombier 
6005e96a66cSDavid du Colombier 	l = b->l;
6015e96a66cSDavid du Colombier 	consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n",
6025e96a66cSDavid du Colombier 		argc==6 ? "old: " : "", addr, l.type, l.state,
6035e96a66cSDavid du Colombier 		l.epoch, l.epochClose, l.tag);
6045e96a66cSDavid du Colombier 
6055e96a66cSDavid du Colombier 	if(argc == 6){
6065e96a66cSDavid du Colombier 		if(strcmp(argv[1], "-") != 0)
6075e96a66cSDavid du Colombier 			l.type = atoi(argv[1]);
6085e96a66cSDavid du Colombier 		if(strcmp(argv[2], "-") != 0)
6095e96a66cSDavid du Colombier 			l.state = atoi(argv[2]);
6105e96a66cSDavid du Colombier 		if(strcmp(argv[3], "-") != 0)
6115e96a66cSDavid du Colombier 			l.epoch = strtoul(argv[3], 0, 0);
6125e96a66cSDavid du Colombier 		if(strcmp(argv[4], "-") != 0)
6135e96a66cSDavid du Colombier 			l.epochClose = strtoul(argv[4], 0, 0);
6145e96a66cSDavid du Colombier 		if(strcmp(argv[5], "-") != 0)
6155e96a66cSDavid du Colombier 			l.tag = strtoul(argv[5], 0, 0);
6165e96a66cSDavid du Colombier 
6175e96a66cSDavid du Colombier 		consPrint("new: label %#ux %ud %ud %ud %ud %#x\n",
6185e96a66cSDavid du Colombier 			addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
6195e96a66cSDavid du Colombier 		bb = _blockSetLabel(b, &l);
6205e96a66cSDavid du Colombier 		if(bb == nil)
6215e96a66cSDavid du Colombier 			goto Out1;
6225e96a66cSDavid du Colombier 		n = 0;
6235e96a66cSDavid du Colombier 		for(;;){
6245e96a66cSDavid du Colombier 			if(blockWrite(bb)){
6255e96a66cSDavid du Colombier 				while(bb->iostate != BioClean){
6265e96a66cSDavid du Colombier 					assert(bb->iostate == BioWriting);
6275e96a66cSDavid du Colombier 					vtSleep(bb->ioready);
6285e96a66cSDavid du Colombier 				}
6295e96a66cSDavid du Colombier 				break;
6305e96a66cSDavid du Colombier 			}
6315e96a66cSDavid du Colombier 			consPrint("blockWrite: %R\n");
6325e96a66cSDavid du Colombier 			if(n++ >= 5){
6335e96a66cSDavid du Colombier 				consPrint("giving up\n");
6345e96a66cSDavid du Colombier 				break;
6355e96a66cSDavid du Colombier 			}
6365e96a66cSDavid du Colombier 			sleep(5*1000);
6375e96a66cSDavid du Colombier 		}
6385e96a66cSDavid du Colombier 		blockPut(bb);
6395e96a66cSDavid du Colombier 	}
6405e96a66cSDavid du Colombier 	r = 1;
6415e96a66cSDavid du Colombier Out1:
6425e96a66cSDavid du Colombier 	blockPut(b);
6435e96a66cSDavid du Colombier Out0:
6445e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
6455e96a66cSDavid du Colombier 
6465e96a66cSDavid du Colombier 	return r;
6475e96a66cSDavid du Colombier }
6485e96a66cSDavid du Colombier 
6495e96a66cSDavid du Colombier /*
6505e96a66cSDavid du Colombier  * Inspect and edit the blocks on disk.
6515e96a66cSDavid du Colombier  */
6525e96a66cSDavid du Colombier static int
6535e96a66cSDavid du Colombier fsysBlock(Fsys* fsys, int argc, char* argv[])
6545e96a66cSDavid du Colombier {
6555e96a66cSDavid du Colombier 	Fs *fs;
6565e96a66cSDavid du Colombier 	char *s;
6575e96a66cSDavid du Colombier 	Block *b;
6585e96a66cSDavid du Colombier 	uchar *buf;
6595e96a66cSDavid du Colombier 	u32int addr;
6605e96a66cSDavid du Colombier 	int c, count, i, offset;
6615e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] block addr offset [count [data]]";
6625e96a66cSDavid du Colombier 
6635e96a66cSDavid du Colombier 	ARGBEGIN{
6645e96a66cSDavid du Colombier 	default:
6655e96a66cSDavid du Colombier 		return cliError(usage);
6665e96a66cSDavid du Colombier 	}ARGEND
6675e96a66cSDavid du Colombier 	if(argc < 2 || argc > 4)
6685e96a66cSDavid du Colombier 		return cliError(usage);
6695e96a66cSDavid du Colombier 
6705e96a66cSDavid du Colombier 	fs = fsys->fs;
6715e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
6725e96a66cSDavid du Colombier 	offset = strtoul(argv[1], 0, 0);
6735e96a66cSDavid du Colombier 	if(offset < 0 || offset >= fs->blockSize){
6745e96a66cSDavid du Colombier 		vtSetError("bad offset");
6755e96a66cSDavid du Colombier 		return 0;
6765e96a66cSDavid du Colombier 	}
6775e96a66cSDavid du Colombier 	if(argc > 2)
6785e96a66cSDavid du Colombier 		count = strtoul(argv[2], 0, 0);
6795e96a66cSDavid du Colombier 	else
6805e96a66cSDavid du Colombier 		count = 100000000;
6815e96a66cSDavid du Colombier 	if(offset+count > fs->blockSize)
6825e96a66cSDavid du Colombier 		count = fs->blockSize - count;
6835e96a66cSDavid du Colombier 
6845e96a66cSDavid du Colombier 	vtRLock(fs->elk);
6855e96a66cSDavid du Colombier 
6865e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
6875e96a66cSDavid du Colombier 	if(b == nil){
6885e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
6895e96a66cSDavid du Colombier 		vtRUnlock(fs->elk);
6905e96a66cSDavid du Colombier 		return 0;
6915e96a66cSDavid du Colombier 	}
6925e96a66cSDavid du Colombier 
6935e96a66cSDavid du Colombier 	consPrint("\t%sblock %#ux %ud %ud %.*H\n",
6945e96a66cSDavid du Colombier 		argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset);
6955e96a66cSDavid du Colombier 
6965e96a66cSDavid du Colombier 	if(argc == 4){
6975e96a66cSDavid du Colombier 		s = argv[3];
6985e96a66cSDavid du Colombier 		if(strlen(s) != 2*count){
6995e96a66cSDavid du Colombier 			vtSetError("bad data count");
7005e96a66cSDavid du Colombier 			goto Out;
7015e96a66cSDavid du Colombier 		}
7025e96a66cSDavid du Colombier 		buf = vtMemAllocZ(count);
7035e96a66cSDavid du Colombier 		for(i = 0; i < count*2; i++){
7045e96a66cSDavid du Colombier 			if(s[i] >= '0' && s[i] <= '9')
7055e96a66cSDavid du Colombier 				c = s[i] - '0';
7065e96a66cSDavid du Colombier 			else if(s[i] >= 'a' && s[i] <= 'f')
7075e96a66cSDavid du Colombier 				c = s[i] - 'a' + 10;
7085e96a66cSDavid du Colombier 			else if(s[i] >= 'A' && s[i] <= 'F')
7095e96a66cSDavid du Colombier 				c = s[i] - 'A' + 10;
7105e96a66cSDavid du Colombier 			else{
7115e96a66cSDavid du Colombier 				vtSetError("bad hex");
7125e96a66cSDavid du Colombier 				vtMemFree(buf);
7135e96a66cSDavid du Colombier 				goto Out;
7145e96a66cSDavid du Colombier 			}
7155e96a66cSDavid du Colombier 			if((i & 1) == 0)
7165e96a66cSDavid du Colombier 				c <<= 4;
7175e96a66cSDavid du Colombier 			buf[i>>1] |= c;
7185e96a66cSDavid du Colombier 		}
7195e96a66cSDavid du Colombier 		memmove(b->data+offset, buf, count);
7205e96a66cSDavid du Colombier 		consPrint("\tnew: block %#ux %ud %ud %.*H\n",
7215e96a66cSDavid du Colombier 			addr, offset, count, count, b->data+offset);
7225e96a66cSDavid du Colombier 		blockDirty(b);
7235e96a66cSDavid du Colombier 	}
7245e96a66cSDavid du Colombier 
7255e96a66cSDavid du Colombier Out:
7265e96a66cSDavid du Colombier 	blockPut(b);
7275e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
7285e96a66cSDavid du Colombier 
7295e96a66cSDavid du Colombier 	return 1;
7305e96a66cSDavid du Colombier }
7315e96a66cSDavid du Colombier 
7325e96a66cSDavid du Colombier /*
7335e96a66cSDavid du Colombier  * Free a disk block.
7345e96a66cSDavid du Colombier  */
7355e96a66cSDavid du Colombier static int
7365e96a66cSDavid du Colombier fsysBfree(Fsys* fsys, int argc, char* argv[])
7375e96a66cSDavid du Colombier {
7385e96a66cSDavid du Colombier 	Fs *fs;
7395e96a66cSDavid du Colombier 	Label l;
7405e96a66cSDavid du Colombier 	char *p;
7415e96a66cSDavid du Colombier 	Block *b;
7425e96a66cSDavid du Colombier 	u32int addr;
7435e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] bfree addr ...";
7445e96a66cSDavid du Colombier 
7455e96a66cSDavid du Colombier 	ARGBEGIN{
7465e96a66cSDavid du Colombier 	default:
7475e96a66cSDavid du Colombier 		return cliError(usage);
7485e96a66cSDavid du Colombier 	}ARGEND
7495e96a66cSDavid du Colombier 	if(argc == 0)
7505e96a66cSDavid du Colombier 		return cliError(usage);
7515e96a66cSDavid du Colombier 
7525e96a66cSDavid du Colombier 	fs = fsys->fs;
7535e96a66cSDavid du Colombier 	vtRLock(fs->elk);
7545e96a66cSDavid du Colombier 	while(argc > 0){
7555e96a66cSDavid du Colombier 		addr = strtoul(argv[0], &p, 0);
7565e96a66cSDavid du Colombier 		if(*p != '\0'){
757*0c6300e7SDavid du Colombier 			consPrint("bad address - '%ud'\n", addr);
7585e96a66cSDavid du Colombier 			/* syntax error; let's stop */
7595e96a66cSDavid du Colombier 			vtRUnlock(fs->elk);
7605e96a66cSDavid du Colombier 			return 0;
7615e96a66cSDavid du Colombier 		}
7625e96a66cSDavid du Colombier 		b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
7635e96a66cSDavid du Colombier 		if(b == nil){
7645e96a66cSDavid du Colombier 			consPrint("loading %#ux: %R\n", addr);
7655e96a66cSDavid du Colombier 			continue;
7665e96a66cSDavid du Colombier 		}
7675e96a66cSDavid du Colombier 		l = b->l;
768e569ccb5SDavid du Colombier 		if(l.state == BsFree)
769e569ccb5SDavid du Colombier 			consPrint("%#ux is already free\n", addr);
770e569ccb5SDavid du Colombier 		else{
7715e96a66cSDavid du Colombier 			consPrint("label %#ux %ud %ud %ud %ud %#x\n",
7725e96a66cSDavid du Colombier 				addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
7735e96a66cSDavid du Colombier 			l.state = BsFree;
7745e96a66cSDavid du Colombier 			l.type = BtMax;
7755e96a66cSDavid du Colombier 			l.tag = 0;
7765e96a66cSDavid du Colombier 			l.epoch = 0;
7775e96a66cSDavid du Colombier 			l.epochClose = 0;
778e569ccb5SDavid du Colombier 			if(!blockSetLabel(b, &l, 0))
7795e96a66cSDavid du Colombier 				consPrint("freeing %#ux: %R\n", addr);
780e569ccb5SDavid du Colombier 		}
7815e96a66cSDavid du Colombier 		blockPut(b);
7825e96a66cSDavid du Colombier 		argc--;
7835e96a66cSDavid du Colombier 		argv++;
7845e96a66cSDavid du Colombier 	}
7855e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
7865e96a66cSDavid du Colombier 
7875e96a66cSDavid du Colombier 	return 1;
7885e96a66cSDavid du Colombier }
7895e96a66cSDavid du Colombier 
7907abd426fSDavid du Colombier static int
7917abd426fSDavid du Colombier fsysDf(Fsys *fsys, int argc, char* argv[])
7927abd426fSDavid du Colombier {
7937abd426fSDavid du Colombier 	char *usage = "usage: [fsys name] df";
7947abd426fSDavid du Colombier 	u32int used, tot, bsize;
7957abd426fSDavid du Colombier 	Fs *fs;
7967abd426fSDavid du Colombier 
7977abd426fSDavid du Colombier 	ARGBEGIN{
7987abd426fSDavid du Colombier 	default:
7997abd426fSDavid du Colombier 		return cliError(usage);
8007abd426fSDavid du Colombier 	}ARGEND
8017abd426fSDavid du Colombier 	if(argc != 0)
8027abd426fSDavid du Colombier 		return cliError(usage);
8037abd426fSDavid du Colombier 
8047abd426fSDavid du Colombier 	fs = fsys->fs;
8057abd426fSDavid du Colombier 	cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize);
806*0c6300e7SDavid du Colombier 	consPrint("\t%s: %,llud used + %,llud free = %,llud (%llud%% used)\n",
807dc5a79c1SDavid du Colombier 		fsys->name, used*(vlong)bsize, (tot-used)*(vlong)bsize,
808208510e1SDavid du Colombier 		tot*(vlong)bsize, used*100LL/tot);
8097abd426fSDavid du Colombier 	return 1;
8107abd426fSDavid du Colombier }
8117abd426fSDavid du Colombier 
8125e96a66cSDavid du Colombier /*
8135e96a66cSDavid du Colombier  * Zero an entry or a pointer.
8145e96a66cSDavid du Colombier  */
8155e96a66cSDavid du Colombier static int
8165e96a66cSDavid du Colombier fsysClrep(Fsys* fsys, int argc, char* argv[], int ch)
8175e96a66cSDavid du Colombier {
8185e96a66cSDavid du Colombier 	Fs *fs;
8195e96a66cSDavid du Colombier 	Entry e;
8205e96a66cSDavid du Colombier 	Block *b;
8215e96a66cSDavid du Colombier 	u32int addr;
8225e96a66cSDavid du Colombier 	int i, max, offset, sz;
8235e96a66cSDavid du Colombier 	uchar zero[VtEntrySize];
8245e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clr%c addr offset ...";
8255e96a66cSDavid du Colombier 
8265e96a66cSDavid du Colombier 	ARGBEGIN{
8275e96a66cSDavid du Colombier 	default:
8285e96a66cSDavid du Colombier 		return cliError(usage, ch);
8295e96a66cSDavid du Colombier 	}ARGEND
8305e96a66cSDavid du Colombier 	if(argc < 2)
8315e96a66cSDavid du Colombier 		return cliError(usage, ch);
8325e96a66cSDavid du Colombier 
8335e96a66cSDavid du Colombier 	fs = fsys->fs;
8345e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
8355e96a66cSDavid du Colombier 
8365e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
8375e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
8385e96a66cSDavid du Colombier 	if(b == nil){
8395e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
8405e96a66cSDavid du Colombier 	Err:
8415e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
8425e96a66cSDavid du Colombier 		return 0;
8435e96a66cSDavid du Colombier 	}
8445e96a66cSDavid du Colombier 
8455e96a66cSDavid du Colombier 	switch(ch){
8465e96a66cSDavid du Colombier 	default:
8475e96a66cSDavid du Colombier 		vtSetError("clrep");
8485e96a66cSDavid du Colombier 		goto Err;
8495e96a66cSDavid du Colombier 	case 'e':
8505e96a66cSDavid du Colombier 		if(b->l.type != BtDir){
8515e96a66cSDavid du Colombier 			vtSetError("wrong block type");
8525e96a66cSDavid du Colombier 			goto Err;
8535e96a66cSDavid du Colombier 		}
8545e96a66cSDavid du Colombier 		sz = VtEntrySize;
8555e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
8565e96a66cSDavid du Colombier 		entryPack(&e, zero, 0);
8575e96a66cSDavid du Colombier 		break;
8585e96a66cSDavid du Colombier 	case 'p':
8595e96a66cSDavid du Colombier 		if(b->l.type == BtDir || b->l.type == BtData){
8605e96a66cSDavid du Colombier 			vtSetError("wrong block type");
8615e96a66cSDavid du Colombier 			goto Err;
8625e96a66cSDavid du Colombier 		}
8635e96a66cSDavid du Colombier 		sz = VtScoreSize;
8645e96a66cSDavid du Colombier 		memmove(zero, vtZeroScore, VtScoreSize);
8655e96a66cSDavid du Colombier 		break;
8665e96a66cSDavid du Colombier 	}
8675e96a66cSDavid du Colombier 	max = fs->blockSize/sz;
8685e96a66cSDavid du Colombier 
8695e96a66cSDavid du Colombier 	for(i = 1; i < argc; i++){
8705e96a66cSDavid du Colombier 		offset = atoi(argv[i]);
8715e96a66cSDavid du Colombier 		if(offset >= max){
8725e96a66cSDavid du Colombier 			consPrint("\toffset %d too large (>= %d)\n", i, max);
8735e96a66cSDavid du Colombier 			continue;
8745e96a66cSDavid du Colombier 		}
8755e96a66cSDavid du Colombier 		consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz);
8765e96a66cSDavid du Colombier 		memmove(b->data+offset*sz, zero, sz);
8775e96a66cSDavid du Colombier 	}
8785e96a66cSDavid du Colombier 	blockDirty(b);
8795e96a66cSDavid du Colombier 	blockPut(b);
8805e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
8815e96a66cSDavid du Colombier 
8825e96a66cSDavid du Colombier 	return 1;
8835e96a66cSDavid du Colombier }
8845e96a66cSDavid du Colombier 
8855e96a66cSDavid du Colombier static int
8865e96a66cSDavid du Colombier fsysClre(Fsys* fsys, int argc, char* argv[])
8875e96a66cSDavid du Colombier {
8885e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'e');
8895e96a66cSDavid du Colombier }
8905e96a66cSDavid du Colombier 
8915e96a66cSDavid du Colombier static int
8925e96a66cSDavid du Colombier fsysClrp(Fsys* fsys, int argc, char* argv[])
8935e96a66cSDavid du Colombier {
8945e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'p');
8955e96a66cSDavid du Colombier }
8965e96a66cSDavid du Colombier 
8975e96a66cSDavid du Colombier static int
8985e96a66cSDavid du Colombier fsysEsearch1(File* f, char* s, u32int elo)
8995e96a66cSDavid du Colombier {
9005e96a66cSDavid du Colombier 	int n, r;
9015e96a66cSDavid du Colombier 	DirEntry de;
9025e96a66cSDavid du Colombier 	DirEntryEnum *dee;
9035e96a66cSDavid du Colombier 	File *ff;
9045e96a66cSDavid du Colombier 	Entry e, ee;
9055e96a66cSDavid du Colombier 	char *t;
9065e96a66cSDavid du Colombier 
9075e96a66cSDavid du Colombier 	dee = deeOpen(f);
9085e96a66cSDavid du Colombier 	if(dee == nil)
9095e96a66cSDavid du Colombier 		return 0;
9105e96a66cSDavid du Colombier 
9115e96a66cSDavid du Colombier 	n = 0;
9125e96a66cSDavid du Colombier 	for(;;){
9135e96a66cSDavid du Colombier 		r = deeRead(dee, &de);
9145e96a66cSDavid du Colombier 		if(r < 0){
9155e96a66cSDavid du Colombier 			consPrint("\tdeeRead %s/%s: %R\n", s, de.elem);
9165e96a66cSDavid du Colombier 			break;
9175e96a66cSDavid du Colombier 		}
9185e96a66cSDavid du Colombier 		if(r == 0)
9195e96a66cSDavid du Colombier 			break;
9205e96a66cSDavid du Colombier 		if(de.mode & ModeSnapshot){
9215e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
9225e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
9235e96a66cSDavid du Colombier 			else{
924e569ccb5SDavid du Colombier 				if(!fileGetSources(ff, &e, &ee))
9255e96a66cSDavid du Colombier 					consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem);
9265e96a66cSDavid du Colombier 				else if(e.snap != 0 && e.snap < elo){
9275e96a66cSDavid du Colombier 					consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem);
9285e96a66cSDavid du Colombier 					n++;
9295e96a66cSDavid du Colombier 				}
9305e96a66cSDavid du Colombier 				fileDecRef(ff);
9315e96a66cSDavid du Colombier 			}
9325e96a66cSDavid du Colombier 		}
9335e96a66cSDavid du Colombier 		else if(de.mode & ModeDir){
9345e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
9355e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
9365e96a66cSDavid du Colombier 			else{
937f8e525acSDavid du Colombier 				t = smprint("%s/%s", s, de.elem);
9385e96a66cSDavid du Colombier 				n += fsysEsearch1(ff, t, elo);
9395e96a66cSDavid du Colombier 				vtMemFree(t);
9405e96a66cSDavid du Colombier 				fileDecRef(ff);
9415e96a66cSDavid du Colombier 			}
9425e96a66cSDavid du Colombier 		}
9435e96a66cSDavid du Colombier 		deCleanup(&de);
9445e96a66cSDavid du Colombier 		if(r < 0)
9455e96a66cSDavid du Colombier 			break;
9465e96a66cSDavid du Colombier 	}
9475e96a66cSDavid du Colombier 	deeClose(dee);
9485e96a66cSDavid du Colombier 
9495e96a66cSDavid du Colombier 	return n;
9505e96a66cSDavid du Colombier }
9515e96a66cSDavid du Colombier 
9525e96a66cSDavid du Colombier static int
9535e96a66cSDavid du Colombier fsysEsearch(Fs* fs, char* path, u32int elo)
9545e96a66cSDavid du Colombier {
9555e96a66cSDavid du Colombier 	int n;
9565e96a66cSDavid du Colombier 	File *f;
9575e96a66cSDavid du Colombier 	DirEntry de;
9585e96a66cSDavid du Colombier 
9595e96a66cSDavid du Colombier 	f = fileOpen(fs, path);
9605e96a66cSDavid du Colombier 	if(f == nil)
9615e96a66cSDavid du Colombier 		return 0;
9625e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
9635e96a66cSDavid du Colombier 		consPrint("\tfileGetDir %s failed: %R\n", path);
9645e96a66cSDavid du Colombier 		fileDecRef(f);
9655e96a66cSDavid du Colombier 		return 0;
9665e96a66cSDavid du Colombier 	}
9675e96a66cSDavid du Colombier 	if((de.mode & ModeDir) == 0){
9685e96a66cSDavid du Colombier 		fileDecRef(f);
9695e96a66cSDavid du Colombier 		deCleanup(&de);
9705e96a66cSDavid du Colombier 		return 0;
9715e96a66cSDavid du Colombier 	}
9725e96a66cSDavid du Colombier 	deCleanup(&de);
9735e96a66cSDavid du Colombier 	n = fsysEsearch1(f, path, elo);
9745e96a66cSDavid du Colombier 	fileDecRef(f);
9755e96a66cSDavid du Colombier 	return n;
9765e96a66cSDavid du Colombier }
9775e96a66cSDavid du Colombier 
9785e96a66cSDavid du Colombier static int
9795e96a66cSDavid du Colombier fsysEpoch(Fsys* fsys, int argc, char* argv[])
9805e96a66cSDavid du Colombier {
9815e96a66cSDavid du Colombier 	Fs *fs;
982dc5a79c1SDavid du Colombier 	int force, n, remove;
9835e96a66cSDavid du Colombier 	u32int low, old;
984dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] epoch [[-ry] low]";
9855e96a66cSDavid du Colombier 
9865e96a66cSDavid du Colombier 	force = 0;
987dc5a79c1SDavid du Colombier 	remove = 0;
9885e96a66cSDavid du Colombier 	ARGBEGIN{
9895e96a66cSDavid du Colombier 	case 'y':
9905e96a66cSDavid du Colombier 		force = 1;
9915e96a66cSDavid du Colombier 		break;
992dc5a79c1SDavid du Colombier 	case 'r':
993dc5a79c1SDavid du Colombier 		remove = 1;
994dc5a79c1SDavid du Colombier 		break;
9955e96a66cSDavid du Colombier 	default:
9965e96a66cSDavid du Colombier 		return cliError(usage);
9975e96a66cSDavid du Colombier 	}ARGEND
9985e96a66cSDavid du Colombier 	if(argc > 1)
9995e96a66cSDavid du Colombier 		return cliError(usage);
10005e96a66cSDavid du Colombier 	if(argc > 0)
10015e96a66cSDavid du Colombier 		low = strtoul(argv[0], 0, 0);
10025e96a66cSDavid du Colombier 	else
10035e96a66cSDavid du Colombier 		low = ~(u32int)0;
10045e96a66cSDavid du Colombier 
10058a2c5ad0SDavid du Colombier 	if(low == 0)
10068a2c5ad0SDavid du Colombier 		return cliError("low epoch cannot be zero");
10078a2c5ad0SDavid du Colombier 
10085e96a66cSDavid du Colombier 	fs = fsys->fs;
10095e96a66cSDavid du Colombier 
10105e96a66cSDavid du Colombier 	vtRLock(fs->elk);
10115e96a66cSDavid du Colombier 	consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi);
101257195852SDavid du Colombier 	if(low == ~(u32int)0){
101357195852SDavid du Colombier 		vtRUnlock(fs->elk);
101457195852SDavid du Colombier 		return 1;
101557195852SDavid du Colombier 	}
10165e96a66cSDavid du Colombier 	n = fsysEsearch(fsys->fs, "/archive", low);
10175e96a66cSDavid du Colombier 	n += fsysEsearch(fsys->fs, "/snapshot", low);
10185e96a66cSDavid du Colombier 	consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low);
10195e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
10205e96a66cSDavid du Colombier 
10215e96a66cSDavid du Colombier 	/*
10225e96a66cSDavid du Colombier 	 * There's a small race here -- a new snapshot with epoch < low might
10235e96a66cSDavid du Colombier 	 * get introduced now that we unlocked fs->elk.  Low has to
10245e96a66cSDavid du Colombier 	 * be <= fs->ehi.  Of course, in order for this to happen low has
10255e96a66cSDavid du Colombier 	 * to be equal to the current fs->ehi _and_ a snapshot has to
10265e96a66cSDavid du Colombier 	 * run right now.  This is a small enough window that I don't care.
10275e96a66cSDavid du Colombier 	 */
10285e96a66cSDavid du Colombier 	if(n != 0 && !force){
10295e96a66cSDavid du Colombier 		consPrint("\tnot setting low epoch\n");
10305e96a66cSDavid du Colombier 		return 1;
10315e96a66cSDavid du Colombier 	}
10325e96a66cSDavid du Colombier 	old = fs->elo;
10335e96a66cSDavid du Colombier 	if(!fsEpochLow(fs, low))
10345e96a66cSDavid du Colombier 		consPrint("\tfsEpochLow: %R\n");
10355e96a66cSDavid du Colombier 	else{
10365e96a66cSDavid du Colombier 		consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old);
10375e96a66cSDavid du Colombier 		consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo);
10385e96a66cSDavid du Colombier 		if(fs->elo < low)
10395e96a66cSDavid du Colombier 			consPrint("\twarning: new low epoch < old low epoch\n");
1040dc5a79c1SDavid du Colombier 		if(force && remove)
1041dc5a79c1SDavid du Colombier 			fsSnapshotRemove(fs);
10425e96a66cSDavid du Colombier 	}
10435e96a66cSDavid du Colombier 
10445e96a66cSDavid du Colombier 	return 1;
10455e96a66cSDavid du Colombier }
10465e96a66cSDavid du Colombier 
10475e96a66cSDavid du Colombier static int
10485e96a66cSDavid du Colombier fsysCreate(Fsys* fsys, int argc, char* argv[])
10495e96a66cSDavid du Colombier {
10505e96a66cSDavid du Colombier 	int r;
10515e96a66cSDavid du Colombier 	ulong mode;
10525e96a66cSDavid du Colombier 	char *elem, *p, *path;
10535e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] create path uid gid perm";
10545e96a66cSDavid du Colombier 	DirEntry de;
10555e96a66cSDavid du Colombier 	File *file, *parent;
10565e96a66cSDavid du Colombier 
10575e96a66cSDavid du Colombier 	ARGBEGIN{
10585e96a66cSDavid du Colombier 	default:
10595e96a66cSDavid du Colombier 		return cliError(usage);
10605e96a66cSDavid du Colombier 	}ARGEND
10615e96a66cSDavid du Colombier 	if(argc != 4)
10625e96a66cSDavid du Colombier 		return cliError(usage);
10635e96a66cSDavid du Colombier 
10645e96a66cSDavid du Colombier 	if(!fsysParseMode(argv[3], &mode))
10655e96a66cSDavid du Colombier 		return cliError(usage);
10665e96a66cSDavid du Colombier 	if(mode&ModeSnapshot)
10675e96a66cSDavid du Colombier 		return cliError("create - cannot create with snapshot bit set");
10685e96a66cSDavid du Colombier 
10695e96a66cSDavid du Colombier 	if(strcmp(argv[1], uidnoworld) == 0)
10705e96a66cSDavid du Colombier 		return cliError("permission denied");
10715e96a66cSDavid du Colombier 
10725e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
10735e96a66cSDavid du Colombier 	path = vtStrDup(argv[0]);
10745e96a66cSDavid du Colombier 	if((p = strrchr(path, '/')) != nil){
10755e96a66cSDavid du Colombier 		*p++ = '\0';
10765e96a66cSDavid du Colombier 		elem = p;
10775e96a66cSDavid du Colombier 		p = path;
10785e96a66cSDavid du Colombier 		if(*p == '\0')
10795e96a66cSDavid du Colombier 			p = "/";
10805e96a66cSDavid du Colombier 	}
10815e96a66cSDavid du Colombier 	else{
10825e96a66cSDavid du Colombier 		p = "/";
10835e96a66cSDavid du Colombier 		elem = path;
10845e96a66cSDavid du Colombier 	}
1085f8e525acSDavid du Colombier 
10865e96a66cSDavid du Colombier 	r = 0;
1087f8e525acSDavid du Colombier 	if((parent = fileOpen(fsys->fs, p)) == nil)
1088f8e525acSDavid du Colombier 		goto out;
1089f8e525acSDavid du Colombier 
10905e96a66cSDavid du Colombier 	file = fileCreate(parent, elem, mode, argv[1]);
10915e96a66cSDavid du Colombier 	fileDecRef(parent);
1092f8e525acSDavid du Colombier 	if(file == nil){
1093f8e525acSDavid du Colombier 		vtSetError("create %s/%s: %R", p, elem);
1094f8e525acSDavid du Colombier 		goto out;
1095f8e525acSDavid du Colombier 	}
1096f8e525acSDavid du Colombier 
1097f8e525acSDavid du Colombier 	if(!fileGetDir(file, &de)){
1098f8e525acSDavid du Colombier 		vtSetError("stat failed after create: %R");
1099f8e525acSDavid du Colombier 		goto out1;
1100f8e525acSDavid du Colombier 	}
1101f8e525acSDavid du Colombier 
11025e96a66cSDavid du Colombier 	if(strcmp(de.gid, argv[2]) != 0){
11035e96a66cSDavid du Colombier 		vtMemFree(de.gid);
11045e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[2]);
1105f8e525acSDavid du Colombier 		if(!fileSetDir(file, &de, argv[1])){
1106f8e525acSDavid du Colombier 			vtSetError("wstat failed after create: %R");
1107f8e525acSDavid du Colombier 			goto out2;
11085e96a66cSDavid du Colombier 		}
1109f8e525acSDavid du Colombier 	}
1110f8e525acSDavid du Colombier 	r = 1;
1111f8e525acSDavid du Colombier 
1112f8e525acSDavid du Colombier out2:
11135e96a66cSDavid du Colombier 	deCleanup(&de);
1114f8e525acSDavid du Colombier out1:
11155e96a66cSDavid du Colombier 	fileDecRef(file);
1116f8e525acSDavid du Colombier out:
11175e96a66cSDavid du Colombier 	vtMemFree(path);
11185e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
11195e96a66cSDavid du Colombier 
11205e96a66cSDavid du Colombier 	return r;
11215e96a66cSDavid du Colombier }
11225e96a66cSDavid du Colombier 
11235e96a66cSDavid du Colombier static void
11245e96a66cSDavid du Colombier fsysPrintStat(char *prefix, char *file, DirEntry *de)
11255e96a66cSDavid du Colombier {
11265e96a66cSDavid du Colombier 	char buf[64];
11275e96a66cSDavid du Colombier 
11285e96a66cSDavid du Colombier 	if(prefix == nil)
11295e96a66cSDavid du Colombier 		prefix = "";
11305e96a66cSDavid du Colombier 	consPrint("%sstat %q %q %q %q %s %llud\n", prefix,
11315e96a66cSDavid du Colombier 		file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size);
11325e96a66cSDavid du Colombier }
11335e96a66cSDavid du Colombier 
11345e96a66cSDavid du Colombier static int
11355e96a66cSDavid du Colombier fsysStat(Fsys* fsys, int argc, char* argv[])
11365e96a66cSDavid du Colombier {
11375e96a66cSDavid du Colombier 	int i;
11385e96a66cSDavid du Colombier 	File *f;
11395e96a66cSDavid du Colombier 	DirEntry de;
11405e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] stat files...";
11415e96a66cSDavid du Colombier 
11425e96a66cSDavid du Colombier 	ARGBEGIN{
11435e96a66cSDavid du Colombier 	default:
11445e96a66cSDavid du Colombier 		return cliError(usage);
11455e96a66cSDavid du Colombier 	}ARGEND
11465e96a66cSDavid du Colombier 
11475e96a66cSDavid du Colombier 	if(argc == 0)
11485e96a66cSDavid du Colombier 		return cliError(usage);
11495e96a66cSDavid du Colombier 
11505e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
11515e96a66cSDavid du Colombier 	for(i=0; i<argc; i++){
11525e96a66cSDavid du Colombier 		if((f = fileOpen(fsys->fs, argv[i])) == nil){
1153*0c6300e7SDavid du Colombier 			consPrint("%s: %R\n", argv[i]);
11545e96a66cSDavid du Colombier 			continue;
11555e96a66cSDavid du Colombier 		}
11565e96a66cSDavid du Colombier 		if(!fileGetDir(f, &de)){
1157*0c6300e7SDavid du Colombier 			consPrint("%s: %R\n", argv[i]);
11585e96a66cSDavid du Colombier 			fileDecRef(f);
11595e96a66cSDavid du Colombier 			continue;
11605e96a66cSDavid du Colombier 		}
11615e96a66cSDavid du Colombier 		fsysPrintStat("\t", argv[i], &de);
11625e96a66cSDavid du Colombier 		deCleanup(&de);
11635e96a66cSDavid du Colombier 		fileDecRef(f);
11645e96a66cSDavid du Colombier 	}
11655e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
11665e96a66cSDavid du Colombier 	return 1;
11675e96a66cSDavid du Colombier }
11685e96a66cSDavid du Colombier 
11695e96a66cSDavid du Colombier static int
11705e96a66cSDavid du Colombier fsysWstat(Fsys *fsys, int argc, char* argv[])
11715e96a66cSDavid du Colombier {
11725e96a66cSDavid du Colombier 	File *f;
11735e96a66cSDavid du Colombier 	char *p;
11745e96a66cSDavid du Colombier 	DirEntry de;
11755e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n"
11765e96a66cSDavid du Colombier 		"\tuse - for any field to mean don't change";
11775e96a66cSDavid du Colombier 
11785e96a66cSDavid du Colombier 	ARGBEGIN{
11795e96a66cSDavid du Colombier 	default:
11805e96a66cSDavid du Colombier 		return cliError(usage);
11815e96a66cSDavid du Colombier 	}ARGEND
11825e96a66cSDavid du Colombier 
11835e96a66cSDavid du Colombier 	if(argc != 6)
11845e96a66cSDavid du Colombier 		return cliError(usage);
11855e96a66cSDavid du Colombier 
11865e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
11875e96a66cSDavid du Colombier 	if((f = fileOpen(fsys->fs, argv[0])) == nil){
11885e96a66cSDavid du Colombier 		vtSetError("console wstat - walk - %R");
11895e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
11905e96a66cSDavid du Colombier 		return 0;
11915e96a66cSDavid du Colombier 	}
11925e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
11935e96a66cSDavid du Colombier 		vtSetError("console wstat - stat - %R");
11945e96a66cSDavid du Colombier 		fileDecRef(f);
11955e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
11965e96a66cSDavid du Colombier 		return 0;
11975e96a66cSDavid du Colombier 	}
11985e96a66cSDavid du Colombier 	fsysPrintStat("\told: w", argv[0], &de);
11995e96a66cSDavid du Colombier 
12005e96a66cSDavid du Colombier 	if(strcmp(argv[1], "-") != 0){
12015e96a66cSDavid du Colombier 		if(!validFileName(argv[1])){
12025e96a66cSDavid du Colombier 			vtSetError("console wstat - bad elem");
12035e96a66cSDavid du Colombier 			goto error;
12045e96a66cSDavid du Colombier 		}
12055e96a66cSDavid du Colombier 		vtMemFree(de.elem);
12065e96a66cSDavid du Colombier 		de.elem = vtStrDup(argv[1]);
12075e96a66cSDavid du Colombier 	}
12085e96a66cSDavid du Colombier 	if(strcmp(argv[2], "-") != 0){
12095e96a66cSDavid du Colombier 		if(!validUserName(argv[2])){
12105e96a66cSDavid du Colombier 			vtSetError("console wstat - bad uid");
12115e96a66cSDavid du Colombier 			goto error;
12125e96a66cSDavid du Colombier 		}
12135e96a66cSDavid du Colombier 		vtMemFree(de.uid);
12145e96a66cSDavid du Colombier 		de.uid = vtStrDup(argv[2]);
12155e96a66cSDavid du Colombier 	}
12165e96a66cSDavid du Colombier 	if(strcmp(argv[3], "-") != 0){
12175e96a66cSDavid du Colombier 		if(!validUserName(argv[3])){
12185e96a66cSDavid du Colombier 			vtSetError("console wstat - bad gid");
12195e96a66cSDavid du Colombier 			goto error;
12205e96a66cSDavid du Colombier 		}
12215e96a66cSDavid du Colombier 		vtMemFree(de.gid);
12225e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[3]);
12235e96a66cSDavid du Colombier 	}
12245e96a66cSDavid du Colombier 	if(strcmp(argv[4], "-") != 0){
12255e96a66cSDavid du Colombier 		if(!fsysParseMode(argv[4], &de.mode)){
12265e96a66cSDavid du Colombier 			vtSetError("console wstat - bad mode");
12275e96a66cSDavid du Colombier 			goto error;
12285e96a66cSDavid du Colombier 		}
12295e96a66cSDavid du Colombier 	}
12305e96a66cSDavid du Colombier 	if(strcmp(argv[5], "-") != 0){
12315e96a66cSDavid du Colombier 		de.size = strtoull(argv[5], &p, 0);
123222a127bbSDavid du Colombier 		if(argv[5][0] == '\0' || *p != '\0' || (vlong)de.size < 0){
12335e96a66cSDavid du Colombier 			vtSetError("console wstat - bad length");
12345e96a66cSDavid du Colombier 			goto error;
12355e96a66cSDavid du Colombier 		}
12365e96a66cSDavid du Colombier 	}
12375e96a66cSDavid du Colombier 
12385e96a66cSDavid du Colombier 	if(!fileSetDir(f, &de, uidadm)){
12395e96a66cSDavid du Colombier 		vtSetError("console wstat - %R");
12405e96a66cSDavid du Colombier 		goto error;
12415e96a66cSDavid du Colombier 	}
12425e96a66cSDavid du Colombier 	deCleanup(&de);
12435e96a66cSDavid du Colombier 
12445e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
12455e96a66cSDavid du Colombier 		vtSetError("console wstat - stat2 - %R");
12465e96a66cSDavid du Colombier 		goto error;
12475e96a66cSDavid du Colombier 	}
12485e96a66cSDavid du Colombier 	fsysPrintStat("\tnew: w", argv[0], &de);
12495e96a66cSDavid du Colombier 	deCleanup(&de);
12505e96a66cSDavid du Colombier 	fileDecRef(f);
12515e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
12525e96a66cSDavid du Colombier 
12535e96a66cSDavid du Colombier 	return 1;
12545e96a66cSDavid du Colombier 
12555e96a66cSDavid du Colombier error:
12565e96a66cSDavid du Colombier 	deCleanup(&de);	/* okay to do this twice */
12575e96a66cSDavid du Colombier 	fileDecRef(f);
12585e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
12595e96a66cSDavid du Colombier 	return 0;
12605e96a66cSDavid du Colombier }
12615e96a66cSDavid du Colombier 
1262e569ccb5SDavid du Colombier static void
1263e569ccb5SDavid du Colombier fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b)
1264e569ccb5SDavid du Colombier {
1265e569ccb5SDavid du Colombier 	USED(name);
1266e569ccb5SDavid du Colombier 
1267e569ccb5SDavid du Colombier 	if((fsck->flags&DoClri) == 0)
1268e569ccb5SDavid du Colombier 		return;
1269e569ccb5SDavid du Colombier 
1270e569ccb5SDavid du Colombier 	mbDelete(mb, i);
1271e569ccb5SDavid du Colombier 	mbPack(mb);
1272e569ccb5SDavid du Colombier 	blockDirty(b);
1273e569ccb5SDavid du Colombier }
1274e569ccb5SDavid du Colombier 
1275e569ccb5SDavid du Colombier static void
1276e569ccb5SDavid du Colombier fsckClose(Fsck *fsck, Block *b, u32int epoch)
1277e569ccb5SDavid du Colombier {
1278e569ccb5SDavid du Colombier 	Label l;
1279e569ccb5SDavid du Colombier 
1280e569ccb5SDavid du Colombier 	if((fsck->flags&DoClose) == 0)
1281e569ccb5SDavid du Colombier 		return;
1282e569ccb5SDavid du Colombier 	l = b->l;
1283e569ccb5SDavid du Colombier 	if(l.state == BsFree || (l.state&BsClosed)){
1284e569ccb5SDavid du Colombier 		consPrint("%#ux is already closed\n", b->addr);
1285e569ccb5SDavid du Colombier 		return;
1286e569ccb5SDavid du Colombier 	}
1287e569ccb5SDavid du Colombier 	if(epoch){
1288e569ccb5SDavid du Colombier 		l.state |= BsClosed;
1289e569ccb5SDavid du Colombier 		l.epochClose = epoch;
1290e569ccb5SDavid du Colombier 	}else
1291e569ccb5SDavid du Colombier 		l.state = BsFree;
1292e569ccb5SDavid du Colombier 
1293e569ccb5SDavid du Colombier 	if(!blockSetLabel(b, &l, 0))
1294e569ccb5SDavid du Colombier 		consPrint("%#ux setlabel: %R\n", b->addr);
1295e569ccb5SDavid du Colombier }
1296e569ccb5SDavid du Colombier 
1297e569ccb5SDavid du Colombier static void
1298e569ccb5SDavid du Colombier fsckClre(Fsck *fsck, Block *b, int offset)
1299e569ccb5SDavid du Colombier {
1300e569ccb5SDavid du Colombier 	Entry e;
1301e569ccb5SDavid du Colombier 
1302e569ccb5SDavid du Colombier 	if((fsck->flags&DoClre) == 0)
1303e569ccb5SDavid du Colombier 		return;
1304e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtEntrySize >= fsck->bsize){
1305e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1306e569ccb5SDavid du Colombier 		return;
1307e569ccb5SDavid du Colombier 	}
1308e569ccb5SDavid du Colombier 	memset(&e, 0, sizeof e);
1309e569ccb5SDavid du Colombier 	entryPack(&e, b->data, offset);
1310e569ccb5SDavid du Colombier 	blockDirty(b);
1311e569ccb5SDavid du Colombier }
1312e569ccb5SDavid du Colombier 
1313e569ccb5SDavid du Colombier static void
1314e569ccb5SDavid du Colombier fsckClrp(Fsck *fsck, Block *b, int offset)
1315e569ccb5SDavid du Colombier {
1316e569ccb5SDavid du Colombier 	if((fsck->flags&DoClrp) == 0)
1317e569ccb5SDavid du Colombier 		return;
1318e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtScoreSize >= fsck->bsize){
1319e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1320e569ccb5SDavid du Colombier 		return;
1321e569ccb5SDavid du Colombier 	}
1322e569ccb5SDavid du Colombier 	memmove(b->data+offset*VtScoreSize, vtZeroScore, VtScoreSize);
1323e569ccb5SDavid du Colombier 	blockDirty(b);
1324e569ccb5SDavid du Colombier }
1325e569ccb5SDavid du Colombier 
1326e569ccb5SDavid du Colombier static int
1327e569ccb5SDavid du Colombier fsysCheck(Fsys *fsys, int argc, char *argv[])
1328e569ccb5SDavid du Colombier {
1329e569ccb5SDavid du Colombier 	int i, halting;
1330e569ccb5SDavid du Colombier 	char *usage = "usage: [fsys name] check [-v] [options]";
1331e569ccb5SDavid du Colombier 	Fsck fsck;
1332e569ccb5SDavid du Colombier 	Block *b;
1333e569ccb5SDavid du Colombier 	Super super;
1334e569ccb5SDavid du Colombier 
1335e569ccb5SDavid du Colombier 	memset(&fsck, 0, sizeof fsck);
1336e569ccb5SDavid du Colombier 	fsck.fs = fsys->fs;
1337e569ccb5SDavid du Colombier 	fsck.clri = fsckClri;
1338e569ccb5SDavid du Colombier 	fsck.clre = fsckClre;
1339e569ccb5SDavid du Colombier 	fsck.clrp = fsckClrp;
1340e569ccb5SDavid du Colombier 	fsck.close = fsckClose;
1341e569ccb5SDavid du Colombier 	fsck.print = consPrint;
1342e569ccb5SDavid du Colombier 
1343e569ccb5SDavid du Colombier 	ARGBEGIN{
1344e569ccb5SDavid du Colombier 	default:
1345e569ccb5SDavid du Colombier 		return cliError(usage);
1346e569ccb5SDavid du Colombier 	}ARGEND
1347e569ccb5SDavid du Colombier 
1348e569ccb5SDavid du Colombier 	for(i=0; i<argc; i++){
1349e569ccb5SDavid du Colombier 		if(strcmp(argv[i], "pblock") == 0)
1350e569ccb5SDavid du Colombier 			fsck.printblocks = 1;
1351e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pdir") == 0)
1352e569ccb5SDavid du Colombier 			fsck.printdirs = 1;
1353e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pfile") == 0)
1354e569ccb5SDavid du Colombier 			fsck.printfiles = 1;
1355e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "bclose") == 0)
1356e569ccb5SDavid du Colombier 			fsck.flags |= DoClose;
1357e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clri") == 0)
1358e569ccb5SDavid du Colombier 			fsck.flags |= DoClri;
1359e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clre") == 0)
1360e569ccb5SDavid du Colombier 			fsck.flags |= DoClre;
1361e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clrp") == 0)
1362e569ccb5SDavid du Colombier 			fsck.flags |= DoClrp;
1363e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "fix") == 0)
1364e569ccb5SDavid du Colombier 			fsck.flags |= DoClose|DoClri|DoClre|DoClrp;
1365e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "venti") == 0)
1366e569ccb5SDavid du Colombier 			fsck.useventi = 1;
1367e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "snapshot") == 0)
1368e569ccb5SDavid du Colombier 			fsck.walksnapshots = 1;
1369e569ccb5SDavid du Colombier 		else{
1370e569ccb5SDavid du Colombier 			consPrint("unknown option '%s'\n", argv[i]);
1371e569ccb5SDavid du Colombier 			return cliError(usage);
1372e569ccb5SDavid du Colombier 		}
1373e569ccb5SDavid du Colombier 	}
1374e569ccb5SDavid du Colombier 
1375e569ccb5SDavid du Colombier 	halting = fsys->fs->halted==0;
1376e569ccb5SDavid du Colombier 	if(halting)
1377e569ccb5SDavid du Colombier 		fsHalt(fsys->fs);
1378e569ccb5SDavid du Colombier 	if(fsys->fs->arch){
1379e569ccb5SDavid du Colombier 		b = superGet(fsys->fs->cache, &super);
1380e569ccb5SDavid du Colombier 		if(b == nil){
1381e569ccb5SDavid du Colombier 			consPrint("could not load super block\n");
1382e569ccb5SDavid du Colombier 			goto Out;
1383e569ccb5SDavid du Colombier 		}
1384e569ccb5SDavid du Colombier 		blockPut(b);
1385e569ccb5SDavid du Colombier 		if(super.current != NilBlock){
1386e569ccb5SDavid du Colombier 			consPrint("cannot check fs while archiver is running; wait for it to finish\n");
1387e569ccb5SDavid du Colombier 			goto Out;
1388e569ccb5SDavid du Colombier 		}
1389e569ccb5SDavid du Colombier 	}
1390e569ccb5SDavid du Colombier 	fsCheck(&fsck);
1391e569ccb5SDavid du Colombier 	consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n",
1392e569ccb5SDavid du Colombier 		fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose);
1393e569ccb5SDavid du Colombier Out:
1394e569ccb5SDavid du Colombier 	if(halting)
1395e569ccb5SDavid du Colombier 		fsUnhalt(fsys->fs);
1396e569ccb5SDavid du Colombier 	return 1;
1397e569ccb5SDavid du Colombier }
1398e569ccb5SDavid du Colombier 
13995e96a66cSDavid du Colombier static int
14005e96a66cSDavid du Colombier fsysVenti(char* name, int argc, char* argv[])
14015e96a66cSDavid du Colombier {
14025e96a66cSDavid du Colombier 	int r;
14035e96a66cSDavid du Colombier 	char *host;
14045e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] venti [address]";
14055e96a66cSDavid du Colombier 	Fsys *fsys;
14065e96a66cSDavid du Colombier 
14075e96a66cSDavid du Colombier 	ARGBEGIN{
14085e96a66cSDavid du Colombier 	default:
14095e96a66cSDavid du Colombier 		return cliError(usage);
14105e96a66cSDavid du Colombier 	}ARGEND
14115e96a66cSDavid du Colombier 
14125e96a66cSDavid du Colombier 	if(argc == 0)
14135e96a66cSDavid du Colombier 		host = nil;
14145e96a66cSDavid du Colombier 	else if(argc == 1)
14155e96a66cSDavid du Colombier 		host = argv[0];
14165e96a66cSDavid du Colombier 	else
14175e96a66cSDavid du Colombier 		return cliError(usage);
14185e96a66cSDavid du Colombier 
14195e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
14205e96a66cSDavid du Colombier 		return 0;
14215e96a66cSDavid du Colombier 
14225e96a66cSDavid du Colombier 	vtLock(fsys->lock);
14235e96a66cSDavid du Colombier 	if(host == nil)
14245e96a66cSDavid du Colombier 		host = fsys->venti;
14255e96a66cSDavid du Colombier 	else{
14265e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
14275e96a66cSDavid du Colombier 		if(host[0])
14285e96a66cSDavid du Colombier 			fsys->venti = vtStrDup(host);
14295e96a66cSDavid du Colombier 		else{
14305e96a66cSDavid du Colombier 			host = nil;
14315e96a66cSDavid du Colombier 			fsys->venti = nil;
14325e96a66cSDavid du Colombier 		}
14335e96a66cSDavid du Colombier 	}
14345e96a66cSDavid du Colombier 
14355e96a66cSDavid du Colombier 	/* already open: do a redial */
14365e96a66cSDavid du Colombier 	if(fsys->fs != nil){
14376042bf6dSDavid du Colombier 		if(fsys->session == nil){
14386042bf6dSDavid du Colombier 			vtSetError("file system was opened with -V");
14396042bf6dSDavid du Colombier 			r = 0;
14406042bf6dSDavid du Colombier 			goto out;
14416042bf6dSDavid du Colombier 		}
14425e96a66cSDavid du Colombier 		r = 1;
14435e96a66cSDavid du Colombier 		if(!vtRedial(fsys->session, host)
14445e96a66cSDavid du Colombier 		|| !vtConnect(fsys->session, 0))
14455e96a66cSDavid du Colombier 			r = 0;
14466042bf6dSDavid du Colombier 		goto out;
14475e96a66cSDavid du Colombier 	}
14485e96a66cSDavid du Colombier 
14495e96a66cSDavid du Colombier 	/* not yet open: try to dial */
14505e96a66cSDavid du Colombier 	if(fsys->session)
14515e96a66cSDavid du Colombier 		vtClose(fsys->session);
14525e96a66cSDavid du Colombier 	r = 1;
14535e96a66cSDavid du Colombier 	if((fsys->session = vtDial(host, 0)) == nil
14545e96a66cSDavid du Colombier 	|| !vtConnect(fsys->session, 0))
14555e96a66cSDavid du Colombier 		r = 0;
14566042bf6dSDavid du Colombier out:
14575e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
14585e96a66cSDavid du Colombier 	fsysPut(fsys);
14595e96a66cSDavid du Colombier 	return r;
14605e96a66cSDavid du Colombier }
14615e96a66cSDavid du Colombier 
14625e96a66cSDavid du Colombier static int
14635e96a66cSDavid du Colombier fsysOpen(char* name, int argc, char* argv[])
14645e96a66cSDavid du Colombier {
14655e96a66cSDavid du Colombier 	char *p, *host;
14665e96a66cSDavid du Colombier 	Fsys *fsys;
14675e96a66cSDavid du Colombier 	long ncache;
14686042bf6dSDavid du Colombier 	int noauth, noventi, noperm, rflag, wstatallow;
14696042bf6dSDavid du Colombier 	char *usage = "usage: fsys name open [-APVWr] [-c ncache]";
14705e96a66cSDavid du Colombier 
14715e96a66cSDavid du Colombier 	ncache = 1000;
14726042bf6dSDavid du Colombier 	noauth = noperm = wstatallow = noventi = 0;
14735e96a66cSDavid du Colombier 	rflag = OReadWrite;
14745e96a66cSDavid du Colombier 
14755e96a66cSDavid du Colombier 	ARGBEGIN{
14765e96a66cSDavid du Colombier 	default:
14775e96a66cSDavid du Colombier 		return cliError(usage);
14785e96a66cSDavid du Colombier 	case 'A':
14795e96a66cSDavid du Colombier 		noauth = 1;
14805e96a66cSDavid du Colombier 		break;
14815e96a66cSDavid du Colombier 	case 'P':
14825e96a66cSDavid du Colombier 		noperm = 1;
14835e96a66cSDavid du Colombier 		break;
14846042bf6dSDavid du Colombier 	case 'V':
14856042bf6dSDavid du Colombier 		noventi = 1;
14866042bf6dSDavid du Colombier 		break;
14875e96a66cSDavid du Colombier 	case 'W':
14885e96a66cSDavid du Colombier 		wstatallow = 1;
14895e96a66cSDavid du Colombier 		break;
14905e96a66cSDavid du Colombier 	case 'c':
14915e96a66cSDavid du Colombier 		p = ARGF();
14925e96a66cSDavid du Colombier 		if(p == nil)
14935e96a66cSDavid du Colombier 			return cliError(usage);
14945e96a66cSDavid du Colombier 		ncache = strtol(argv[0], &p, 0);
14955e96a66cSDavid du Colombier 		if(ncache <= 0 || p == argv[0] || *p != '\0')
14965e96a66cSDavid du Colombier 			return cliError(usage);
14975e96a66cSDavid du Colombier 		break;
14985e96a66cSDavid du Colombier 	case 'r':
14995e96a66cSDavid du Colombier 		rflag = OReadOnly;
15005e96a66cSDavid du Colombier 		break;
15015e96a66cSDavid du Colombier 	}ARGEND
15025e96a66cSDavid du Colombier 	if(argc)
15035e96a66cSDavid du Colombier 		return cliError(usage);
15045e96a66cSDavid du Colombier 
15055e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
15065e96a66cSDavid du Colombier 		return 0;
15075e96a66cSDavid du Colombier 
15085e96a66cSDavid du Colombier 	vtLock(fsys->lock);
15095e96a66cSDavid du Colombier 	if(fsys->fs != nil){
15105e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
15115e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
15125e96a66cSDavid du Colombier 		fsysPut(fsys);
15135e96a66cSDavid du Colombier 		return 0;
15145e96a66cSDavid du Colombier 	}
15155e96a66cSDavid du Colombier 
15167611b47fSDavid du Colombier 	if(noventi){
15177611b47fSDavid du Colombier 		if(fsys->session){
15187611b47fSDavid du Colombier 			vtClose(fsys->session);
15197611b47fSDavid du Colombier 			fsys->session = nil;
15207611b47fSDavid du Colombier 		}
15217611b47fSDavid du Colombier 	}
15227611b47fSDavid du Colombier 	else if(fsys->session == nil){
15235e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
15245e96a66cSDavid du Colombier 			host = fsys->venti;
15255e96a66cSDavid du Colombier 		else
15265e96a66cSDavid du Colombier 			host = nil;
15275e96a66cSDavid du Colombier 		fsys->session = vtDial(host, 1);
15286042bf6dSDavid du Colombier 		if(!vtConnect(fsys->session, nil) && !noventi)
152961201b97SDavid du Colombier 			fprint(2, "warning: connecting to venti: %R\n");
15305e96a66cSDavid du Colombier 	}
15315e96a66cSDavid du Colombier 	if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
1532dc5a79c1SDavid du Colombier 		vtSetError("fsOpen: %R");
15335e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
15345e96a66cSDavid du Colombier 		fsysPut(fsys);
15355e96a66cSDavid du Colombier 		return 0;
15365e96a66cSDavid du Colombier 	}
1537*0c6300e7SDavid du Colombier 	fsys->fs->name = fsys->name;	/* for better error messages */
15385e96a66cSDavid du Colombier 	fsys->noauth = noauth;
15395e96a66cSDavid du Colombier 	fsys->noperm = noperm;
15405e96a66cSDavid du Colombier 	fsys->wstatallow = wstatallow;
15415e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
15425e96a66cSDavid du Colombier 	fsysPut(fsys);
15435e96a66cSDavid du Colombier 
154481cf8742SDavid du Colombier 	if(strcmp(name, "main") == 0)
154581cf8742SDavid du Colombier 		usersFileRead(nil);
154681cf8742SDavid du Colombier 
15475e96a66cSDavid du Colombier 	return 1;
15485e96a66cSDavid du Colombier }
15495e96a66cSDavid du Colombier 
15505e96a66cSDavid du Colombier static int
15515e96a66cSDavid du Colombier fsysUnconfig(char* name, int argc, char* argv[])
15525e96a66cSDavid du Colombier {
15535e96a66cSDavid du Colombier 	Fsys *fsys, **fp;
15545e96a66cSDavid du Colombier 	char *usage = "usage: fsys name unconfig";
15555e96a66cSDavid du Colombier 
15565e96a66cSDavid du Colombier 	ARGBEGIN{
15575e96a66cSDavid du Colombier 	default:
15585e96a66cSDavid du Colombier 		return cliError(usage);
15595e96a66cSDavid du Colombier 	}ARGEND
15605e96a66cSDavid du Colombier 	if(argc)
15615e96a66cSDavid du Colombier 		return cliError(usage);
15625e96a66cSDavid du Colombier 
15635e96a66cSDavid du Colombier 	vtLock(sbox.lock);
15645e96a66cSDavid du Colombier 	fp = &sbox.head;
15655e96a66cSDavid du Colombier 	for(fsys = *fp; fsys != nil; fsys = fsys->next){
15665e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) == 0)
15675e96a66cSDavid du Colombier 			break;
15685e96a66cSDavid du Colombier 		fp = &fsys->next;
15695e96a66cSDavid du Colombier 	}
15705e96a66cSDavid du Colombier 	if(fsys == nil){
15715e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
15725e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
15735e96a66cSDavid du Colombier 		return 0;
15745e96a66cSDavid du Colombier 	}
15755e96a66cSDavid du Colombier 	if(fsys->ref != 0 || fsys->fs != nil){
15765e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
15775e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
15785e96a66cSDavid du Colombier 		return 0;
15795e96a66cSDavid du Colombier 	}
15805e96a66cSDavid du Colombier 	*fp = fsys->next;
15815e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
15825e96a66cSDavid du Colombier 
15835e96a66cSDavid du Colombier 	if(fsys->session != nil){
15845e96a66cSDavid du Colombier 		vtClose(fsys->session);
15855e96a66cSDavid du Colombier 		vtFree(fsys->session);
15865e96a66cSDavid du Colombier 	}
15875e96a66cSDavid du Colombier 	if(fsys->venti != nil)
15885e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
15895e96a66cSDavid du Colombier 	if(fsys->dev != nil)
15905e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
15915e96a66cSDavid du Colombier 	if(fsys->name != nil)
15925e96a66cSDavid du Colombier 		vtMemFree(fsys->name);
15935e96a66cSDavid du Colombier 	vtMemFree(fsys);
15945e96a66cSDavid du Colombier 
15955e96a66cSDavid du Colombier 	return 1;
15965e96a66cSDavid du Colombier }
15975e96a66cSDavid du Colombier 
15985e96a66cSDavid du Colombier static int
15995e96a66cSDavid du Colombier fsysConfig(char* name, int argc, char* argv[])
16005e96a66cSDavid du Colombier {
16015e96a66cSDavid du Colombier 	Fsys *fsys;
16025e96a66cSDavid du Colombier 	char *usage = "usage: fsys name config dev";
16035e96a66cSDavid du Colombier 
16045e96a66cSDavid du Colombier 	ARGBEGIN{
16055e96a66cSDavid du Colombier 	default:
16065e96a66cSDavid du Colombier 		return cliError(usage);
16075e96a66cSDavid du Colombier 	}ARGEND
16085e96a66cSDavid du Colombier 	if(argc != 1)
16095e96a66cSDavid du Colombier 		return cliError(usage);
16105e96a66cSDavid du Colombier 
16115e96a66cSDavid du Colombier 	if((fsys = _fsysGet(argv[0])) != nil){
16125e96a66cSDavid du Colombier 		vtLock(fsys->lock);
16135e96a66cSDavid du Colombier 		if(fsys->fs != nil){
16145e96a66cSDavid du Colombier 			vtSetError(EFsysBusy, fsys->name);
16155e96a66cSDavid du Colombier 			vtUnlock(fsys->lock);
16165e96a66cSDavid du Colombier 			fsysPut(fsys);
16175e96a66cSDavid du Colombier 			return 0;
16185e96a66cSDavid du Colombier 		}
16195e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
16205e96a66cSDavid du Colombier 		fsys->dev = vtStrDup(argv[0]);
16215e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
16225e96a66cSDavid du Colombier 	}
16235e96a66cSDavid du Colombier 	else if((fsys = fsysAlloc(name, argv[0])) == nil)
16245e96a66cSDavid du Colombier 		return 0;
16255e96a66cSDavid du Colombier 
16265e96a66cSDavid du Colombier 	fsysPut(fsys);
16275e96a66cSDavid du Colombier 
16285e96a66cSDavid du Colombier 	return 1;
16295e96a66cSDavid du Colombier }
16305e96a66cSDavid du Colombier 
16315e96a66cSDavid du Colombier static struct {
16325e96a66cSDavid du Colombier 	char*	cmd;
16335e96a66cSDavid du Colombier 	int	(*f)(Fsys*, int, char**);
16345e96a66cSDavid du Colombier 	int	(*f1)(char*, int, char**);
16355e96a66cSDavid du Colombier } fsyscmd[] = {
16365e96a66cSDavid du Colombier 	{ "close",	fsysClose, },
16375e96a66cSDavid du Colombier 	{ "config",	nil, fsysConfig, },
16385e96a66cSDavid du Colombier 	{ "open",	nil, fsysOpen, },
16395e96a66cSDavid du Colombier 	{ "unconfig",	nil, fsysUnconfig, },
16405e96a66cSDavid du Colombier 	{ "venti",	nil, fsysVenti, },
16415e96a66cSDavid du Colombier 
16425e96a66cSDavid du Colombier 	{ "bfree",	fsysBfree, },
16435e96a66cSDavid du Colombier 	{ "block",	fsysBlock, },
1644e569ccb5SDavid du Colombier 	{ "check",	fsysCheck, },
16455e96a66cSDavid du Colombier 	{ "clre",	fsysClre, },
16465e96a66cSDavid du Colombier 	{ "clri",	fsysClri, },
16475e96a66cSDavid du Colombier 	{ "clrp",	fsysClrp, },
16485e96a66cSDavid du Colombier 	{ "create",	fsysCreate, },
16497abd426fSDavid du Colombier 	{ "df",		fsysDf, },
16505e96a66cSDavid du Colombier 	{ "epoch",	fsysEpoch, },
165181cf8742SDavid du Colombier 	{ "halt",	fsysHalt, },
16525e96a66cSDavid du Colombier 	{ "label",	fsysLabel, },
16535e96a66cSDavid du Colombier 	{ "remove",	fsysRemove, },
16545e96a66cSDavid du Colombier 	{ "snap",	fsysSnap, },
16555e96a66cSDavid du Colombier 	{ "snaptime",	fsysSnapTime, },
1656dc5a79c1SDavid du Colombier 	{ "snapclean",	fsysSnapClean, },
16575e96a66cSDavid du Colombier 	{ "stat",	fsysStat, },
16585e96a66cSDavid du Colombier 	{ "sync",	fsysSync, },
165981cf8742SDavid du Colombier 	{ "unhalt",	fsysUnhalt, },
16605e96a66cSDavid du Colombier 	{ "wstat",	fsysWstat, },
16615e96a66cSDavid du Colombier 	{ "vac",	fsysVac, },
16625e96a66cSDavid du Colombier 
16635e96a66cSDavid du Colombier 	{ nil,		nil, },
16645e96a66cSDavid du Colombier };
16655e96a66cSDavid du Colombier 
16665e96a66cSDavid du Colombier static int
166781cf8742SDavid du Colombier fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
166881cf8742SDavid du Colombier {
166981cf8742SDavid du Colombier 	int r;
167081cf8742SDavid du Colombier 
167181cf8742SDavid du Colombier 	vtLock(fsys->lock);
167281cf8742SDavid du Colombier 	if(fsys->fs == nil){
167381cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
167481cf8742SDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
167581cf8742SDavid du Colombier 		return 0;
167681cf8742SDavid du Colombier 	}
167781cf8742SDavid du Colombier 
1678e569ccb5SDavid du Colombier 	if(fsys->fs->halted
1679e569ccb5SDavid du Colombier 	&& fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){
168081cf8742SDavid du Colombier 		vtSetError("file system %s is halted", fsys->name);
168181cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
168281cf8742SDavid du Colombier 		return 0;
168381cf8742SDavid du Colombier 	}
168481cf8742SDavid du Colombier 
168581cf8742SDavid du Colombier 	r = (*fsyscmd[i].f)(fsys, argc, argv);
168681cf8742SDavid du Colombier 	vtUnlock(fsys->lock);
168781cf8742SDavid du Colombier 	return r;
168881cf8742SDavid du Colombier }
168981cf8742SDavid du Colombier 
169081cf8742SDavid du Colombier static int
16915e96a66cSDavid du Colombier fsysXXX(char* name, int argc, char* argv[])
16925e96a66cSDavid du Colombier {
16935e96a66cSDavid du Colombier 	int i, r;
16945e96a66cSDavid du Colombier 	Fsys *fsys;
16955e96a66cSDavid du Colombier 
16965e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
16975e96a66cSDavid du Colombier 		if(strcmp(fsyscmd[i].cmd, argv[0]) == 0)
16985e96a66cSDavid du Colombier 			break;
16995e96a66cSDavid du Colombier 	}
17005e96a66cSDavid du Colombier 
17015e96a66cSDavid du Colombier 	if(fsyscmd[i].cmd == nil){
17025e96a66cSDavid du Colombier 		vtSetError("unknown command - '%s'", argv[0]);
17035e96a66cSDavid du Colombier 		return 0;
17045e96a66cSDavid du Colombier 	}
17055e96a66cSDavid du Colombier 
17065e96a66cSDavid du Colombier 	/* some commands want the name... */
170781cf8742SDavid du Colombier 	if(fsyscmd[i].f1 != nil){
170881cf8742SDavid du Colombier 		if(strcmp(name, FsysAll) == 0){
170981cf8742SDavid du Colombier 			vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
17105e96a66cSDavid du Colombier 			return 0;
17115e96a66cSDavid du Colombier 		}
171281cf8742SDavid du Colombier 		return (*fsyscmd[i].f1)(name, argc, argv);
171381cf8742SDavid du Colombier 	}
17145e96a66cSDavid du Colombier 
171581cf8742SDavid du Colombier 	/* ... but most commands want the Fsys */
171681cf8742SDavid du Colombier 	if(strcmp(name, FsysAll) == 0){
171781cf8742SDavid du Colombier 		r = 1;
171881cf8742SDavid du Colombier 		vtRLock(sbox.lock);
171981cf8742SDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
172081cf8742SDavid du Colombier 			fsys->ref++;
172181cf8742SDavid du Colombier 			r = fsysXXX1(fsys, i, argc, argv) && r;
172281cf8742SDavid du Colombier 			fsys->ref--;
172381cf8742SDavid du Colombier 		}
172481cf8742SDavid du Colombier 		vtRUnlock(sbox.lock);
172581cf8742SDavid du Colombier 	}else{
172681cf8742SDavid du Colombier 		if((fsys = _fsysGet(name)) == nil)
172781cf8742SDavid du Colombier 			return 0;
172881cf8742SDavid du Colombier 		r = fsysXXX1(fsys, i, argc, argv);
17295e96a66cSDavid du Colombier 		fsysPut(fsys);
173081cf8742SDavid du Colombier 	}
17315e96a66cSDavid du Colombier 	return r;
17325e96a66cSDavid du Colombier }
17335e96a66cSDavid du Colombier 
17345e96a66cSDavid du Colombier static int
17355e96a66cSDavid du Colombier cmdFsysXXX(int argc, char* argv[])
17365e96a66cSDavid du Colombier {
17375e96a66cSDavid du Colombier 	char *name;
17385e96a66cSDavid du Colombier 
17395e96a66cSDavid du Colombier 	if((name = sbox.curfsys) == nil){
17405e96a66cSDavid du Colombier 		vtSetError(EFsysNoCurrent, argv[0]);
17415e96a66cSDavid du Colombier 		return 0;
17425e96a66cSDavid du Colombier 	}
17435e96a66cSDavid du Colombier 
17445e96a66cSDavid du Colombier 	return fsysXXX(name, argc, argv);
17455e96a66cSDavid du Colombier }
17465e96a66cSDavid du Colombier 
17475e96a66cSDavid du Colombier static int
17485e96a66cSDavid du Colombier cmdFsys(int argc, char* argv[])
17495e96a66cSDavid du Colombier {
17505e96a66cSDavid du Colombier 	Fsys *fsys;
17515e96a66cSDavid du Colombier 	char *usage = "usage: fsys [name ...]";
17525e96a66cSDavid du Colombier 
17535e96a66cSDavid du Colombier 	ARGBEGIN{
17545e96a66cSDavid du Colombier 	default:
17555e96a66cSDavid du Colombier 		return cliError(usage);
17565e96a66cSDavid du Colombier 	}ARGEND
17575e96a66cSDavid du Colombier 
17585e96a66cSDavid du Colombier 	if(argc == 0){
17595e96a66cSDavid du Colombier 		vtRLock(sbox.lock);
17605e96a66cSDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next)
17615e96a66cSDavid du Colombier 			consPrint("\t%s\n", fsys->name);
17625e96a66cSDavid du Colombier 		vtRUnlock(sbox.lock);
17635e96a66cSDavid du Colombier 		return 1;
17645e96a66cSDavid du Colombier 	}
17655e96a66cSDavid du Colombier 	if(argc == 1){
176681cf8742SDavid du Colombier 		fsys = nil;
176781cf8742SDavid du Colombier 		if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
17685e96a66cSDavid du Colombier 			return 0;
176981cf8742SDavid du Colombier 		sbox.curfsys = vtStrDup(argv[0]);
17705e96a66cSDavid du Colombier 		consPrompt(sbox.curfsys);
177181cf8742SDavid du Colombier 		if(fsys)
17725e96a66cSDavid du Colombier 			fsysPut(fsys);
17735e96a66cSDavid du Colombier 		return 1;
17745e96a66cSDavid du Colombier 	}
17755e96a66cSDavid du Colombier 
17765e96a66cSDavid du Colombier 	return fsysXXX(argv[0], argc-1, argv+1);
17775e96a66cSDavid du Colombier }
17785e96a66cSDavid du Colombier 
17795e96a66cSDavid du Colombier int
17805e96a66cSDavid du Colombier fsysInit(void)
17815e96a66cSDavid du Colombier {
17825e96a66cSDavid du Colombier 	int i;
17835e96a66cSDavid du Colombier 
17845e96a66cSDavid du Colombier 	fmtinstall('H', encodefmt);
17855e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
17865e96a66cSDavid du Colombier 	fmtinstall('R', vtErrFmt);
17875e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
17885e96a66cSDavid du Colombier 
17895e96a66cSDavid du Colombier 	sbox.lock = vtLockAlloc();
17905e96a66cSDavid du Colombier 
17915e96a66cSDavid du Colombier 	cliAddCmd("fsys", cmdFsys);
17925e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
17935e96a66cSDavid du Colombier 		if(fsyscmd[i].f != nil)
17945e96a66cSDavid du Colombier 			cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX);
17955e96a66cSDavid du Colombier 	}
17965e96a66cSDavid du Colombier 	/* the venti cmd is special: the fs can be either open or closed */
17975e96a66cSDavid du Colombier 	cliAddCmd("venti", cmdFsysXXX);
17985e96a66cSDavid du Colombier 	cliAddCmd("printconfig", cmdPrintConfig);
17995e96a66cSDavid du Colombier 
18005e96a66cSDavid du Colombier 	return 1;
18015e96a66cSDavid du Colombier }
1802