xref: /plan9-contrib/sys/src/cmd/fossil/9fsys.c (revision d7aba6c3b511bc618cf0c53345848188fc02611a)
15e96a66cSDavid du Colombier #include "stdinc.h"
2b8a11165SDavid du Colombier #include <bio.h>
35e96a66cSDavid du Colombier #include "dat.h"
45e96a66cSDavid du Colombier #include "fns.h"
55e96a66cSDavid du Colombier #include "9.h"
65e96a66cSDavid du Colombier 
77abd426fSDavid du Colombier struct Fsys {
8*d7aba6c3SDavid du Colombier 	QLock	lock;
95e96a66cSDavid du Colombier 
100c6300e7SDavid du Colombier 	char*	name;		/* copy here & Fs to ease error reporting */
115e96a66cSDavid du Colombier 	char*	dev;
125e96a66cSDavid du Colombier 	char*	venti;
135e96a66cSDavid du Colombier 
145e96a66cSDavid du Colombier 	Fs*	fs;
15*d7aba6c3SDavid du Colombier 	VtConn* session;
165e96a66cSDavid du Colombier 	int	ref;
175e96a66cSDavid du Colombier 
185e96a66cSDavid du Colombier 	int	noauth;
195e96a66cSDavid du Colombier 	int	noperm;
205e96a66cSDavid du Colombier 	int	wstatallow;
215e96a66cSDavid du Colombier 
225e96a66cSDavid du Colombier 	Fsys*	next;
237abd426fSDavid du Colombier };
245e96a66cSDavid du Colombier 
25b8a11165SDavid du Colombier int mempcnt;			/* from fossil.c */
26b8a11165SDavid du Colombier 
27b8a11165SDavid du Colombier int	fsGetBlockSize(Fs *fs);
28b8a11165SDavid du Colombier 
295e96a66cSDavid du Colombier static struct {
30*d7aba6c3SDavid du Colombier 	RWLock	lock;
315e96a66cSDavid du Colombier 	Fsys*	head;
325e96a66cSDavid du Colombier 	Fsys*	tail;
335e96a66cSDavid du Colombier 
345e96a66cSDavid du Colombier 	char*	curfsys;
355e96a66cSDavid du Colombier } sbox;
365e96a66cSDavid du Colombier 
375e96a66cSDavid du Colombier static char *_argv0;
385e96a66cSDavid du Colombier #define argv0 _argv0
395e96a66cSDavid du Colombier 
4081cf8742SDavid du Colombier static char FsysAll[] = "all";
4181cf8742SDavid du Colombier 
425e96a66cSDavid du Colombier static char EFsysBusy[] = "fsys: '%s' busy";
435e96a66cSDavid du Colombier static char EFsysExists[] = "fsys: '%s' already exists";
445e96a66cSDavid du Colombier static char EFsysNoCurrent[] = "fsys: no current fsys";
455e96a66cSDavid du Colombier static char EFsysNotFound[] = "fsys: '%s' not found";
465e96a66cSDavid du Colombier static char EFsysNotOpen[] = "fsys: '%s' not open";
475e96a66cSDavid du Colombier 
48ea58ad6fSDavid du Colombier static char *
ventihost(char * host)49ea58ad6fSDavid du Colombier ventihost(char *host)
50ea58ad6fSDavid du Colombier {
51ea58ad6fSDavid du Colombier 	if(host != nil)
52*d7aba6c3SDavid du Colombier 		return vtstrdup(host);
53ea58ad6fSDavid du Colombier 	host = getenv("venti");
54ea58ad6fSDavid du Colombier 	if(host == nil)
55*d7aba6c3SDavid du Colombier 		host = vtstrdup("$venti");
56ea58ad6fSDavid du Colombier 	return host;
57ea58ad6fSDavid du Colombier }
58ea58ad6fSDavid du Colombier 
59ea58ad6fSDavid du Colombier static void
prventihost(char * host)60ea58ad6fSDavid du Colombier prventihost(char *host)
61ea58ad6fSDavid du Colombier {
62ea58ad6fSDavid du Colombier 	char *vh;
63ea58ad6fSDavid du Colombier 
64ea58ad6fSDavid du Colombier 	vh = ventihost(host);
65ea58ad6fSDavid du Colombier 	fprint(2, "%s: dialing venti at %s\n",
66ea58ad6fSDavid du Colombier 		argv0, netmkaddr(vh, 0, "venti"));
67ea58ad6fSDavid du Colombier 	free(vh);
68ea58ad6fSDavid du Colombier }
69ea58ad6fSDavid du Colombier 
70*d7aba6c3SDavid du Colombier static VtConn *
myDial(char * host)71*d7aba6c3SDavid du Colombier myDial(char *host)
72ea58ad6fSDavid du Colombier {
73ea58ad6fSDavid du Colombier 	prventihost(host);
74*d7aba6c3SDavid du Colombier 	return vtdial(host);
75ea58ad6fSDavid du Colombier }
76ea58ad6fSDavid du Colombier 
77ea58ad6fSDavid du Colombier static int
myRedial(VtConn * z,char * host)78*d7aba6c3SDavid du Colombier myRedial(VtConn *z, char *host)
79ea58ad6fSDavid du Colombier {
80ea58ad6fSDavid du Colombier 	prventihost(host);
81*d7aba6c3SDavid du Colombier 	return vtredial(z, host);
82ea58ad6fSDavid du Colombier }
83ea58ad6fSDavid du Colombier 
845e96a66cSDavid du Colombier static Fsys*
_fsysGet(char * name)855e96a66cSDavid du Colombier _fsysGet(char* name)
865e96a66cSDavid du Colombier {
875e96a66cSDavid du Colombier 	Fsys *fsys;
885e96a66cSDavid du Colombier 
895e96a66cSDavid du Colombier 	if(name == nil || name[0] == '\0')
905e96a66cSDavid du Colombier 		name = "main";
915e96a66cSDavid du Colombier 
92*d7aba6c3SDavid du Colombier 	rlock(&sbox.lock);
935e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
945e96a66cSDavid du Colombier 		if(strcmp(name, fsys->name) == 0){
955e96a66cSDavid du Colombier 			fsys->ref++;
965e96a66cSDavid du Colombier 			break;
975e96a66cSDavid du Colombier 		}
985e96a66cSDavid du Colombier 	}
99*d7aba6c3SDavid du Colombier 	runlock(&sbox.lock);
1005e96a66cSDavid du Colombier 	if(fsys == nil)
101*d7aba6c3SDavid du Colombier 		werrstr(EFsysNotFound, name);
1025e96a66cSDavid du Colombier 	return fsys;
1035e96a66cSDavid du Colombier }
1045e96a66cSDavid du Colombier 
1055e96a66cSDavid du Colombier static int
cmdPrintConfig(int argc,char * argv[])1065e96a66cSDavid du Colombier cmdPrintConfig(int argc, char* argv[])
1075e96a66cSDavid du Colombier {
1085e96a66cSDavid du Colombier 	Fsys *fsys;
1095e96a66cSDavid du Colombier 	char *usage = "usage: printconfig";
1105e96a66cSDavid du Colombier 
1115e96a66cSDavid du Colombier 	ARGBEGIN{
1125e96a66cSDavid du Colombier 	default:
1135e96a66cSDavid du Colombier 		return cliError(usage);
1145e96a66cSDavid du Colombier 	}ARGEND
1155e96a66cSDavid du Colombier 
1165e96a66cSDavid du Colombier 	if(argc)
1175e96a66cSDavid du Colombier 		return cliError(usage);
1185e96a66cSDavid du Colombier 
119*d7aba6c3SDavid du Colombier 	rlock(&sbox.lock);
1205e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
1215e96a66cSDavid du Colombier 		consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev);
1225e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
1230c6300e7SDavid du Colombier 			consPrint("\tfsys %s venti %q\n", fsys->name,
1240c6300e7SDavid du Colombier 				fsys->venti);
1255e96a66cSDavid du Colombier 	}
126*d7aba6c3SDavid du Colombier 	runlock(&sbox.lock);
1275e96a66cSDavid du Colombier 	return 1;
1285e96a66cSDavid du Colombier }
1295e96a66cSDavid du Colombier 
1305e96a66cSDavid du Colombier Fsys*
fsysGet(char * name)1315e96a66cSDavid du Colombier fsysGet(char* name)
1325e96a66cSDavid du Colombier {
1335e96a66cSDavid du Colombier 	Fsys *fsys;
1345e96a66cSDavid du Colombier 
1355e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
1365e96a66cSDavid du Colombier 		return nil;
1375e96a66cSDavid du Colombier 
138*d7aba6c3SDavid du Colombier 	qlock(&fsys->lock);
1395e96a66cSDavid du Colombier 	if(fsys->fs == nil){
140*d7aba6c3SDavid du Colombier 		werrstr(EFsysNotOpen, fsys->name);
141*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
1425e96a66cSDavid du Colombier 		fsysPut(fsys);
1435e96a66cSDavid du Colombier 		return nil;
1445e96a66cSDavid du Colombier 	}
145*d7aba6c3SDavid du Colombier 	qunlock(&fsys->lock);
1465e96a66cSDavid du Colombier 
1475e96a66cSDavid du Colombier 	return fsys;
1485e96a66cSDavid du Colombier }
1495e96a66cSDavid du Colombier 
15061201b97SDavid du Colombier char*
fsysGetName(Fsys * fsys)15161201b97SDavid du Colombier fsysGetName(Fsys* fsys)
15261201b97SDavid du Colombier {
15361201b97SDavid du Colombier 	return fsys->name;
15461201b97SDavid du Colombier }
15561201b97SDavid du Colombier 
1565e96a66cSDavid du Colombier Fsys*
fsysIncRef(Fsys * fsys)1575e96a66cSDavid du Colombier fsysIncRef(Fsys* fsys)
1585e96a66cSDavid du Colombier {
159*d7aba6c3SDavid du Colombier 	wlock(&sbox.lock);
1605e96a66cSDavid du Colombier 	fsys->ref++;
161*d7aba6c3SDavid du Colombier 	wunlock(&sbox.lock);
1625e96a66cSDavid du Colombier 
1635e96a66cSDavid du Colombier 	return fsys;
1645e96a66cSDavid du Colombier }
1655e96a66cSDavid du Colombier 
1665e96a66cSDavid du Colombier void
fsysPut(Fsys * fsys)1675e96a66cSDavid du Colombier fsysPut(Fsys* fsys)
1685e96a66cSDavid du Colombier {
169*d7aba6c3SDavid du Colombier 	wlock(&sbox.lock);
1705e96a66cSDavid du Colombier 	assert(fsys->ref > 0);
1715e96a66cSDavid du Colombier 	fsys->ref--;
172*d7aba6c3SDavid du Colombier 	wunlock(&sbox.lock);
1735e96a66cSDavid du Colombier }
1745e96a66cSDavid du Colombier 
1755e96a66cSDavid du Colombier Fs*
fsysGetFs(Fsys * fsys)1765e96a66cSDavid du Colombier fsysGetFs(Fsys* fsys)
1775e96a66cSDavid du Colombier {
1785e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
1795e96a66cSDavid du Colombier 
1805e96a66cSDavid du Colombier 	return fsys->fs;
1815e96a66cSDavid du Colombier }
1825e96a66cSDavid du Colombier 
1835e96a66cSDavid du Colombier void
fsysFsRlock(Fsys * fsys)1845e96a66cSDavid du Colombier fsysFsRlock(Fsys* fsys)
1855e96a66cSDavid du Colombier {
186*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
1875e96a66cSDavid du Colombier }
1885e96a66cSDavid du Colombier 
1895e96a66cSDavid du Colombier void
fsysFsRUnlock(Fsys * fsys)1905e96a66cSDavid du Colombier fsysFsRUnlock(Fsys* fsys)
1915e96a66cSDavid du Colombier {
192*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
1935e96a66cSDavid du Colombier }
1945e96a66cSDavid du Colombier 
1955e96a66cSDavid du Colombier int
fsysNoAuthCheck(Fsys * fsys)1965e96a66cSDavid du Colombier fsysNoAuthCheck(Fsys* fsys)
1975e96a66cSDavid du Colombier {
1985e96a66cSDavid du Colombier 	return fsys->noauth;
1995e96a66cSDavid du Colombier }
2005e96a66cSDavid du Colombier 
2015e96a66cSDavid du Colombier int
fsysNoPermCheck(Fsys * fsys)2025e96a66cSDavid du Colombier fsysNoPermCheck(Fsys* fsys)
2035e96a66cSDavid du Colombier {
2045e96a66cSDavid du Colombier 	return fsys->noperm;
2055e96a66cSDavid du Colombier }
2065e96a66cSDavid du Colombier 
2075e96a66cSDavid du Colombier int
fsysWstatAllow(Fsys * fsys)2085e96a66cSDavid du Colombier fsysWstatAllow(Fsys* fsys)
2095e96a66cSDavid du Colombier {
2105e96a66cSDavid du Colombier 	return fsys->wstatallow;
2115e96a66cSDavid du Colombier }
2125e96a66cSDavid du Colombier 
2135e96a66cSDavid du Colombier static char modechars[] = "YUGalLdHSATs";
2145e96a66cSDavid du Colombier static ulong modebits[] = {
2155e96a66cSDavid du Colombier 	ModeSticky,
2165e96a66cSDavid du Colombier 	ModeSetUid,
2175e96a66cSDavid du Colombier 	ModeSetGid,
2185e96a66cSDavid du Colombier 	ModeAppend,
2195e96a66cSDavid du Colombier 	ModeExclusive,
2205e96a66cSDavid du Colombier 	ModeLink,
2215e96a66cSDavid du Colombier 	ModeDir,
2225e96a66cSDavid du Colombier 	ModeHidden,
2235e96a66cSDavid du Colombier 	ModeSystem,
2245e96a66cSDavid du Colombier 	ModeArchive,
2255e96a66cSDavid du Colombier 	ModeTemporary,
2265e96a66cSDavid du Colombier 	ModeSnapshot,
2275e96a66cSDavid du Colombier 	0
2285e96a66cSDavid du Colombier };
2295e96a66cSDavid du Colombier 
2305e96a66cSDavid du Colombier char*
fsysModeString(ulong mode,char * buf)2315e96a66cSDavid du Colombier fsysModeString(ulong mode, char *buf)
2325e96a66cSDavid du Colombier {
2335e96a66cSDavid du Colombier 	int i;
2345e96a66cSDavid du Colombier 	char *p;
2355e96a66cSDavid du Colombier 
2365e96a66cSDavid du Colombier 	p = buf;
2375e96a66cSDavid du Colombier 	for(i=0; modebits[i]; i++)
2385e96a66cSDavid du Colombier 		if(mode & modebits[i])
2395e96a66cSDavid du Colombier 			*p++ = modechars[i];
2405e96a66cSDavid du Colombier 	sprint(p, "%luo", mode&0777);
2415e96a66cSDavid du Colombier 	return buf;
2425e96a66cSDavid du Colombier }
2435e96a66cSDavid du Colombier 
2445e96a66cSDavid du Colombier int
fsysParseMode(char * s,ulong * mode)2455e96a66cSDavid du Colombier fsysParseMode(char* s, ulong* mode)
2465e96a66cSDavid du Colombier {
2475e96a66cSDavid du Colombier 	ulong x, y;
2485e96a66cSDavid du Colombier 	char *p;
2495e96a66cSDavid du Colombier 
2505e96a66cSDavid du Colombier 	x = 0;
2515e96a66cSDavid du Colombier 	for(; *s < '0' || *s > '9'; s++){
2525e96a66cSDavid du Colombier 		if(*s == 0)
2535e96a66cSDavid du Colombier 			return 0;
2545e96a66cSDavid du Colombier 		p = strchr(modechars, *s);
2555e96a66cSDavid du Colombier 		if(p == nil)
2565e96a66cSDavid du Colombier 			return 0;
2575e96a66cSDavid du Colombier 		x |= modebits[p-modechars];
2585e96a66cSDavid du Colombier 	}
2595e96a66cSDavid du Colombier 	y = strtoul(s, &p, 8);
2605e96a66cSDavid du Colombier 	if(*p != '\0' || y > 0777)
2615e96a66cSDavid du Colombier 		return 0;
2625e96a66cSDavid du Colombier 	*mode = x|y;
2635e96a66cSDavid du Colombier 	return 1;
2645e96a66cSDavid du Colombier }
2655e96a66cSDavid du Colombier 
2665e96a66cSDavid du Colombier File*
fsysGetRoot(Fsys * fsys,char * name)2675e96a66cSDavid du Colombier fsysGetRoot(Fsys* fsys, char* name)
2685e96a66cSDavid du Colombier {
2695e96a66cSDavid du Colombier 	File *root, *sub;
2705e96a66cSDavid du Colombier 
2715e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
2725e96a66cSDavid du Colombier 
2735e96a66cSDavid du Colombier 	root = fsGetRoot(fsys->fs);
2745e96a66cSDavid du Colombier 	if(name == nil || strcmp(name, "") == 0)
2755e96a66cSDavid du Colombier 		return root;
2765e96a66cSDavid du Colombier 
2775e96a66cSDavid du Colombier 	sub = fileWalk(root, name);
2785e96a66cSDavid du Colombier 	fileDecRef(root);
2795e96a66cSDavid du Colombier 
2805e96a66cSDavid du Colombier 	return sub;
2815e96a66cSDavid du Colombier }
2825e96a66cSDavid du Colombier 
2835e96a66cSDavid du Colombier static Fsys*
fsysAlloc(char * name,char * dev)2845e96a66cSDavid du Colombier fsysAlloc(char* name, char* dev)
2855e96a66cSDavid du Colombier {
2865e96a66cSDavid du Colombier 	Fsys *fsys;
2875e96a66cSDavid du Colombier 
288*d7aba6c3SDavid du Colombier 	wlock(&sbox.lock);
2895e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
2905e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) != 0)
2915e96a66cSDavid du Colombier 			continue;
292*d7aba6c3SDavid du Colombier 		werrstr(EFsysExists, name);
293*d7aba6c3SDavid du Colombier 		wunlock(&sbox.lock);
2945e96a66cSDavid du Colombier 		return nil;
2955e96a66cSDavid du Colombier 	}
2965e96a66cSDavid du Colombier 
297*d7aba6c3SDavid du Colombier 	fsys = vtmallocz(sizeof(Fsys));
298*d7aba6c3SDavid du Colombier 	fsys->name = vtstrdup(name);
299*d7aba6c3SDavid du Colombier 	fsys->dev = vtstrdup(dev);
3005e96a66cSDavid du Colombier 
3015e96a66cSDavid du Colombier 	fsys->ref = 1;
3025e96a66cSDavid du Colombier 
3035e96a66cSDavid du Colombier 	if(sbox.tail != nil)
3045e96a66cSDavid du Colombier 		sbox.tail->next = fsys;
3055e96a66cSDavid du Colombier 	else
3065e96a66cSDavid du Colombier 		sbox.head = fsys;
3075e96a66cSDavid du Colombier 	sbox.tail = fsys;
308*d7aba6c3SDavid du Colombier 	wunlock(&sbox.lock);
3095e96a66cSDavid du Colombier 
3105e96a66cSDavid du Colombier 	return fsys;
3115e96a66cSDavid du Colombier }
3125e96a66cSDavid du Colombier 
3135e96a66cSDavid du Colombier static int
fsysClose(Fsys * fsys,int argc,char * argv[])3145e96a66cSDavid du Colombier fsysClose(Fsys* fsys, int argc, char* argv[])
3155e96a66cSDavid du Colombier {
3165e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] close";
3175e96a66cSDavid du Colombier 
3185e96a66cSDavid du Colombier 	ARGBEGIN{
3195e96a66cSDavid du Colombier 	default:
3205e96a66cSDavid du Colombier 		return cliError(usage);
3215e96a66cSDavid du Colombier 	}ARGEND
3225e96a66cSDavid du Colombier 	if(argc)
3235e96a66cSDavid du Colombier 		return cliError(usage);
3245e96a66cSDavid du Colombier 
32568412abfSDavid du Colombier 	return cliError("close isn't working yet; halt %s and then kill fossil",
32668412abfSDavid du Colombier 		fsys->name);
3275e96a66cSDavid du Colombier 
3285e96a66cSDavid du Colombier 	/*
3295e96a66cSDavid du Colombier 	 * Oooh. This could be hard. What if fsys->ref != 1?
3305e96a66cSDavid du Colombier 	 * Also, fsClose() either does the job or panics, can we
3315e96a66cSDavid du Colombier 	 * gracefully detect it's still busy?
3325e96a66cSDavid du Colombier 	 *
3335e96a66cSDavid du Colombier 	 * More thought and care needed here.
3345e96a66cSDavid du Colombier 	fsClose(fsys->fs);
3355e96a66cSDavid du Colombier 	fsys->fs = nil;
336*d7aba6c3SDavid du Colombier 	vtfreeconn(fsys->session);
3375e96a66cSDavid du Colombier 	fsys->session = nil;
3385e96a66cSDavid du Colombier 
3395e96a66cSDavid du Colombier 	if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){
3405e96a66cSDavid du Colombier 		sbox.curfsys = nil;
3415e96a66cSDavid du Colombier 		consPrompt(nil);
3425e96a66cSDavid du Colombier 	}
3435e96a66cSDavid du Colombier 
3445e96a66cSDavid du Colombier 	return 1;
34568412abfSDavid du Colombier 	 */
3465e96a66cSDavid du Colombier }
3475e96a66cSDavid du Colombier 
3485e96a66cSDavid du Colombier static int
fsysVac(Fsys * fsys,int argc,char * argv[])3495e96a66cSDavid du Colombier fsysVac(Fsys* fsys, int argc, char* argv[])
3505e96a66cSDavid du Colombier {
3515e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
3525e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] vac path";
3535e96a66cSDavid du Colombier 
3545e96a66cSDavid du Colombier 	ARGBEGIN{
3555e96a66cSDavid du Colombier 	default:
3565e96a66cSDavid du Colombier 		return cliError(usage);
3575e96a66cSDavid du Colombier 	}ARGEND
3585e96a66cSDavid du Colombier 	if(argc != 1)
3595e96a66cSDavid du Colombier 		return cliError(usage);
3605e96a66cSDavid du Colombier 
3615e96a66cSDavid du Colombier 	if(!fsVac(fsys->fs, argv[0], score))
3625e96a66cSDavid du Colombier 		return 0;
3635e96a66cSDavid du Colombier 
3645e96a66cSDavid du Colombier 	consPrint("vac:%V\n", score);
3655e96a66cSDavid du Colombier 	return 1;
3665e96a66cSDavid du Colombier }
3675e96a66cSDavid du Colombier 
3685e96a66cSDavid du Colombier static int
fsysSnap(Fsys * fsys,int argc,char * argv[])3695e96a66cSDavid du Colombier fsysSnap(Fsys* fsys, int argc, char* argv[])
3705e96a66cSDavid du Colombier {
3715e96a66cSDavid du Colombier 	int doarchive;
372c3c4501eSDavid du Colombier 	char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]";
373c3c4501eSDavid du Colombier 	char *src, *dst;
3745e96a66cSDavid du Colombier 
375c3c4501eSDavid du Colombier 	src = nil;
376c3c4501eSDavid du Colombier 	dst = nil;
3775e96a66cSDavid du Colombier 	doarchive = 0;
3785e96a66cSDavid du Colombier 	ARGBEGIN{
3795e96a66cSDavid du Colombier 	default:
3805e96a66cSDavid du Colombier 		return cliError(usage);
3815e96a66cSDavid du Colombier 	case 'a':
3825e96a66cSDavid du Colombier 		doarchive = 1;
3835e96a66cSDavid du Colombier 		break;
384c3c4501eSDavid du Colombier 	case 'd':
385c3c4501eSDavid du Colombier 		if((dst = ARGF()) == nil)
386c3c4501eSDavid du Colombier 			return cliError(usage);
387c3c4501eSDavid du Colombier 		break;
388c3c4501eSDavid du Colombier 	case 's':
389c3c4501eSDavid du Colombier 		if((src = ARGF()) == nil)
390c3c4501eSDavid du Colombier 			return cliError(usage);
391c3c4501eSDavid du Colombier 		break;
3925e96a66cSDavid du Colombier 	}ARGEND
3935e96a66cSDavid du Colombier 	if(argc)
3945e96a66cSDavid du Colombier 		return cliError(usage);
3955e96a66cSDavid du Colombier 
396c3c4501eSDavid du Colombier 	if(!fsSnapshot(fsys->fs, src, dst, doarchive))
3975e96a66cSDavid du Colombier 		return 0;
3985e96a66cSDavid du Colombier 
3995e96a66cSDavid du Colombier 	return 1;
4005e96a66cSDavid du Colombier }
4015e96a66cSDavid du Colombier 
4025e96a66cSDavid du Colombier static int
fsysSnapClean(Fsys * fsys,int argc,char * argv[])403dc5a79c1SDavid du Colombier fsysSnapClean(Fsys *fsys, int argc, char* argv[])
404dc5a79c1SDavid du Colombier {
405dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
406dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snapclean [maxminutes]\n";
407dc5a79c1SDavid du Colombier 
408dc5a79c1SDavid du Colombier 	ARGBEGIN{
409dc5a79c1SDavid du Colombier 	default:
410dc5a79c1SDavid du Colombier 		return cliError(usage);
411dc5a79c1SDavid du Colombier 	}ARGEND
412dc5a79c1SDavid du Colombier 
413dc5a79c1SDavid du Colombier 	if(argc > 1)
414dc5a79c1SDavid du Colombier 		return cliError(usage);
415dc5a79c1SDavid du Colombier 	if(argc == 1)
416f83f9c78SDavid du Colombier 		life = atoi(argv[0]);
417dc5a79c1SDavid du Colombier 	else
418dc5a79c1SDavid du Colombier 		snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
419dc5a79c1SDavid du Colombier 
420dc5a79c1SDavid du Colombier 	fsSnapshotCleanup(fsys->fs, life);
421dc5a79c1SDavid du Colombier 	return 1;
422dc5a79c1SDavid du Colombier }
423dc5a79c1SDavid du Colombier 
424dc5a79c1SDavid du Colombier static int
fsysSnapTime(Fsys * fsys,int argc,char * argv[])4255e96a66cSDavid du Colombier fsysSnapTime(Fsys* fsys, int argc, char* argv[])
4265e96a66cSDavid du Colombier {
427dc5a79c1SDavid du Colombier 	char buf[128], *x;
428dc5a79c1SDavid du Colombier 	int hh, mm, changed;
429dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
430dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]";
4315e96a66cSDavid du Colombier 
432dc5a79c1SDavid du Colombier 	changed = 0;
433dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
4345e96a66cSDavid du Colombier 	ARGBEGIN{
4355e96a66cSDavid du Colombier 	case 'a':
436dc5a79c1SDavid du Colombier 		changed = 1;
4375e96a66cSDavid du Colombier 		x = ARGF();
4385e96a66cSDavid du Colombier 		if(x == nil)
4395e96a66cSDavid du Colombier 			return cliError(usage);
4405e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4415e96a66cSDavid du Colombier 			arch = ~(u32int)0;
4425e96a66cSDavid du Colombier 			break;
4435e96a66cSDavid du Colombier 		}
4445e96a66cSDavid du Colombier 		if(strlen(x) != 4 || strspn(x, "0123456789") != 4)
4455e96a66cSDavid du Colombier 			return cliError(usage);
4465e96a66cSDavid du Colombier 		hh = (x[0]-'0')*10 + x[1]-'0';
4475e96a66cSDavid du Colombier 		mm = (x[2]-'0')*10 + x[3]-'0';
4485e96a66cSDavid du Colombier 		if(hh >= 24 || mm >= 60)
4495e96a66cSDavid du Colombier 			return cliError(usage);
4505e96a66cSDavid du Colombier 		arch = hh*60+mm;
4515e96a66cSDavid du Colombier 		break;
4525e96a66cSDavid du Colombier 	case 's':
453dc5a79c1SDavid du Colombier 		changed = 1;
4545e96a66cSDavid du Colombier 		x = ARGF();
4555e96a66cSDavid du Colombier 		if(x == nil)
4565e96a66cSDavid du Colombier 			return cliError(usage);
4575e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4585e96a66cSDavid du Colombier 			snap = ~(u32int)0;
4595e96a66cSDavid du Colombier 			break;
4605e96a66cSDavid du Colombier 		}
4615e96a66cSDavid du Colombier 		snap = atoi(x);
4625e96a66cSDavid du Colombier 		break;
463dc5a79c1SDavid du Colombier 	case 't':
464dc5a79c1SDavid du Colombier 		changed = 1;
465dc5a79c1SDavid du Colombier 		x = ARGF();
466dc5a79c1SDavid du Colombier 		if(x == nil)
467dc5a79c1SDavid du Colombier 			return cliError(usage);
468dc5a79c1SDavid du Colombier 		if(strcmp(x, "none") == 0){
469dc5a79c1SDavid du Colombier 			life = ~(u32int)0;
470dc5a79c1SDavid du Colombier 			break;
471dc5a79c1SDavid du Colombier 		}
472dc5a79c1SDavid du Colombier 		life = atoi(x);
473dc5a79c1SDavid du Colombier 		break;
4745e96a66cSDavid du Colombier 	default:
4755e96a66cSDavid du Colombier 		return cliError(usage);
4765e96a66cSDavid du Colombier 	}ARGEND
4775e96a66cSDavid du Colombier 	if(argc > 0)
4785e96a66cSDavid du Colombier 		return cliError(usage);
4795e96a66cSDavid du Colombier 
480dc5a79c1SDavid du Colombier 	if(changed){
481dc5a79c1SDavid du Colombier 		snapSetTimes(fsys->fs->snap, arch, snap, life);
482dc5a79c1SDavid du Colombier 		return 1;
483dc5a79c1SDavid du Colombier 	}
484dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
4855e96a66cSDavid du Colombier 	if(arch != ~(u32int)0)
4865e96a66cSDavid du Colombier 		sprint(buf, "-a %02d%02d", arch/60, arch%60);
4875e96a66cSDavid du Colombier 	else
4885e96a66cSDavid du Colombier 		sprint(buf, "-a none");
4895e96a66cSDavid du Colombier 	if(snap != ~(u32int)0)
4905e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s %d", snap);
4915e96a66cSDavid du Colombier 	else
4925e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s none");
493dc5a79c1SDavid du Colombier 	if(life != ~(u32int)0)
494dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t %ud", life);
495dc5a79c1SDavid du Colombier 	else
496dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t none");
4975e96a66cSDavid du Colombier 	consPrint("\tsnaptime %s\n", buf);
4985e96a66cSDavid du Colombier 	return 1;
4995e96a66cSDavid du Colombier }
5005e96a66cSDavid du Colombier 
5015e96a66cSDavid du Colombier static int
fsysSync(Fsys * fsys,int argc,char * argv[])5025e96a66cSDavid du Colombier fsysSync(Fsys* fsys, int argc, char* argv[])
5035e96a66cSDavid du Colombier {
5045e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] sync";
5050b9a5132SDavid du Colombier 	int n;
5065e96a66cSDavid du Colombier 
5075e96a66cSDavid du Colombier 	ARGBEGIN{
5085e96a66cSDavid du Colombier 	default:
5095e96a66cSDavid du Colombier 		return cliError(usage);
5105e96a66cSDavid du Colombier 	}ARGEND
5115e96a66cSDavid du Colombier 	if(argc > 0)
5125e96a66cSDavid du Colombier 		return cliError(usage);
5135e96a66cSDavid du Colombier 
5140b9a5132SDavid du Colombier 	n = cacheDirty(fsys->fs->cache);
5155e96a66cSDavid du Colombier 	fsSync(fsys->fs);
5160b9a5132SDavid du Colombier 	consPrint("\t%s sync: wrote %d blocks\n", fsys->name, n);
51781cf8742SDavid du Colombier 	return 1;
51881cf8742SDavid du Colombier }
5195e96a66cSDavid du Colombier 
52081cf8742SDavid du Colombier static int
fsysHalt(Fsys * fsys,int argc,char * argv[])52181cf8742SDavid du Colombier fsysHalt(Fsys *fsys, int argc, char* argv[])
52281cf8742SDavid du Colombier {
52381cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] halt";
52481cf8742SDavid du Colombier 
52581cf8742SDavid du Colombier 	ARGBEGIN{
52681cf8742SDavid du Colombier 	default:
52781cf8742SDavid du Colombier 		return cliError(usage);
52881cf8742SDavid du Colombier 	}ARGEND
52981cf8742SDavid du Colombier 	if(argc > 0)
53081cf8742SDavid du Colombier 		return cliError(usage);
53181cf8742SDavid du Colombier 
53281cf8742SDavid du Colombier 	fsHalt(fsys->fs);
53381cf8742SDavid du Colombier 	return 1;
53481cf8742SDavid du Colombier }
53581cf8742SDavid du Colombier 
53681cf8742SDavid du Colombier static int
fsysUnhalt(Fsys * fsys,int argc,char * argv[])53781cf8742SDavid du Colombier fsysUnhalt(Fsys *fsys, int argc, char* argv[])
53881cf8742SDavid du Colombier {
53981cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] unhalt";
54081cf8742SDavid du Colombier 
54181cf8742SDavid du Colombier 	ARGBEGIN{
54281cf8742SDavid du Colombier 	default:
54381cf8742SDavid du Colombier 		return cliError(usage);
54481cf8742SDavid du Colombier 	}ARGEND
54581cf8742SDavid du Colombier 	if(argc > 0)
54681cf8742SDavid du Colombier 		return cliError(usage);
54781cf8742SDavid du Colombier 
54881cf8742SDavid du Colombier 	if(!fsys->fs->halted)
54981cf8742SDavid du Colombier 		return cliError("file system %s not halted", fsys->name);
55081cf8742SDavid du Colombier 
55181cf8742SDavid du Colombier 	fsUnhalt(fsys->fs);
5525e96a66cSDavid du Colombier 	return 1;
5535e96a66cSDavid du Colombier }
5545e96a66cSDavid du Colombier 
5555e96a66cSDavid du Colombier static int
fsysRemove(Fsys * fsys,int argc,char * argv[])5565e96a66cSDavid du Colombier fsysRemove(Fsys* fsys, int argc, char* argv[])
5575e96a66cSDavid du Colombier {
5585e96a66cSDavid du Colombier 	File *file;
5595e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] remove path ...";
5605e96a66cSDavid du Colombier 
5615e96a66cSDavid du Colombier 	ARGBEGIN{
5625e96a66cSDavid du Colombier 	default:
5635e96a66cSDavid du Colombier 		return cliError(usage);
5645e96a66cSDavid du Colombier 	}ARGEND
5655e96a66cSDavid du Colombier 	if(argc == 0)
5665e96a66cSDavid du Colombier 		return cliError(usage);
5675e96a66cSDavid du Colombier 
568*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
5695e96a66cSDavid du Colombier 	while(argc > 0){
5705e96a66cSDavid du Colombier 		if((file = fileOpen(fsys->fs, argv[0])) == nil)
571*d7aba6c3SDavid du Colombier 			consPrint("%s: %r\n", argv[0]);
5725e96a66cSDavid du Colombier 		else{
5735e96a66cSDavid du Colombier 			if(!fileRemove(file, uidadm))
574*d7aba6c3SDavid du Colombier 				consPrint("%s: %r\n", argv[0]);
5755e96a66cSDavid du Colombier 			fileDecRef(file);
5765e96a66cSDavid du Colombier 		}
5775e96a66cSDavid du Colombier 		argc--;
5785e96a66cSDavid du Colombier 		argv++;
5795e96a66cSDavid du Colombier 	}
580*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
5815e96a66cSDavid du Colombier 
5825e96a66cSDavid du Colombier 	return 1;
5835e96a66cSDavid du Colombier }
5845e96a66cSDavid du Colombier 
5855e96a66cSDavid du Colombier static int
fsysClri(Fsys * fsys,int argc,char * argv[])5865e96a66cSDavid du Colombier fsysClri(Fsys* fsys, int argc, char* argv[])
5875e96a66cSDavid du Colombier {
5885e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clri path ...";
5895e96a66cSDavid du Colombier 
5905e96a66cSDavid du Colombier 	ARGBEGIN{
5915e96a66cSDavid du Colombier 	default:
5925e96a66cSDavid du Colombier 		return cliError(usage);
5935e96a66cSDavid du Colombier 	}ARGEND
5945e96a66cSDavid du Colombier 	if(argc == 0)
5955e96a66cSDavid du Colombier 		return cliError(usage);
5965e96a66cSDavid du Colombier 
597*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
5985e96a66cSDavid du Colombier 	while(argc > 0){
599dc5a79c1SDavid du Colombier 		if(!fileClriPath(fsys->fs, argv[0], uidadm))
600*d7aba6c3SDavid du Colombier 			consPrint("clri %s: %r\n", argv[0]);
6015e96a66cSDavid du Colombier 		argc--;
6025e96a66cSDavid du Colombier 		argv++;
6035e96a66cSDavid du Colombier 	}
604*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
6055e96a66cSDavid du Colombier 
6065e96a66cSDavid du Colombier 	return 1;
6075e96a66cSDavid du Colombier }
6085e96a66cSDavid du Colombier 
6095e96a66cSDavid du Colombier /*
6105e96a66cSDavid du Colombier  * Inspect and edit the labels for blocks on disk.
6115e96a66cSDavid du Colombier  */
6125e96a66cSDavid du Colombier static int
fsysLabel(Fsys * fsys,int argc,char * argv[])6135e96a66cSDavid du Colombier fsysLabel(Fsys* fsys, int argc, char* argv[])
6145e96a66cSDavid du Colombier {
6155e96a66cSDavid du Colombier 	Fs *fs;
6165e96a66cSDavid du Colombier 	Label l;
6175e96a66cSDavid du Colombier 	int n, r;
6185e96a66cSDavid du Colombier 	u32int addr;
6195e96a66cSDavid du Colombier 	Block *b, *bb;
6205e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]";
6215e96a66cSDavid du Colombier 
6225e96a66cSDavid du Colombier 	ARGBEGIN{
6235e96a66cSDavid du Colombier 	default:
6245e96a66cSDavid du Colombier 		return cliError(usage);
6255e96a66cSDavid du Colombier 	}ARGEND
6265e96a66cSDavid du Colombier 	if(argc != 1 && argc != 6)
6275e96a66cSDavid du Colombier 		return cliError(usage);
6285e96a66cSDavid du Colombier 
6295e96a66cSDavid du Colombier 	r = 0;
630*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
6315e96a66cSDavid du Colombier 
6325e96a66cSDavid du Colombier 	fs = fsys->fs;
6335e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
6345e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
6355e96a66cSDavid du Colombier 	if(b == nil)
6365e96a66cSDavid du Colombier 		goto Out0;
6375e96a66cSDavid du Colombier 
6385e96a66cSDavid du Colombier 	l = b->l;
6395e96a66cSDavid du Colombier 	consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n",
6405e96a66cSDavid du Colombier 		argc==6 ? "old: " : "", addr, l.type, l.state,
6415e96a66cSDavid du Colombier 		l.epoch, l.epochClose, l.tag);
6425e96a66cSDavid du Colombier 
6435e96a66cSDavid du Colombier 	if(argc == 6){
6445e96a66cSDavid du Colombier 		if(strcmp(argv[1], "-") != 0)
6455e96a66cSDavid du Colombier 			l.type = atoi(argv[1]);
6465e96a66cSDavid du Colombier 		if(strcmp(argv[2], "-") != 0)
6475e96a66cSDavid du Colombier 			l.state = atoi(argv[2]);
6485e96a66cSDavid du Colombier 		if(strcmp(argv[3], "-") != 0)
6495e96a66cSDavid du Colombier 			l.epoch = strtoul(argv[3], 0, 0);
6505e96a66cSDavid du Colombier 		if(strcmp(argv[4], "-") != 0)
6515e96a66cSDavid du Colombier 			l.epochClose = strtoul(argv[4], 0, 0);
6525e96a66cSDavid du Colombier 		if(strcmp(argv[5], "-") != 0)
6535e96a66cSDavid du Colombier 			l.tag = strtoul(argv[5], 0, 0);
6545e96a66cSDavid du Colombier 
6555e96a66cSDavid du Colombier 		consPrint("new: label %#ux %ud %ud %ud %ud %#x\n",
6565e96a66cSDavid du Colombier 			addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
6575e96a66cSDavid du Colombier 		bb = _blockSetLabel(b, &l);
6585e96a66cSDavid du Colombier 		if(bb == nil)
6595e96a66cSDavid du Colombier 			goto Out1;
6605e96a66cSDavid du Colombier 		n = 0;
6615e96a66cSDavid du Colombier 		for(;;){
662e12a9870SDavid du Colombier 			if(blockWrite(bb, Waitlock)){
6635e96a66cSDavid du Colombier 				while(bb->iostate != BioClean){
6645e96a66cSDavid du Colombier 					assert(bb->iostate == BioWriting);
665*d7aba6c3SDavid du Colombier 					rsleep(&bb->ioready);
6665e96a66cSDavid du Colombier 				}
6675e96a66cSDavid du Colombier 				break;
6685e96a66cSDavid du Colombier 			}
669*d7aba6c3SDavid du Colombier 			consPrint("blockWrite: %r\n");
6705e96a66cSDavid du Colombier 			if(n++ >= 5){
6715e96a66cSDavid du Colombier 				consPrint("giving up\n");
6725e96a66cSDavid du Colombier 				break;
6735e96a66cSDavid du Colombier 			}
6745e96a66cSDavid du Colombier 			sleep(5*1000);
6755e96a66cSDavid du Colombier 		}
6765e96a66cSDavid du Colombier 		blockPut(bb);
6775e96a66cSDavid du Colombier 	}
6785e96a66cSDavid du Colombier 	r = 1;
6795e96a66cSDavid du Colombier Out1:
6805e96a66cSDavid du Colombier 	blockPut(b);
6815e96a66cSDavid du Colombier Out0:
682*d7aba6c3SDavid du Colombier 	runlock(&fs->elk);
6835e96a66cSDavid du Colombier 
6845e96a66cSDavid du Colombier 	return r;
6855e96a66cSDavid du Colombier }
6865e96a66cSDavid du Colombier 
6875e96a66cSDavid du Colombier /*
6885e96a66cSDavid du Colombier  * Inspect and edit the blocks on disk.
6895e96a66cSDavid du Colombier  */
6905e96a66cSDavid du Colombier static int
fsysBlock(Fsys * fsys,int argc,char * argv[])6915e96a66cSDavid du Colombier fsysBlock(Fsys* fsys, int argc, char* argv[])
6925e96a66cSDavid du Colombier {
6935e96a66cSDavid du Colombier 	Fs *fs;
6945e96a66cSDavid du Colombier 	char *s;
6955e96a66cSDavid du Colombier 	Block *b;
6965e96a66cSDavid du Colombier 	uchar *buf;
6975e96a66cSDavid du Colombier 	u32int addr;
6985e96a66cSDavid du Colombier 	int c, count, i, offset;
6995e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] block addr offset [count [data]]";
7005e96a66cSDavid du Colombier 
7015e96a66cSDavid du Colombier 	ARGBEGIN{
7025e96a66cSDavid du Colombier 	default:
7035e96a66cSDavid du Colombier 		return cliError(usage);
7045e96a66cSDavid du Colombier 	}ARGEND
7055e96a66cSDavid du Colombier 	if(argc < 2 || argc > 4)
7065e96a66cSDavid du Colombier 		return cliError(usage);
7075e96a66cSDavid du Colombier 
7085e96a66cSDavid du Colombier 	fs = fsys->fs;
7095e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
7105e96a66cSDavid du Colombier 	offset = strtoul(argv[1], 0, 0);
7115e96a66cSDavid du Colombier 	if(offset < 0 || offset >= fs->blockSize){
712*d7aba6c3SDavid du Colombier 		werrstr("bad offset");
7135e96a66cSDavid du Colombier 		return 0;
7145e96a66cSDavid du Colombier 	}
7155e96a66cSDavid du Colombier 	if(argc > 2)
7165e96a66cSDavid du Colombier 		count = strtoul(argv[2], 0, 0);
7175e96a66cSDavid du Colombier 	else
7185e96a66cSDavid du Colombier 		count = 100000000;
7195e96a66cSDavid du Colombier 	if(offset+count > fs->blockSize)
7205e96a66cSDavid du Colombier 		count = fs->blockSize - count;
7215e96a66cSDavid du Colombier 
722*d7aba6c3SDavid du Colombier 	rlock(&fs->elk);
7235e96a66cSDavid du Colombier 
7245e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
7255e96a66cSDavid du Colombier 	if(b == nil){
726*d7aba6c3SDavid du Colombier 		werrstr("cacheLocal %#ux: %r", addr);
727*d7aba6c3SDavid du Colombier 		runlock(&fs->elk);
7285e96a66cSDavid du Colombier 		return 0;
7295e96a66cSDavid du Colombier 	}
7305e96a66cSDavid du Colombier 
7315e96a66cSDavid du Colombier 	consPrint("\t%sblock %#ux %ud %ud %.*H\n",
7325e96a66cSDavid du Colombier 		argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset);
7335e96a66cSDavid du Colombier 
7345e96a66cSDavid du Colombier 	if(argc == 4){
7355e96a66cSDavid du Colombier 		s = argv[3];
7365e96a66cSDavid du Colombier 		if(strlen(s) != 2*count){
737*d7aba6c3SDavid du Colombier 			werrstr("bad data count");
7385e96a66cSDavid du Colombier 			goto Out;
7395e96a66cSDavid du Colombier 		}
740*d7aba6c3SDavid du Colombier 		buf = vtmallocz(count);
7415e96a66cSDavid du Colombier 		for(i = 0; i < count*2; i++){
7425e96a66cSDavid du Colombier 			if(s[i] >= '0' && s[i] <= '9')
7435e96a66cSDavid du Colombier 				c = s[i] - '0';
7445e96a66cSDavid du Colombier 			else if(s[i] >= 'a' && s[i] <= 'f')
7455e96a66cSDavid du Colombier 				c = s[i] - 'a' + 10;
7465e96a66cSDavid du Colombier 			else if(s[i] >= 'A' && s[i] <= 'F')
7475e96a66cSDavid du Colombier 				c = s[i] - 'A' + 10;
7485e96a66cSDavid du Colombier 			else{
749*d7aba6c3SDavid du Colombier 				werrstr("bad hex");
750*d7aba6c3SDavid du Colombier 				vtfree(buf);
7515e96a66cSDavid du Colombier 				goto Out;
7525e96a66cSDavid du Colombier 			}
7535e96a66cSDavid du Colombier 			if((i & 1) == 0)
7545e96a66cSDavid du Colombier 				c <<= 4;
7555e96a66cSDavid du Colombier 			buf[i>>1] |= c;
7565e96a66cSDavid du Colombier 		}
7575e96a66cSDavid du Colombier 		memmove(b->data+offset, buf, count);
7585e96a66cSDavid du Colombier 		consPrint("\tnew: block %#ux %ud %ud %.*H\n",
7595e96a66cSDavid du Colombier 			addr, offset, count, count, b->data+offset);
7605e96a66cSDavid du Colombier 		blockDirty(b);
7615e96a66cSDavid du Colombier 	}
7625e96a66cSDavid du Colombier 
7635e96a66cSDavid du Colombier Out:
7645e96a66cSDavid du Colombier 	blockPut(b);
765*d7aba6c3SDavid du Colombier 	runlock(&fs->elk);
7665e96a66cSDavid du Colombier 
7675e96a66cSDavid du Colombier 	return 1;
7685e96a66cSDavid du Colombier }
7695e96a66cSDavid du Colombier 
7705e96a66cSDavid du Colombier /*
7715e96a66cSDavid du Colombier  * Free a disk block.
7725e96a66cSDavid du Colombier  */
7735e96a66cSDavid du Colombier static int
fsysBfree(Fsys * fsys,int argc,char * argv[])7745e96a66cSDavid du Colombier fsysBfree(Fsys* fsys, int argc, char* argv[])
7755e96a66cSDavid du Colombier {
7765e96a66cSDavid du Colombier 	Fs *fs;
7775e96a66cSDavid du Colombier 	Label l;
7785e96a66cSDavid du Colombier 	char *p;
7795e96a66cSDavid du Colombier 	Block *b;
7805e96a66cSDavid du Colombier 	u32int addr;
7815e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] bfree addr ...";
7825e96a66cSDavid du Colombier 
7835e96a66cSDavid du Colombier 	ARGBEGIN{
7845e96a66cSDavid du Colombier 	default:
7855e96a66cSDavid du Colombier 		return cliError(usage);
7865e96a66cSDavid du Colombier 	}ARGEND
7875e96a66cSDavid du Colombier 	if(argc == 0)
7885e96a66cSDavid du Colombier 		return cliError(usage);
7895e96a66cSDavid du Colombier 
7905e96a66cSDavid du Colombier 	fs = fsys->fs;
791*d7aba6c3SDavid du Colombier 	rlock(&fs->elk);
7925e96a66cSDavid du Colombier 	while(argc > 0){
7935e96a66cSDavid du Colombier 		addr = strtoul(argv[0], &p, 0);
7945e96a66cSDavid du Colombier 		if(*p != '\0'){
7950c6300e7SDavid du Colombier 			consPrint("bad address - '%ud'\n", addr);
7965e96a66cSDavid du Colombier 			/* syntax error; let's stop */
797*d7aba6c3SDavid du Colombier 			runlock(&fs->elk);
7985e96a66cSDavid du Colombier 			return 0;
7995e96a66cSDavid du Colombier 		}
8005e96a66cSDavid du Colombier 		b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
8015e96a66cSDavid du Colombier 		if(b == nil){
802*d7aba6c3SDavid du Colombier 			consPrint("loading %#ux: %r\n", addr);
8035e96a66cSDavid du Colombier 			continue;
8045e96a66cSDavid du Colombier 		}
8055e96a66cSDavid du Colombier 		l = b->l;
806e569ccb5SDavid du Colombier 		if(l.state == BsFree)
807e569ccb5SDavid du Colombier 			consPrint("%#ux is already free\n", addr);
808e569ccb5SDavid du Colombier 		else{
8095e96a66cSDavid du Colombier 			consPrint("label %#ux %ud %ud %ud %ud %#x\n",
8105e96a66cSDavid du Colombier 				addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
8115e96a66cSDavid du Colombier 			l.state = BsFree;
8125e96a66cSDavid du Colombier 			l.type = BtMax;
8135e96a66cSDavid du Colombier 			l.tag = 0;
8145e96a66cSDavid du Colombier 			l.epoch = 0;
8155e96a66cSDavid du Colombier 			l.epochClose = 0;
816e569ccb5SDavid du Colombier 			if(!blockSetLabel(b, &l, 0))
817*d7aba6c3SDavid du Colombier 				consPrint("freeing %#ux: %r\n", addr);
818e569ccb5SDavid du Colombier 		}
8195e96a66cSDavid du Colombier 		blockPut(b);
8205e96a66cSDavid du Colombier 		argc--;
8215e96a66cSDavid du Colombier 		argv++;
8225e96a66cSDavid du Colombier 	}
823*d7aba6c3SDavid du Colombier 	runlock(&fs->elk);
8245e96a66cSDavid du Colombier 
8255e96a66cSDavid du Colombier 	return 1;
8265e96a66cSDavid du Colombier }
8275e96a66cSDavid du Colombier 
8287abd426fSDavid du Colombier static int
fsysDf(Fsys * fsys,int argc,char * argv[])8297abd426fSDavid du Colombier fsysDf(Fsys *fsys, int argc, char* argv[])
8307abd426fSDavid du Colombier {
8317abd426fSDavid du Colombier 	char *usage = "usage: [fsys name] df";
8327abd426fSDavid du Colombier 	u32int used, tot, bsize;
8337abd426fSDavid du Colombier 	Fs *fs;
8347abd426fSDavid du Colombier 
8357abd426fSDavid du Colombier 	ARGBEGIN{
8367abd426fSDavid du Colombier 	default:
8377abd426fSDavid du Colombier 		return cliError(usage);
8387abd426fSDavid du Colombier 	}ARGEND
8397abd426fSDavid du Colombier 	if(argc != 0)
8407abd426fSDavid du Colombier 		return cliError(usage);
8417abd426fSDavid du Colombier 
8427abd426fSDavid du Colombier 	fs = fsys->fs;
8437abd426fSDavid du Colombier 	cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize);
844e12a9870SDavid du Colombier 	consPrint("\t%s: %,llud used + %,llud free = %,llud (%.1f%% used)\n",
845dc5a79c1SDavid du Colombier 		fsys->name, used*(vlong)bsize, (tot-used)*(vlong)bsize,
846e12a9870SDavid du Colombier 		tot*(vlong)bsize, used*100.0/tot);
8477abd426fSDavid du Colombier 	return 1;
8487abd426fSDavid du Colombier }
8497abd426fSDavid du Colombier 
8505e96a66cSDavid du Colombier /*
8515e96a66cSDavid du Colombier  * Zero an entry or a pointer.
8525e96a66cSDavid du Colombier  */
8535e96a66cSDavid du Colombier static int
fsysClrep(Fsys * fsys,int argc,char * argv[],int ch)8545e96a66cSDavid du Colombier fsysClrep(Fsys* fsys, int argc, char* argv[], int ch)
8555e96a66cSDavid du Colombier {
8565e96a66cSDavid du Colombier 	Fs *fs;
8575e96a66cSDavid du Colombier 	Entry e;
8585e96a66cSDavid du Colombier 	Block *b;
8595e96a66cSDavid du Colombier 	u32int addr;
8605e96a66cSDavid du Colombier 	int i, max, offset, sz;
8615e96a66cSDavid du Colombier 	uchar zero[VtEntrySize];
8625e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clr%c addr offset ...";
8635e96a66cSDavid du Colombier 
8645e96a66cSDavid du Colombier 	ARGBEGIN{
8655e96a66cSDavid du Colombier 	default:
8665e96a66cSDavid du Colombier 		return cliError(usage, ch);
8675e96a66cSDavid du Colombier 	}ARGEND
8685e96a66cSDavid du Colombier 	if(argc < 2)
8695e96a66cSDavid du Colombier 		return cliError(usage, ch);
8705e96a66cSDavid du Colombier 
8715e96a66cSDavid du Colombier 	fs = fsys->fs;
872*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
8735e96a66cSDavid du Colombier 
8745e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
8755e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
8765e96a66cSDavid du Colombier 	if(b == nil){
877*d7aba6c3SDavid du Colombier 		werrstr("cacheLocal %#ux: %r", addr);
8785e96a66cSDavid du Colombier 	Err:
879*d7aba6c3SDavid du Colombier 		runlock(&fsys->fs->elk);
8805e96a66cSDavid du Colombier 		return 0;
8815e96a66cSDavid du Colombier 	}
8825e96a66cSDavid du Colombier 
8835e96a66cSDavid du Colombier 	switch(ch){
8845e96a66cSDavid du Colombier 	default:
885*d7aba6c3SDavid du Colombier 		werrstr("clrep");
8865e96a66cSDavid du Colombier 		goto Err;
8875e96a66cSDavid du Colombier 	case 'e':
8885e96a66cSDavid du Colombier 		if(b->l.type != BtDir){
889*d7aba6c3SDavid du Colombier 			werrstr("wrong block type");
8905e96a66cSDavid du Colombier 			goto Err;
8915e96a66cSDavid du Colombier 		}
8925e96a66cSDavid du Colombier 		sz = VtEntrySize;
8935e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
8945e96a66cSDavid du Colombier 		entryPack(&e, zero, 0);
8955e96a66cSDavid du Colombier 		break;
8965e96a66cSDavid du Colombier 	case 'p':
8975e96a66cSDavid du Colombier 		if(b->l.type == BtDir || b->l.type == BtData){
898*d7aba6c3SDavid du Colombier 			werrstr("wrong block type");
8995e96a66cSDavid du Colombier 			goto Err;
9005e96a66cSDavid du Colombier 		}
9015e96a66cSDavid du Colombier 		sz = VtScoreSize;
902*d7aba6c3SDavid du Colombier 		memmove(zero, vtzeroscore, VtScoreSize);
9035e96a66cSDavid du Colombier 		break;
9045e96a66cSDavid du Colombier 	}
9055e96a66cSDavid du Colombier 	max = fs->blockSize/sz;
9065e96a66cSDavid du Colombier 
9075e96a66cSDavid du Colombier 	for(i = 1; i < argc; i++){
9085e96a66cSDavid du Colombier 		offset = atoi(argv[i]);
9095e96a66cSDavid du Colombier 		if(offset >= max){
9105e96a66cSDavid du Colombier 			consPrint("\toffset %d too large (>= %d)\n", i, max);
9115e96a66cSDavid du Colombier 			continue;
9125e96a66cSDavid du Colombier 		}
9135e96a66cSDavid du Colombier 		consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz);
9145e96a66cSDavid du Colombier 		memmove(b->data+offset*sz, zero, sz);
9155e96a66cSDavid du Colombier 	}
9165e96a66cSDavid du Colombier 	blockDirty(b);
9175e96a66cSDavid du Colombier 	blockPut(b);
918*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
9195e96a66cSDavid du Colombier 
9205e96a66cSDavid du Colombier 	return 1;
9215e96a66cSDavid du Colombier }
9225e96a66cSDavid du Colombier 
9235e96a66cSDavid du Colombier static int
fsysClre(Fsys * fsys,int argc,char * argv[])9245e96a66cSDavid du Colombier fsysClre(Fsys* fsys, int argc, char* argv[])
9255e96a66cSDavid du Colombier {
9265e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'e');
9275e96a66cSDavid du Colombier }
9285e96a66cSDavid du Colombier 
9295e96a66cSDavid du Colombier static int
fsysClrp(Fsys * fsys,int argc,char * argv[])9305e96a66cSDavid du Colombier fsysClrp(Fsys* fsys, int argc, char* argv[])
9315e96a66cSDavid du Colombier {
9325e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'p');
9335e96a66cSDavid du Colombier }
9345e96a66cSDavid du Colombier 
9355e96a66cSDavid du Colombier static int
fsysEsearch1(File * f,char * s,u32int elo)9365e96a66cSDavid du Colombier fsysEsearch1(File* f, char* s, u32int elo)
9375e96a66cSDavid du Colombier {
9385e96a66cSDavid du Colombier 	int n, r;
9395e96a66cSDavid du Colombier 	DirEntry de;
9405e96a66cSDavid du Colombier 	DirEntryEnum *dee;
9415e96a66cSDavid du Colombier 	File *ff;
9425e96a66cSDavid du Colombier 	Entry e, ee;
9435e96a66cSDavid du Colombier 	char *t;
9445e96a66cSDavid du Colombier 
9455e96a66cSDavid du Colombier 	dee = deeOpen(f);
9465e96a66cSDavid du Colombier 	if(dee == nil)
9475e96a66cSDavid du Colombier 		return 0;
9485e96a66cSDavid du Colombier 
9495e96a66cSDavid du Colombier 	n = 0;
9505e96a66cSDavid du Colombier 	for(;;){
9515e96a66cSDavid du Colombier 		r = deeRead(dee, &de);
9525e96a66cSDavid du Colombier 		if(r < 0){
953*d7aba6c3SDavid du Colombier 			consPrint("\tdeeRead %s/%s: %r\n", s, de.elem);
9545e96a66cSDavid du Colombier 			break;
9555e96a66cSDavid du Colombier 		}
9565e96a66cSDavid du Colombier 		if(r == 0)
9575e96a66cSDavid du Colombier 			break;
9585e96a66cSDavid du Colombier 		if(de.mode & ModeSnapshot){
9595e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
960*d7aba6c3SDavid du Colombier 				consPrint("\tcannot walk %s/%s: %r\n", s, de.elem);
9615e96a66cSDavid du Colombier 			else{
962e569ccb5SDavid du Colombier 				if(!fileGetSources(ff, &e, &ee))
963*d7aba6c3SDavid du Colombier 					consPrint("\tcannot get sources for %s/%s: %r\n", s, de.elem);
9645e96a66cSDavid du Colombier 				else if(e.snap != 0 && e.snap < elo){
9655e96a66cSDavid du Colombier 					consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem);
9665e96a66cSDavid du Colombier 					n++;
9675e96a66cSDavid du Colombier 				}
9685e96a66cSDavid du Colombier 				fileDecRef(ff);
9695e96a66cSDavid du Colombier 			}
9705e96a66cSDavid du Colombier 		}
9715e96a66cSDavid du Colombier 		else if(de.mode & ModeDir){
9725e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
973*d7aba6c3SDavid du Colombier 				consPrint("\tcannot walk %s/%s: %r\n", s, de.elem);
9745e96a66cSDavid du Colombier 			else{
975f8e525acSDavid du Colombier 				t = smprint("%s/%s", s, de.elem);
9765e96a66cSDavid du Colombier 				n += fsysEsearch1(ff, t, elo);
977*d7aba6c3SDavid du Colombier 				vtfree(t);
9785e96a66cSDavid du Colombier 				fileDecRef(ff);
9795e96a66cSDavid du Colombier 			}
9805e96a66cSDavid du Colombier 		}
9815e96a66cSDavid du Colombier 		deCleanup(&de);
9825e96a66cSDavid du Colombier 		if(r < 0)
9835e96a66cSDavid du Colombier 			break;
9845e96a66cSDavid du Colombier 	}
9855e96a66cSDavid du Colombier 	deeClose(dee);
9865e96a66cSDavid du Colombier 
9875e96a66cSDavid du Colombier 	return n;
9885e96a66cSDavid du Colombier }
9895e96a66cSDavid du Colombier 
9905e96a66cSDavid du Colombier static int
fsysEsearch(Fs * fs,char * path,u32int elo)9915e96a66cSDavid du Colombier fsysEsearch(Fs* fs, char* path, u32int elo)
9925e96a66cSDavid du Colombier {
9935e96a66cSDavid du Colombier 	int n;
9945e96a66cSDavid du Colombier 	File *f;
9955e96a66cSDavid du Colombier 	DirEntry de;
9965e96a66cSDavid du Colombier 
9975e96a66cSDavid du Colombier 	f = fileOpen(fs, path);
9985e96a66cSDavid du Colombier 	if(f == nil)
9995e96a66cSDavid du Colombier 		return 0;
10005e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
1001*d7aba6c3SDavid du Colombier 		consPrint("\tfileGetDir %s failed: %r\n", path);
10025e96a66cSDavid du Colombier 		fileDecRef(f);
10035e96a66cSDavid du Colombier 		return 0;
10045e96a66cSDavid du Colombier 	}
10055e96a66cSDavid du Colombier 	if((de.mode & ModeDir) == 0){
10065e96a66cSDavid du Colombier 		fileDecRef(f);
10075e96a66cSDavid du Colombier 		deCleanup(&de);
10085e96a66cSDavid du Colombier 		return 0;
10095e96a66cSDavid du Colombier 	}
10105e96a66cSDavid du Colombier 	deCleanup(&de);
10115e96a66cSDavid du Colombier 	n = fsysEsearch1(f, path, elo);
10125e96a66cSDavid du Colombier 	fileDecRef(f);
10135e96a66cSDavid du Colombier 	return n;
10145e96a66cSDavid du Colombier }
10155e96a66cSDavid du Colombier 
10165e96a66cSDavid du Colombier static int
fsysEpoch(Fsys * fsys,int argc,char * argv[])10175e96a66cSDavid du Colombier fsysEpoch(Fsys* fsys, int argc, char* argv[])
10185e96a66cSDavid du Colombier {
10195e96a66cSDavid du Colombier 	Fs *fs;
1020dc5a79c1SDavid du Colombier 	int force, n, remove;
10215e96a66cSDavid du Colombier 	u32int low, old;
1022dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] epoch [[-ry] low]";
10235e96a66cSDavid du Colombier 
10245e96a66cSDavid du Colombier 	force = 0;
1025dc5a79c1SDavid du Colombier 	remove = 0;
10265e96a66cSDavid du Colombier 	ARGBEGIN{
10275e96a66cSDavid du Colombier 	case 'y':
10285e96a66cSDavid du Colombier 		force = 1;
10295e96a66cSDavid du Colombier 		break;
1030dc5a79c1SDavid du Colombier 	case 'r':
1031dc5a79c1SDavid du Colombier 		remove = 1;
1032dc5a79c1SDavid du Colombier 		break;
10335e96a66cSDavid du Colombier 	default:
10345e96a66cSDavid du Colombier 		return cliError(usage);
10355e96a66cSDavid du Colombier 	}ARGEND
10365e96a66cSDavid du Colombier 	if(argc > 1)
10375e96a66cSDavid du Colombier 		return cliError(usage);
10385e96a66cSDavid du Colombier 	if(argc > 0)
10395e96a66cSDavid du Colombier 		low = strtoul(argv[0], 0, 0);
10405e96a66cSDavid du Colombier 	else
10415e96a66cSDavid du Colombier 		low = ~(u32int)0;
10425e96a66cSDavid du Colombier 
10438a2c5ad0SDavid du Colombier 	if(low == 0)
10448a2c5ad0SDavid du Colombier 		return cliError("low epoch cannot be zero");
10458a2c5ad0SDavid du Colombier 
10465e96a66cSDavid du Colombier 	fs = fsys->fs;
10475e96a66cSDavid du Colombier 
1048*d7aba6c3SDavid du Colombier 	rlock(&fs->elk);
10495e96a66cSDavid du Colombier 	consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi);
105057195852SDavid du Colombier 	if(low == ~(u32int)0){
1051*d7aba6c3SDavid du Colombier 		runlock(&fs->elk);
105257195852SDavid du Colombier 		return 1;
105357195852SDavid du Colombier 	}
10545e96a66cSDavid du Colombier 	n = fsysEsearch(fsys->fs, "/archive", low);
10555e96a66cSDavid du Colombier 	n += fsysEsearch(fsys->fs, "/snapshot", low);
10565e96a66cSDavid du Colombier 	consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low);
1057*d7aba6c3SDavid du Colombier 	runlock(&fs->elk);
10585e96a66cSDavid du Colombier 
10595e96a66cSDavid du Colombier 	/*
10605e96a66cSDavid du Colombier 	 * There's a small race here -- a new snapshot with epoch < low might
10615e96a66cSDavid du Colombier 	 * get introduced now that we unlocked fs->elk.  Low has to
10625e96a66cSDavid du Colombier 	 * be <= fs->ehi.  Of course, in order for this to happen low has
10635e96a66cSDavid du Colombier 	 * to be equal to the current fs->ehi _and_ a snapshot has to
10645e96a66cSDavid du Colombier 	 * run right now.  This is a small enough window that I don't care.
10655e96a66cSDavid du Colombier 	 */
10665e96a66cSDavid du Colombier 	if(n != 0 && !force){
10675e96a66cSDavid du Colombier 		consPrint("\tnot setting low epoch\n");
10685e96a66cSDavid du Colombier 		return 1;
10695e96a66cSDavid du Colombier 	}
10705e96a66cSDavid du Colombier 	old = fs->elo;
10715e96a66cSDavid du Colombier 	if(!fsEpochLow(fs, low))
1072*d7aba6c3SDavid du Colombier 		consPrint("\tfsEpochLow: %r\n");
10735e96a66cSDavid du Colombier 	else{
10745e96a66cSDavid du Colombier 		consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old);
10755e96a66cSDavid du Colombier 		consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo);
10765e96a66cSDavid du Colombier 		if(fs->elo < low)
10775e96a66cSDavid du Colombier 			consPrint("\twarning: new low epoch < old low epoch\n");
1078dc5a79c1SDavid du Colombier 		if(force && remove)
1079dc5a79c1SDavid du Colombier 			fsSnapshotRemove(fs);
10805e96a66cSDavid du Colombier 	}
10815e96a66cSDavid du Colombier 
10825e96a66cSDavid du Colombier 	return 1;
10835e96a66cSDavid du Colombier }
10845e96a66cSDavid du Colombier 
10855e96a66cSDavid du Colombier static int
fsysCreate(Fsys * fsys,int argc,char * argv[])10865e96a66cSDavid du Colombier fsysCreate(Fsys* fsys, int argc, char* argv[])
10875e96a66cSDavid du Colombier {
10885e96a66cSDavid du Colombier 	int r;
10895e96a66cSDavid du Colombier 	ulong mode;
10905e96a66cSDavid du Colombier 	char *elem, *p, *path;
10915e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] create path uid gid perm";
10925e96a66cSDavid du Colombier 	DirEntry de;
10935e96a66cSDavid du Colombier 	File *file, *parent;
10945e96a66cSDavid du Colombier 
10955e96a66cSDavid du Colombier 	ARGBEGIN{
10965e96a66cSDavid du Colombier 	default:
10975e96a66cSDavid du Colombier 		return cliError(usage);
10985e96a66cSDavid du Colombier 	}ARGEND
10995e96a66cSDavid du Colombier 	if(argc != 4)
11005e96a66cSDavid du Colombier 		return cliError(usage);
11015e96a66cSDavid du Colombier 
11025e96a66cSDavid du Colombier 	if(!fsysParseMode(argv[3], &mode))
11035e96a66cSDavid du Colombier 		return cliError(usage);
11045e96a66cSDavid du Colombier 	if(mode&ModeSnapshot)
11055e96a66cSDavid du Colombier 		return cliError("create - cannot create with snapshot bit set");
11065e96a66cSDavid du Colombier 
11075e96a66cSDavid du Colombier 	if(strcmp(argv[1], uidnoworld) == 0)
11085e96a66cSDavid du Colombier 		return cliError("permission denied");
11095e96a66cSDavid du Colombier 
1110*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
1111*d7aba6c3SDavid du Colombier 	path = vtstrdup(argv[0]);
11125e96a66cSDavid du Colombier 	if((p = strrchr(path, '/')) != nil){
11135e96a66cSDavid du Colombier 		*p++ = '\0';
11145e96a66cSDavid du Colombier 		elem = p;
11155e96a66cSDavid du Colombier 		p = path;
11165e96a66cSDavid du Colombier 		if(*p == '\0')
11175e96a66cSDavid du Colombier 			p = "/";
11185e96a66cSDavid du Colombier 	}
11195e96a66cSDavid du Colombier 	else{
11205e96a66cSDavid du Colombier 		p = "/";
11215e96a66cSDavid du Colombier 		elem = path;
11225e96a66cSDavid du Colombier 	}
1123f8e525acSDavid du Colombier 
11245e96a66cSDavid du Colombier 	r = 0;
1125f8e525acSDavid du Colombier 	if((parent = fileOpen(fsys->fs, p)) == nil)
1126f8e525acSDavid du Colombier 		goto out;
1127f8e525acSDavid du Colombier 
11285e96a66cSDavid du Colombier 	file = fileCreate(parent, elem, mode, argv[1]);
11295e96a66cSDavid du Colombier 	fileDecRef(parent);
1130f8e525acSDavid du Colombier 	if(file == nil){
1131*d7aba6c3SDavid du Colombier 		werrstr("create %s/%s: %r", p, elem);
1132f8e525acSDavid du Colombier 		goto out;
1133f8e525acSDavid du Colombier 	}
1134f8e525acSDavid du Colombier 
1135f8e525acSDavid du Colombier 	if(!fileGetDir(file, &de)){
1136*d7aba6c3SDavid du Colombier 		werrstr("stat failed after create: %r");
1137f8e525acSDavid du Colombier 		goto out1;
1138f8e525acSDavid du Colombier 	}
1139f8e525acSDavid du Colombier 
11405e96a66cSDavid du Colombier 	if(strcmp(de.gid, argv[2]) != 0){
1141*d7aba6c3SDavid du Colombier 		vtfree(de.gid);
1142*d7aba6c3SDavid du Colombier 		de.gid = vtstrdup(argv[2]);
1143f8e525acSDavid du Colombier 		if(!fileSetDir(file, &de, argv[1])){
1144*d7aba6c3SDavid du Colombier 			werrstr("wstat failed after create: %r");
1145f8e525acSDavid du Colombier 			goto out2;
11465e96a66cSDavid du Colombier 		}
1147f8e525acSDavid du Colombier 	}
1148f8e525acSDavid du Colombier 	r = 1;
1149f8e525acSDavid du Colombier 
1150f8e525acSDavid du Colombier out2:
11515e96a66cSDavid du Colombier 	deCleanup(&de);
1152f8e525acSDavid du Colombier out1:
11535e96a66cSDavid du Colombier 	fileDecRef(file);
1154f8e525acSDavid du Colombier out:
1155*d7aba6c3SDavid du Colombier 	vtfree(path);
1156*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
11575e96a66cSDavid du Colombier 
11585e96a66cSDavid du Colombier 	return r;
11595e96a66cSDavid du Colombier }
11605e96a66cSDavid du Colombier 
11615e96a66cSDavid du Colombier static void
fsysPrintStat(char * prefix,char * file,DirEntry * de)11625e96a66cSDavid du Colombier fsysPrintStat(char *prefix, char *file, DirEntry *de)
11635e96a66cSDavid du Colombier {
11645e96a66cSDavid du Colombier 	char buf[64];
11655e96a66cSDavid du Colombier 
11665e96a66cSDavid du Colombier 	if(prefix == nil)
11675e96a66cSDavid du Colombier 		prefix = "";
11685e96a66cSDavid du Colombier 	consPrint("%sstat %q %q %q %q %s %llud\n", prefix,
11695e96a66cSDavid du Colombier 		file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size);
11705e96a66cSDavid du Colombier }
11715e96a66cSDavid du Colombier 
11725e96a66cSDavid du Colombier static int
fsysStat(Fsys * fsys,int argc,char * argv[])11735e96a66cSDavid du Colombier fsysStat(Fsys* fsys, int argc, char* argv[])
11745e96a66cSDavid du Colombier {
11755e96a66cSDavid du Colombier 	int i;
11765e96a66cSDavid du Colombier 	File *f;
11775e96a66cSDavid du Colombier 	DirEntry de;
11785e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] stat files...";
11795e96a66cSDavid du Colombier 
11805e96a66cSDavid du Colombier 	ARGBEGIN{
11815e96a66cSDavid du Colombier 	default:
11825e96a66cSDavid du Colombier 		return cliError(usage);
11835e96a66cSDavid du Colombier 	}ARGEND
11845e96a66cSDavid du Colombier 
11855e96a66cSDavid du Colombier 	if(argc == 0)
11865e96a66cSDavid du Colombier 		return cliError(usage);
11875e96a66cSDavid du Colombier 
1188*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
11895e96a66cSDavid du Colombier 	for(i=0; i<argc; i++){
11905e96a66cSDavid du Colombier 		if((f = fileOpen(fsys->fs, argv[i])) == nil){
1191*d7aba6c3SDavid du Colombier 			consPrint("%s: %r\n", argv[i]);
11925e96a66cSDavid du Colombier 			continue;
11935e96a66cSDavid du Colombier 		}
11945e96a66cSDavid du Colombier 		if(!fileGetDir(f, &de)){
1195*d7aba6c3SDavid du Colombier 			consPrint("%s: %r\n", argv[i]);
11965e96a66cSDavid du Colombier 			fileDecRef(f);
11975e96a66cSDavid du Colombier 			continue;
11985e96a66cSDavid du Colombier 		}
11995e96a66cSDavid du Colombier 		fsysPrintStat("\t", argv[i], &de);
12005e96a66cSDavid du Colombier 		deCleanup(&de);
12015e96a66cSDavid du Colombier 		fileDecRef(f);
12025e96a66cSDavid du Colombier 	}
1203*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
12045e96a66cSDavid du Colombier 	return 1;
12055e96a66cSDavid du Colombier }
12065e96a66cSDavid du Colombier 
12075e96a66cSDavid du Colombier static int
fsysWstat(Fsys * fsys,int argc,char * argv[])12085e96a66cSDavid du Colombier fsysWstat(Fsys *fsys, int argc, char* argv[])
12095e96a66cSDavid du Colombier {
12105e96a66cSDavid du Colombier 	File *f;
12115e96a66cSDavid du Colombier 	char *p;
12125e96a66cSDavid du Colombier 	DirEntry de;
12135e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n"
12145e96a66cSDavid du Colombier 		"\tuse - for any field to mean don't change";
12155e96a66cSDavid du Colombier 
12165e96a66cSDavid du Colombier 	ARGBEGIN{
12175e96a66cSDavid du Colombier 	default:
12185e96a66cSDavid du Colombier 		return cliError(usage);
12195e96a66cSDavid du Colombier 	}ARGEND
12205e96a66cSDavid du Colombier 
12215e96a66cSDavid du Colombier 	if(argc != 6)
12225e96a66cSDavid du Colombier 		return cliError(usage);
12235e96a66cSDavid du Colombier 
1224*d7aba6c3SDavid du Colombier 	rlock(&fsys->fs->elk);
12255e96a66cSDavid du Colombier 	if((f = fileOpen(fsys->fs, argv[0])) == nil){
1226*d7aba6c3SDavid du Colombier 		werrstr("console wstat - walk - %r");
1227*d7aba6c3SDavid du Colombier 		runlock(&fsys->fs->elk);
12285e96a66cSDavid du Colombier 		return 0;
12295e96a66cSDavid du Colombier 	}
12305e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
1231*d7aba6c3SDavid du Colombier 		werrstr("console wstat - stat - %r");
12325e96a66cSDavid du Colombier 		fileDecRef(f);
1233*d7aba6c3SDavid du Colombier 		runlock(&fsys->fs->elk);
12345e96a66cSDavid du Colombier 		return 0;
12355e96a66cSDavid du Colombier 	}
12365e96a66cSDavid du Colombier 	fsysPrintStat("\told: w", argv[0], &de);
12375e96a66cSDavid du Colombier 
12385e96a66cSDavid du Colombier 	if(strcmp(argv[1], "-") != 0){
12395e96a66cSDavid du Colombier 		if(!validFileName(argv[1])){
1240*d7aba6c3SDavid du Colombier 			werrstr("console wstat - bad elem");
12415e96a66cSDavid du Colombier 			goto error;
12425e96a66cSDavid du Colombier 		}
1243*d7aba6c3SDavid du Colombier 		vtfree(de.elem);
1244*d7aba6c3SDavid du Colombier 		de.elem = vtstrdup(argv[1]);
12455e96a66cSDavid du Colombier 	}
12465e96a66cSDavid du Colombier 	if(strcmp(argv[2], "-") != 0){
12475e96a66cSDavid du Colombier 		if(!validUserName(argv[2])){
1248*d7aba6c3SDavid du Colombier 			werrstr("console wstat - bad uid");
12495e96a66cSDavid du Colombier 			goto error;
12505e96a66cSDavid du Colombier 		}
1251*d7aba6c3SDavid du Colombier 		vtfree(de.uid);
1252*d7aba6c3SDavid du Colombier 		de.uid = vtstrdup(argv[2]);
12535e96a66cSDavid du Colombier 	}
12545e96a66cSDavid du Colombier 	if(strcmp(argv[3], "-") != 0){
12555e96a66cSDavid du Colombier 		if(!validUserName(argv[3])){
1256*d7aba6c3SDavid du Colombier 			werrstr("console wstat - bad gid");
12575e96a66cSDavid du Colombier 			goto error;
12585e96a66cSDavid du Colombier 		}
1259*d7aba6c3SDavid du Colombier 		vtfree(de.gid);
1260*d7aba6c3SDavid du Colombier 		de.gid = vtstrdup(argv[3]);
12615e96a66cSDavid du Colombier 	}
12625e96a66cSDavid du Colombier 	if(strcmp(argv[4], "-") != 0){
12635e96a66cSDavid du Colombier 		if(!fsysParseMode(argv[4], &de.mode)){
1264*d7aba6c3SDavid du Colombier 			werrstr("console wstat - bad mode");
12655e96a66cSDavid du Colombier 			goto error;
12665e96a66cSDavid du Colombier 		}
12675e96a66cSDavid du Colombier 	}
12685e96a66cSDavid du Colombier 	if(strcmp(argv[5], "-") != 0){
12695e96a66cSDavid du Colombier 		de.size = strtoull(argv[5], &p, 0);
127022a127bbSDavid du Colombier 		if(argv[5][0] == '\0' || *p != '\0' || (vlong)de.size < 0){
1271*d7aba6c3SDavid du Colombier 			werrstr("console wstat - bad length");
12725e96a66cSDavid du Colombier 			goto error;
12735e96a66cSDavid du Colombier 		}
12745e96a66cSDavid du Colombier 	}
12755e96a66cSDavid du Colombier 
12765e96a66cSDavid du Colombier 	if(!fileSetDir(f, &de, uidadm)){
1277*d7aba6c3SDavid du Colombier 		werrstr("console wstat - %r");
12785e96a66cSDavid du Colombier 		goto error;
12795e96a66cSDavid du Colombier 	}
12805e96a66cSDavid du Colombier 	deCleanup(&de);
12815e96a66cSDavid du Colombier 
12825e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
1283*d7aba6c3SDavid du Colombier 		werrstr("console wstat - stat2 - %r");
12845e96a66cSDavid du Colombier 		goto error;
12855e96a66cSDavid du Colombier 	}
12865e96a66cSDavid du Colombier 	fsysPrintStat("\tnew: w", argv[0], &de);
12875e96a66cSDavid du Colombier 	deCleanup(&de);
12885e96a66cSDavid du Colombier 	fileDecRef(f);
1289*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
12905e96a66cSDavid du Colombier 
12915e96a66cSDavid du Colombier 	return 1;
12925e96a66cSDavid du Colombier 
12935e96a66cSDavid du Colombier error:
12945e96a66cSDavid du Colombier 	deCleanup(&de);	/* okay to do this twice */
12955e96a66cSDavid du Colombier 	fileDecRef(f);
1296*d7aba6c3SDavid du Colombier 	runlock(&fsys->fs->elk);
12975e96a66cSDavid du Colombier 	return 0;
12985e96a66cSDavid du Colombier }
12995e96a66cSDavid du Colombier 
1300e569ccb5SDavid du Colombier static void
fsckClri(Fsck * fsck,char * name,MetaBlock * mb,int i,Block * b)1301e569ccb5SDavid du Colombier fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b)
1302e569ccb5SDavid du Colombier {
1303e569ccb5SDavid du Colombier 	USED(name);
1304e569ccb5SDavid du Colombier 
1305e569ccb5SDavid du Colombier 	if((fsck->flags&DoClri) == 0)
1306e569ccb5SDavid du Colombier 		return;
1307e569ccb5SDavid du Colombier 
1308e569ccb5SDavid du Colombier 	mbDelete(mb, i);
1309e569ccb5SDavid du Colombier 	mbPack(mb);
1310e569ccb5SDavid du Colombier 	blockDirty(b);
1311e569ccb5SDavid du Colombier }
1312e569ccb5SDavid du Colombier 
1313e569ccb5SDavid du Colombier static void
fsckClose(Fsck * fsck,Block * b,u32int epoch)1314e569ccb5SDavid du Colombier fsckClose(Fsck *fsck, Block *b, u32int epoch)
1315e569ccb5SDavid du Colombier {
1316e569ccb5SDavid du Colombier 	Label l;
1317e569ccb5SDavid du Colombier 
1318e569ccb5SDavid du Colombier 	if((fsck->flags&DoClose) == 0)
1319e569ccb5SDavid du Colombier 		return;
1320e569ccb5SDavid du Colombier 	l = b->l;
1321e569ccb5SDavid du Colombier 	if(l.state == BsFree || (l.state&BsClosed)){
1322e569ccb5SDavid du Colombier 		consPrint("%#ux is already closed\n", b->addr);
1323e569ccb5SDavid du Colombier 		return;
1324e569ccb5SDavid du Colombier 	}
1325e569ccb5SDavid du Colombier 	if(epoch){
1326e569ccb5SDavid du Colombier 		l.state |= BsClosed;
1327e569ccb5SDavid du Colombier 		l.epochClose = epoch;
1328e569ccb5SDavid du Colombier 	}else
1329e569ccb5SDavid du Colombier 		l.state = BsFree;
1330e569ccb5SDavid du Colombier 
1331e569ccb5SDavid du Colombier 	if(!blockSetLabel(b, &l, 0))
1332*d7aba6c3SDavid du Colombier 		consPrint("%#ux setlabel: %r\n", b->addr);
1333e569ccb5SDavid du Colombier }
1334e569ccb5SDavid du Colombier 
1335e569ccb5SDavid du Colombier static void
fsckClre(Fsck * fsck,Block * b,int offset)1336e569ccb5SDavid du Colombier fsckClre(Fsck *fsck, Block *b, int offset)
1337e569ccb5SDavid du Colombier {
1338e569ccb5SDavid du Colombier 	Entry e;
1339e569ccb5SDavid du Colombier 
1340e569ccb5SDavid du Colombier 	if((fsck->flags&DoClre) == 0)
1341e569ccb5SDavid du Colombier 		return;
1342e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtEntrySize >= fsck->bsize){
1343e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1344e569ccb5SDavid du Colombier 		return;
1345e569ccb5SDavid du Colombier 	}
1346e569ccb5SDavid du Colombier 	memset(&e, 0, sizeof e);
1347e569ccb5SDavid du Colombier 	entryPack(&e, b->data, offset);
1348e569ccb5SDavid du Colombier 	blockDirty(b);
1349e569ccb5SDavid du Colombier }
1350e569ccb5SDavid du Colombier 
1351e569ccb5SDavid du Colombier static void
fsckClrp(Fsck * fsck,Block * b,int offset)1352e569ccb5SDavid du Colombier fsckClrp(Fsck *fsck, Block *b, int offset)
1353e569ccb5SDavid du Colombier {
1354e569ccb5SDavid du Colombier 	if((fsck->flags&DoClrp) == 0)
1355e569ccb5SDavid du Colombier 		return;
1356e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtScoreSize >= fsck->bsize){
1357e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1358e569ccb5SDavid du Colombier 		return;
1359e569ccb5SDavid du Colombier 	}
1360*d7aba6c3SDavid du Colombier 	memmove(b->data+offset*VtScoreSize, vtzeroscore, VtScoreSize);
1361e569ccb5SDavid du Colombier 	blockDirty(b);
1362e569ccb5SDavid du Colombier }
1363e569ccb5SDavid du Colombier 
1364e569ccb5SDavid du Colombier static int
fsysCheck(Fsys * fsys,int argc,char * argv[])1365e569ccb5SDavid du Colombier fsysCheck(Fsys *fsys, int argc, char *argv[])
1366e569ccb5SDavid du Colombier {
1367e569ccb5SDavid du Colombier 	int i, halting;
1368e569ccb5SDavid du Colombier 	char *usage = "usage: [fsys name] check [-v] [options]";
1369e569ccb5SDavid du Colombier 	Fsck fsck;
1370e569ccb5SDavid du Colombier 	Block *b;
1371e569ccb5SDavid du Colombier 	Super super;
1372e569ccb5SDavid du Colombier 
1373e569ccb5SDavid du Colombier 	memset(&fsck, 0, sizeof fsck);
1374e569ccb5SDavid du Colombier 	fsck.fs = fsys->fs;
1375e569ccb5SDavid du Colombier 	fsck.clri = fsckClri;
1376e569ccb5SDavid du Colombier 	fsck.clre = fsckClre;
1377e569ccb5SDavid du Colombier 	fsck.clrp = fsckClrp;
1378e569ccb5SDavid du Colombier 	fsck.close = fsckClose;
1379e569ccb5SDavid du Colombier 	fsck.print = consPrint;
1380e569ccb5SDavid du Colombier 
1381e569ccb5SDavid du Colombier 	ARGBEGIN{
1382e569ccb5SDavid du Colombier 	default:
1383e569ccb5SDavid du Colombier 		return cliError(usage);
1384e569ccb5SDavid du Colombier 	}ARGEND
1385e569ccb5SDavid du Colombier 
1386e569ccb5SDavid du Colombier 	for(i=0; i<argc; i++){
1387e569ccb5SDavid du Colombier 		if(strcmp(argv[i], "pblock") == 0)
1388e569ccb5SDavid du Colombier 			fsck.printblocks = 1;
1389e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pdir") == 0)
1390e569ccb5SDavid du Colombier 			fsck.printdirs = 1;
1391e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pfile") == 0)
1392e569ccb5SDavid du Colombier 			fsck.printfiles = 1;
1393e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "bclose") == 0)
1394e569ccb5SDavid du Colombier 			fsck.flags |= DoClose;
1395e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clri") == 0)
1396e569ccb5SDavid du Colombier 			fsck.flags |= DoClri;
1397e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clre") == 0)
1398e569ccb5SDavid du Colombier 			fsck.flags |= DoClre;
1399e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clrp") == 0)
1400e569ccb5SDavid du Colombier 			fsck.flags |= DoClrp;
1401e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "fix") == 0)
1402e569ccb5SDavid du Colombier 			fsck.flags |= DoClose|DoClri|DoClre|DoClrp;
1403e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "venti") == 0)
1404e569ccb5SDavid du Colombier 			fsck.useventi = 1;
1405e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "snapshot") == 0)
1406e569ccb5SDavid du Colombier 			fsck.walksnapshots = 1;
1407e569ccb5SDavid du Colombier 		else{
1408e569ccb5SDavid du Colombier 			consPrint("unknown option '%s'\n", argv[i]);
1409e569ccb5SDavid du Colombier 			return cliError(usage);
1410e569ccb5SDavid du Colombier 		}
1411e569ccb5SDavid du Colombier 	}
1412e569ccb5SDavid du Colombier 
1413e569ccb5SDavid du Colombier 	halting = fsys->fs->halted==0;
1414e569ccb5SDavid du Colombier 	if(halting)
1415e569ccb5SDavid du Colombier 		fsHalt(fsys->fs);
1416e569ccb5SDavid du Colombier 	if(fsys->fs->arch){
1417e569ccb5SDavid du Colombier 		b = superGet(fsys->fs->cache, &super);
1418e569ccb5SDavid du Colombier 		if(b == nil){
1419e569ccb5SDavid du Colombier 			consPrint("could not load super block\n");
1420e569ccb5SDavid du Colombier 			goto Out;
1421e569ccb5SDavid du Colombier 		}
1422e569ccb5SDavid du Colombier 		blockPut(b);
1423e569ccb5SDavid du Colombier 		if(super.current != NilBlock){
1424225077b0SDavid du Colombier 			consPrint("cannot check fs while archiver is running; "
1425225077b0SDavid du Colombier 				"wait for it to finish\n");
1426e569ccb5SDavid du Colombier 			goto Out;
1427e569ccb5SDavid du Colombier 		}
1428e569ccb5SDavid du Colombier 	}
1429e569ccb5SDavid du Colombier 	fsCheck(&fsck);
1430e569ccb5SDavid du Colombier 	consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n",
1431e569ccb5SDavid du Colombier 		fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose);
1432e569ccb5SDavid du Colombier Out:
1433e569ccb5SDavid du Colombier 	if(halting)
1434e569ccb5SDavid du Colombier 		fsUnhalt(fsys->fs);
1435e569ccb5SDavid du Colombier 	return 1;
1436e569ccb5SDavid du Colombier }
1437e569ccb5SDavid du Colombier 
14385e96a66cSDavid du Colombier static int
fsysVenti(char * name,int argc,char * argv[])14395e96a66cSDavid du Colombier fsysVenti(char* name, int argc, char* argv[])
14405e96a66cSDavid du Colombier {
14415e96a66cSDavid du Colombier 	int r;
14425e96a66cSDavid du Colombier 	char *host;
14435e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] venti [address]";
14445e96a66cSDavid du Colombier 	Fsys *fsys;
14455e96a66cSDavid du Colombier 
14465e96a66cSDavid du Colombier 	ARGBEGIN{
14475e96a66cSDavid du Colombier 	default:
14485e96a66cSDavid du Colombier 		return cliError(usage);
14495e96a66cSDavid du Colombier 	}ARGEND
14505e96a66cSDavid du Colombier 
14515e96a66cSDavid du Colombier 	if(argc == 0)
14525e96a66cSDavid du Colombier 		host = nil;
14535e96a66cSDavid du Colombier 	else if(argc == 1)
14545e96a66cSDavid du Colombier 		host = argv[0];
14555e96a66cSDavid du Colombier 	else
14565e96a66cSDavid du Colombier 		return cliError(usage);
14575e96a66cSDavid du Colombier 
14585e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
14595e96a66cSDavid du Colombier 		return 0;
14605e96a66cSDavid du Colombier 
1461*d7aba6c3SDavid du Colombier 	qlock(&fsys->lock);
14625e96a66cSDavid du Colombier 	if(host == nil)
14635e96a66cSDavid du Colombier 		host = fsys->venti;
14645e96a66cSDavid du Colombier 	else{
1465*d7aba6c3SDavid du Colombier 		vtfree(fsys->venti);
14665e96a66cSDavid du Colombier 		if(host[0])
1467*d7aba6c3SDavid du Colombier 			fsys->venti = vtstrdup(host);
14685e96a66cSDavid du Colombier 		else{
14695e96a66cSDavid du Colombier 			host = nil;
14705e96a66cSDavid du Colombier 			fsys->venti = nil;
14715e96a66cSDavid du Colombier 		}
14725e96a66cSDavid du Colombier 	}
14735e96a66cSDavid du Colombier 
14745e96a66cSDavid du Colombier 	/* already open: do a redial */
14755e96a66cSDavid du Colombier 	if(fsys->fs != nil){
14766042bf6dSDavid du Colombier 		if(fsys->session == nil){
1477*d7aba6c3SDavid du Colombier 			werrstr("file system was opened with -V");
14786042bf6dSDavid du Colombier 			r = 0;
14796042bf6dSDavid du Colombier 			goto out;
14806042bf6dSDavid du Colombier 		}
14815e96a66cSDavid du Colombier 		r = 1;
1482*d7aba6c3SDavid du Colombier 		if(myRedial(fsys->session, host) < 0
1483*d7aba6c3SDavid du Colombier 		|| vtconnect(fsys->session) < 0)
14845e96a66cSDavid du Colombier 			r = 0;
14856042bf6dSDavid du Colombier 		goto out;
14865e96a66cSDavid du Colombier 	}
14875e96a66cSDavid du Colombier 
14885e96a66cSDavid du Colombier 	/* not yet open: try to dial */
14895e96a66cSDavid du Colombier 	if(fsys->session)
1490*d7aba6c3SDavid du Colombier 		vtfreeconn(fsys->session);
14915e96a66cSDavid du Colombier 	r = 1;
1492*d7aba6c3SDavid du Colombier 	if((fsys->session = myDial(host)) == nil
1493*d7aba6c3SDavid du Colombier 	|| vtconnect(fsys->session) < 0)
14945e96a66cSDavid du Colombier 		r = 0;
14956042bf6dSDavid du Colombier out:
1496*d7aba6c3SDavid du Colombier 	qunlock(&fsys->lock);
14975e96a66cSDavid du Colombier 	fsysPut(fsys);
14985e96a66cSDavid du Colombier 	return r;
14995e96a66cSDavid du Colombier }
15005e96a66cSDavid du Colombier 
1501b8a11165SDavid du Colombier static ulong
freemem(void)1502b8a11165SDavid du Colombier freemem(void)
1503b8a11165SDavid du Colombier {
1504b8a11165SDavid du Colombier 	int nf, pgsize = 0;
1505b8a11165SDavid du Colombier 	uvlong size, userpgs = 0, userused = 0;
1506b8a11165SDavid du Colombier 	char *ln, *sl;
1507b8a11165SDavid du Colombier 	char *fields[2];
1508b8a11165SDavid du Colombier 	Biobuf *bp;
1509b8a11165SDavid du Colombier 
1510b8a11165SDavid du Colombier 	size = 64*1024*1024;
1511b8a11165SDavid du Colombier 	bp = Bopen("#c/swap", OREAD);
1512b8a11165SDavid du Colombier 	if (bp != nil) {
1513b8a11165SDavid du Colombier 		while ((ln = Brdline(bp, '\n')) != nil) {
1514b8a11165SDavid du Colombier 			ln[Blinelen(bp)-1] = '\0';
1515b8a11165SDavid du Colombier 			nf = tokenize(ln, fields, nelem(fields));
1516b8a11165SDavid du Colombier 			if (nf != 2)
1517b8a11165SDavid du Colombier 				continue;
1518b8a11165SDavid du Colombier 			if (strcmp(fields[1], "pagesize") == 0)
1519b8a11165SDavid du Colombier 				pgsize = atoi(fields[0]);
1520b8a11165SDavid du Colombier 			else if (strcmp(fields[1], "user") == 0) {
1521b8a11165SDavid du Colombier 				sl = strchr(fields[0], '/');
1522b8a11165SDavid du Colombier 				if (sl == nil)
1523b8a11165SDavid du Colombier 					continue;
1524b8a11165SDavid du Colombier 				userpgs = atoll(sl+1);
1525b8a11165SDavid du Colombier 				userused = atoll(fields[0]);
1526b8a11165SDavid du Colombier 			}
1527b8a11165SDavid du Colombier 		}
1528b8a11165SDavid du Colombier 		Bterm(bp);
1529b8a11165SDavid du Colombier 		if (pgsize > 0 && userpgs > 0)
1530b8a11165SDavid du Colombier 			size = (userpgs - userused) * pgsize;
1531b8a11165SDavid du Colombier 	}
1532b8a11165SDavid du Colombier 	/* cap it to keep the size within 32 bits */
1533b8a11165SDavid du Colombier 	if (size >= 3840UL * 1024 * 1024)
1534b8a11165SDavid du Colombier 		size = 3840UL * 1024 * 1024;
1535b8a11165SDavid du Colombier 	return size;
1536b8a11165SDavid du Colombier }
1537b8a11165SDavid du Colombier 
15385e96a66cSDavid du Colombier static int
fsysOpen(char * name,int argc,char * argv[])15395e96a66cSDavid du Colombier fsysOpen(char* name, int argc, char* argv[])
15405e96a66cSDavid du Colombier {
15415e96a66cSDavid du Colombier 	char *p, *host;
15425e96a66cSDavid du Colombier 	Fsys *fsys;
1543f4051287SDavid du Colombier 	int noauth, noventi, noperm, rflag, wstatallow, noatimeupd;
1544b8a11165SDavid du Colombier 	long ncache;
15456042bf6dSDavid du Colombier 	char *usage = "usage: fsys name open [-APVWr] [-c ncache]";
15465e96a66cSDavid du Colombier 
15475e96a66cSDavid du Colombier 	ncache = 1000;
1548f4051287SDavid du Colombier 	noauth = noperm = wstatallow = noventi = noatimeupd = 0;
15495e96a66cSDavid du Colombier 	rflag = OReadWrite;
15505e96a66cSDavid du Colombier 
15515e96a66cSDavid du Colombier 	ARGBEGIN{
15525e96a66cSDavid du Colombier 	default:
15535e96a66cSDavid du Colombier 		return cliError(usage);
15545e96a66cSDavid du Colombier 	case 'A':
15555e96a66cSDavid du Colombier 		noauth = 1;
15565e96a66cSDavid du Colombier 		break;
15575e96a66cSDavid du Colombier 	case 'P':
15585e96a66cSDavid du Colombier 		noperm = 1;
15595e96a66cSDavid du Colombier 		break;
15606042bf6dSDavid du Colombier 	case 'V':
15616042bf6dSDavid du Colombier 		noventi = 1;
15626042bf6dSDavid du Colombier 		break;
15635e96a66cSDavid du Colombier 	case 'W':
15645e96a66cSDavid du Colombier 		wstatallow = 1;
15655e96a66cSDavid du Colombier 		break;
1566f4051287SDavid du Colombier 	case 'a':
1567f4051287SDavid du Colombier 		noatimeupd = 1;
1568f4051287SDavid du Colombier 		break;
15695e96a66cSDavid du Colombier 	case 'c':
15705e96a66cSDavid du Colombier 		p = ARGF();
15715e96a66cSDavid du Colombier 		if(p == nil)
15725e96a66cSDavid du Colombier 			return cliError(usage);
15735e96a66cSDavid du Colombier 		ncache = strtol(argv[0], &p, 0);
15745e96a66cSDavid du Colombier 		if(ncache <= 0 || p == argv[0] || *p != '\0')
15755e96a66cSDavid du Colombier 			return cliError(usage);
15765e96a66cSDavid du Colombier 		break;
15775e96a66cSDavid du Colombier 	case 'r':
15785e96a66cSDavid du Colombier 		rflag = OReadOnly;
15795e96a66cSDavid du Colombier 		break;
15805e96a66cSDavid du Colombier 	}ARGEND
15815e96a66cSDavid du Colombier 	if(argc)
15825e96a66cSDavid du Colombier 		return cliError(usage);
15835e96a66cSDavid du Colombier 
15845e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
15855e96a66cSDavid du Colombier 		return 0;
15865e96a66cSDavid du Colombier 
1587b8a11165SDavid du Colombier 	/* automatic memory sizing? */
1588b8a11165SDavid du Colombier 	if(mempcnt > 0) {
1589b8a11165SDavid du Colombier 		/* TODO: 8K is a hack; use the actual block size */
1590b8a11165SDavid du Colombier 		ncache = (((vlong)freemem() * mempcnt) / 100) / (8*1024);
1591b8a11165SDavid du Colombier 		if (ncache < 100)
1592b8a11165SDavid du Colombier 			ncache = 100;
1593b8a11165SDavid du Colombier 	}
1594b8a11165SDavid du Colombier 
1595*d7aba6c3SDavid du Colombier 	qlock(&fsys->lock);
15965e96a66cSDavid du Colombier 	if(fsys->fs != nil){
1597*d7aba6c3SDavid du Colombier 		werrstr(EFsysBusy, fsys->name);
1598*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
15995e96a66cSDavid du Colombier 		fsysPut(fsys);
16005e96a66cSDavid du Colombier 		return 0;
16015e96a66cSDavid du Colombier 	}
16025e96a66cSDavid du Colombier 
16037611b47fSDavid du Colombier 	if(noventi){
16047611b47fSDavid du Colombier 		if(fsys->session){
1605*d7aba6c3SDavid du Colombier 			vtfreeconn(fsys->session);
16067611b47fSDavid du Colombier 			fsys->session = nil;
16077611b47fSDavid du Colombier 		}
16087611b47fSDavid du Colombier 	}
16097611b47fSDavid du Colombier 	else if(fsys->session == nil){
16105e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
16115e96a66cSDavid du Colombier 			host = fsys->venti;
16125e96a66cSDavid du Colombier 		else
16135e96a66cSDavid du Colombier 			host = nil;
1614*d7aba6c3SDavid du Colombier 
1615*d7aba6c3SDavid du Colombier 		if((fsys->session = myDial(host)) == nil
1616*d7aba6c3SDavid du Colombier 		|| vtconnect(fsys->session) < 0 && !noventi)
1617*d7aba6c3SDavid du Colombier 			fprint(2, "warning: connecting to venti: %r\n");
16185e96a66cSDavid du Colombier 	}
16195e96a66cSDavid du Colombier 	if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
1620*d7aba6c3SDavid du Colombier 		werrstr("fsOpen: %r");
1621*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
16225e96a66cSDavid du Colombier 		fsysPut(fsys);
16235e96a66cSDavid du Colombier 		return 0;
16245e96a66cSDavid du Colombier 	}
16250c6300e7SDavid du Colombier 	fsys->fs->name = fsys->name;	/* for better error messages */
16265e96a66cSDavid du Colombier 	fsys->noauth = noauth;
16275e96a66cSDavid du Colombier 	fsys->noperm = noperm;
16285e96a66cSDavid du Colombier 	fsys->wstatallow = wstatallow;
1629f4051287SDavid du Colombier 	fsys->fs->noatimeupd = noatimeupd;
1630*d7aba6c3SDavid du Colombier 	qunlock(&fsys->lock);
16315e96a66cSDavid du Colombier 	fsysPut(fsys);
16325e96a66cSDavid du Colombier 
163381cf8742SDavid du Colombier 	if(strcmp(name, "main") == 0)
163481cf8742SDavid du Colombier 		usersFileRead(nil);
163581cf8742SDavid du Colombier 
16365e96a66cSDavid du Colombier 	return 1;
16375e96a66cSDavid du Colombier }
16385e96a66cSDavid du Colombier 
16395e96a66cSDavid du Colombier static int
fsysUnconfig(char * name,int argc,char * argv[])16405e96a66cSDavid du Colombier fsysUnconfig(char* name, int argc, char* argv[])
16415e96a66cSDavid du Colombier {
16425e96a66cSDavid du Colombier 	Fsys *fsys, **fp;
16435e96a66cSDavid du Colombier 	char *usage = "usage: fsys name unconfig";
16445e96a66cSDavid du Colombier 
16455e96a66cSDavid du Colombier 	ARGBEGIN{
16465e96a66cSDavid du Colombier 	default:
16475e96a66cSDavid du Colombier 		return cliError(usage);
16485e96a66cSDavid du Colombier 	}ARGEND
16495e96a66cSDavid du Colombier 	if(argc)
16505e96a66cSDavid du Colombier 		return cliError(usage);
16515e96a66cSDavid du Colombier 
1652*d7aba6c3SDavid du Colombier 	wlock(&sbox.lock);
16535e96a66cSDavid du Colombier 	fp = &sbox.head;
16545e96a66cSDavid du Colombier 	for(fsys = *fp; fsys != nil; fsys = fsys->next){
16555e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) == 0)
16565e96a66cSDavid du Colombier 			break;
16575e96a66cSDavid du Colombier 		fp = &fsys->next;
16585e96a66cSDavid du Colombier 	}
16595e96a66cSDavid du Colombier 	if(fsys == nil){
1660*d7aba6c3SDavid du Colombier 		werrstr(EFsysNotFound, name);
1661*d7aba6c3SDavid du Colombier 		wunlock(&sbox.lock);
16625e96a66cSDavid du Colombier 		return 0;
16635e96a66cSDavid du Colombier 	}
16645e96a66cSDavid du Colombier 	if(fsys->ref != 0 || fsys->fs != nil){
1665*d7aba6c3SDavid du Colombier 		werrstr(EFsysBusy, fsys->name);
1666*d7aba6c3SDavid du Colombier 		wunlock(&sbox.lock);
16675e96a66cSDavid du Colombier 		return 0;
16685e96a66cSDavid du Colombier 	}
16695e96a66cSDavid du Colombier 	*fp = fsys->next;
1670*d7aba6c3SDavid du Colombier 	wunlock(&sbox.lock);
16715e96a66cSDavid du Colombier 
1672*d7aba6c3SDavid du Colombier 	if(fsys->session != nil)
1673*d7aba6c3SDavid du Colombier 		vtfreeconn(fsys->session);
16745e96a66cSDavid du Colombier 	if(fsys->venti != nil)
1675*d7aba6c3SDavid du Colombier 		vtfree(fsys->venti);
16765e96a66cSDavid du Colombier 	if(fsys->dev != nil)
1677*d7aba6c3SDavid du Colombier 		vtfree(fsys->dev);
16785e96a66cSDavid du Colombier 	if(fsys->name != nil)
1679*d7aba6c3SDavid du Colombier 		vtfree(fsys->name);
1680*d7aba6c3SDavid du Colombier 	vtfree(fsys);
16815e96a66cSDavid du Colombier 
16825e96a66cSDavid du Colombier 	return 1;
16835e96a66cSDavid du Colombier }
16845e96a66cSDavid du Colombier 
16855e96a66cSDavid du Colombier static int
fsysConfig(char * name,int argc,char * argv[])16865e96a66cSDavid du Colombier fsysConfig(char* name, int argc, char* argv[])
16875e96a66cSDavid du Colombier {
16885e96a66cSDavid du Colombier 	Fsys *fsys;
16891bdadbfaSDavid du Colombier 	char *part;
16901bdadbfaSDavid du Colombier 	char *usage = "usage: fsys name config [dev]";
16915e96a66cSDavid du Colombier 
16925e96a66cSDavid du Colombier 	ARGBEGIN{
16935e96a66cSDavid du Colombier 	default:
16945e96a66cSDavid du Colombier 		return cliError(usage);
16955e96a66cSDavid du Colombier 	}ARGEND
16961bdadbfaSDavid du Colombier 	if(argc > 1)
16975e96a66cSDavid du Colombier 		return cliError(usage);
16985e96a66cSDavid du Colombier 
16991bdadbfaSDavid du Colombier 	if(argc == 0)
17001bdadbfaSDavid du Colombier 		part = foptname;
17011bdadbfaSDavid du Colombier 	else
17021bdadbfaSDavid du Colombier 		part = argv[0];
17031bdadbfaSDavid du Colombier 
17041bdadbfaSDavid du Colombier 	if((fsys = _fsysGet(part)) != nil){
1705*d7aba6c3SDavid du Colombier 		qlock(&fsys->lock);
17065e96a66cSDavid du Colombier 		if(fsys->fs != nil){
1707*d7aba6c3SDavid du Colombier 			werrstr(EFsysBusy, fsys->name);
1708*d7aba6c3SDavid du Colombier 			qunlock(&fsys->lock);
17095e96a66cSDavid du Colombier 			fsysPut(fsys);
17105e96a66cSDavid du Colombier 			return 0;
17115e96a66cSDavid du Colombier 		}
1712*d7aba6c3SDavid du Colombier 		vtfree(fsys->dev);
1713*d7aba6c3SDavid du Colombier 		fsys->dev = vtstrdup(part);
1714*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
17155e96a66cSDavid du Colombier 	}
17161bdadbfaSDavid du Colombier 	else if((fsys = fsysAlloc(name, part)) == nil)
17175e96a66cSDavid du Colombier 		return 0;
17185e96a66cSDavid du Colombier 
17195e96a66cSDavid du Colombier 	fsysPut(fsys);
17205e96a66cSDavid du Colombier 	return 1;
17215e96a66cSDavid du Colombier }
17225e96a66cSDavid du Colombier 
17235e96a66cSDavid du Colombier static struct {
17245e96a66cSDavid du Colombier 	char*	cmd;
17255e96a66cSDavid du Colombier 	int	(*f)(Fsys*, int, char**);
17265e96a66cSDavid du Colombier 	int	(*f1)(char*, int, char**);
17275e96a66cSDavid du Colombier } fsyscmd[] = {
17285e96a66cSDavid du Colombier 	{ "close",	fsysClose, },
17295e96a66cSDavid du Colombier 	{ "config",	nil, fsysConfig, },
17305e96a66cSDavid du Colombier 	{ "open",	nil, fsysOpen, },
17315e96a66cSDavid du Colombier 	{ "unconfig",	nil, fsysUnconfig, },
17325e96a66cSDavid du Colombier 	{ "venti",	nil, fsysVenti, },
17335e96a66cSDavid du Colombier 
17345e96a66cSDavid du Colombier 	{ "bfree",	fsysBfree, },
17355e96a66cSDavid du Colombier 	{ "block",	fsysBlock, },
1736e569ccb5SDavid du Colombier 	{ "check",	fsysCheck, },
17375e96a66cSDavid du Colombier 	{ "clre",	fsysClre, },
17385e96a66cSDavid du Colombier 	{ "clri",	fsysClri, },
17395e96a66cSDavid du Colombier 	{ "clrp",	fsysClrp, },
17405e96a66cSDavid du Colombier 	{ "create",	fsysCreate, },
17417abd426fSDavid du Colombier 	{ "df",		fsysDf, },
17425e96a66cSDavid du Colombier 	{ "epoch",	fsysEpoch, },
174381cf8742SDavid du Colombier 	{ "halt",	fsysHalt, },
17445e96a66cSDavid du Colombier 	{ "label",	fsysLabel, },
17455e96a66cSDavid du Colombier 	{ "remove",	fsysRemove, },
17465e96a66cSDavid du Colombier 	{ "snap",	fsysSnap, },
17475e96a66cSDavid du Colombier 	{ "snaptime",	fsysSnapTime, },
1748dc5a79c1SDavid du Colombier 	{ "snapclean",	fsysSnapClean, },
17495e96a66cSDavid du Colombier 	{ "stat",	fsysStat, },
17505e96a66cSDavid du Colombier 	{ "sync",	fsysSync, },
175181cf8742SDavid du Colombier 	{ "unhalt",	fsysUnhalt, },
17525e96a66cSDavid du Colombier 	{ "wstat",	fsysWstat, },
17535e96a66cSDavid du Colombier 	{ "vac",	fsysVac, },
17545e96a66cSDavid du Colombier 
17555e96a66cSDavid du Colombier 	{ nil,		nil, },
17565e96a66cSDavid du Colombier };
17575e96a66cSDavid du Colombier 
17585e96a66cSDavid du Colombier static int
fsysXXX1(Fsys * fsys,int i,int argc,char * argv[])175981cf8742SDavid du Colombier fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
176081cf8742SDavid du Colombier {
176181cf8742SDavid du Colombier 	int r;
176281cf8742SDavid du Colombier 
1763*d7aba6c3SDavid du Colombier 	qlock(&fsys->lock);
176481cf8742SDavid du Colombier 	if(fsys->fs == nil){
1765*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
1766*d7aba6c3SDavid du Colombier 		werrstr(EFsysNotOpen, fsys->name);
176781cf8742SDavid du Colombier 		return 0;
176881cf8742SDavid du Colombier 	}
176981cf8742SDavid du Colombier 
1770e569ccb5SDavid du Colombier 	if(fsys->fs->halted
1771e569ccb5SDavid du Colombier 	&& fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){
1772*d7aba6c3SDavid du Colombier 		werrstr("file system %s is halted", fsys->name);
1773*d7aba6c3SDavid du Colombier 		qunlock(&fsys->lock);
177481cf8742SDavid du Colombier 		return 0;
177581cf8742SDavid du Colombier 	}
177681cf8742SDavid du Colombier 
177781cf8742SDavid du Colombier 	r = (*fsyscmd[i].f)(fsys, argc, argv);
1778*d7aba6c3SDavid du Colombier 	qunlock(&fsys->lock);
177981cf8742SDavid du Colombier 	return r;
178081cf8742SDavid du Colombier }
178181cf8742SDavid du Colombier 
178281cf8742SDavid du Colombier static int
fsysXXX(char * name,int argc,char * argv[])17835e96a66cSDavid du Colombier fsysXXX(char* name, int argc, char* argv[])
17845e96a66cSDavid du Colombier {
17855e96a66cSDavid du Colombier 	int i, r;
17865e96a66cSDavid du Colombier 	Fsys *fsys;
17875e96a66cSDavid du Colombier 
17885e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
17895e96a66cSDavid du Colombier 		if(strcmp(fsyscmd[i].cmd, argv[0]) == 0)
17905e96a66cSDavid du Colombier 			break;
17915e96a66cSDavid du Colombier 	}
17925e96a66cSDavid du Colombier 
17935e96a66cSDavid du Colombier 	if(fsyscmd[i].cmd == nil){
1794*d7aba6c3SDavid du Colombier 		werrstr("unknown command - '%s'", argv[0]);
17955e96a66cSDavid du Colombier 		return 0;
17965e96a66cSDavid du Colombier 	}
17975e96a66cSDavid du Colombier 
17985e96a66cSDavid du Colombier 	/* some commands want the name... */
179981cf8742SDavid du Colombier 	if(fsyscmd[i].f1 != nil){
180081cf8742SDavid du Colombier 		if(strcmp(name, FsysAll) == 0){
1801*d7aba6c3SDavid du Colombier 			werrstr("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
18025e96a66cSDavid du Colombier 			return 0;
18035e96a66cSDavid du Colombier 		}
180481cf8742SDavid du Colombier 		return (*fsyscmd[i].f1)(name, argc, argv);
180581cf8742SDavid du Colombier 	}
18065e96a66cSDavid du Colombier 
180781cf8742SDavid du Colombier 	/* ... but most commands want the Fsys */
180881cf8742SDavid du Colombier 	if(strcmp(name, FsysAll) == 0){
180981cf8742SDavid du Colombier 		r = 1;
1810*d7aba6c3SDavid du Colombier 		rlock(&sbox.lock);
181181cf8742SDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
181281cf8742SDavid du Colombier 			fsys->ref++;
181381cf8742SDavid du Colombier 			r = fsysXXX1(fsys, i, argc, argv) && r;
181481cf8742SDavid du Colombier 			fsys->ref--;
181581cf8742SDavid du Colombier 		}
1816*d7aba6c3SDavid du Colombier 		runlock(&sbox.lock);
181781cf8742SDavid du Colombier 	}else{
181881cf8742SDavid du Colombier 		if((fsys = _fsysGet(name)) == nil)
181981cf8742SDavid du Colombier 			return 0;
182081cf8742SDavid du Colombier 		r = fsysXXX1(fsys, i, argc, argv);
18215e96a66cSDavid du Colombier 		fsysPut(fsys);
182281cf8742SDavid du Colombier 	}
18235e96a66cSDavid du Colombier 	return r;
18245e96a66cSDavid du Colombier }
18255e96a66cSDavid du Colombier 
18265e96a66cSDavid du Colombier static int
cmdFsysXXX(int argc,char * argv[])18275e96a66cSDavid du Colombier cmdFsysXXX(int argc, char* argv[])
18285e96a66cSDavid du Colombier {
18295e96a66cSDavid du Colombier 	char *name;
18305e96a66cSDavid du Colombier 
18315e96a66cSDavid du Colombier 	if((name = sbox.curfsys) == nil){
1832*d7aba6c3SDavid du Colombier 		werrstr(EFsysNoCurrent, argv[0]);
18335e96a66cSDavid du Colombier 		return 0;
18345e96a66cSDavid du Colombier 	}
18355e96a66cSDavid du Colombier 
18365e96a66cSDavid du Colombier 	return fsysXXX(name, argc, argv);
18375e96a66cSDavid du Colombier }
18385e96a66cSDavid du Colombier 
18395e96a66cSDavid du Colombier static int
cmdFsys(int argc,char * argv[])18405e96a66cSDavid du Colombier cmdFsys(int argc, char* argv[])
18415e96a66cSDavid du Colombier {
18425e96a66cSDavid du Colombier 	Fsys *fsys;
18435e96a66cSDavid du Colombier 	char *usage = "usage: fsys [name ...]";
18445e96a66cSDavid du Colombier 
18455e96a66cSDavid du Colombier 	ARGBEGIN{
18465e96a66cSDavid du Colombier 	default:
18475e96a66cSDavid du Colombier 		return cliError(usage);
18485e96a66cSDavid du Colombier 	}ARGEND
18495e96a66cSDavid du Colombier 
18505e96a66cSDavid du Colombier 	if(argc == 0){
1851*d7aba6c3SDavid du Colombier 		rlock(&sbox.lock);
1852b8a11165SDavid du Colombier 		currfsysname = sbox.head->name;
18535e96a66cSDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next)
18545e96a66cSDavid du Colombier 			consPrint("\t%s\n", fsys->name);
1855*d7aba6c3SDavid du Colombier 		runlock(&sbox.lock);
18565e96a66cSDavid du Colombier 		return 1;
18575e96a66cSDavid du Colombier 	}
18585e96a66cSDavid du Colombier 	if(argc == 1){
185981cf8742SDavid du Colombier 		fsys = nil;
186081cf8742SDavid du Colombier 		if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
18615e96a66cSDavid du Colombier 			return 0;
1862*d7aba6c3SDavid du Colombier 		sbox.curfsys = vtstrdup(argv[0]);
18635e96a66cSDavid du Colombier 		consPrompt(sbox.curfsys);
186481cf8742SDavid du Colombier 		if(fsys)
18655e96a66cSDavid du Colombier 			fsysPut(fsys);
18665e96a66cSDavid du Colombier 		return 1;
18675e96a66cSDavid du Colombier 	}
18685e96a66cSDavid du Colombier 
18695e96a66cSDavid du Colombier 	return fsysXXX(argv[0], argc-1, argv+1);
18705e96a66cSDavid du Colombier }
18715e96a66cSDavid du Colombier 
18725e96a66cSDavid du Colombier int
fsysInit(void)18735e96a66cSDavid du Colombier fsysInit(void)
18745e96a66cSDavid du Colombier {
18755e96a66cSDavid du Colombier 	int i;
18765e96a66cSDavid du Colombier 
18775e96a66cSDavid du Colombier 	fmtinstall('H', encodefmt);
18785e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
18795e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
18805e96a66cSDavid du Colombier 
18815e96a66cSDavid du Colombier 	cliAddCmd("fsys", cmdFsys);
18825e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
18835e96a66cSDavid du Colombier 		if(fsyscmd[i].f != nil)
18845e96a66cSDavid du Colombier 			cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX);
18855e96a66cSDavid du Colombier 	}
18865e96a66cSDavid du Colombier 	/* the venti cmd is special: the fs can be either open or closed */
18875e96a66cSDavid du Colombier 	cliAddCmd("venti", cmdFsysXXX);
18885e96a66cSDavid du Colombier 	cliAddCmd("printconfig", cmdPrintConfig);
18895e96a66cSDavid du Colombier 
18905e96a66cSDavid du Colombier 	return 1;
18915e96a66cSDavid du Colombier }
1892