xref: /plan9-contrib/sys/src/cmd/fossil/9fsys.c (revision 1bdadbfaf2cf3795c8a455b1b74a23e47e115183)
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 
75e96a66cSDavid du Colombier typedef struct Fsys Fsys;
85e96a66cSDavid du Colombier 
97abd426fSDavid du Colombier struct Fsys {
105e96a66cSDavid du Colombier 	VtLock* lock;
115e96a66cSDavid du Colombier 
120c6300e7SDavid du Colombier 	char*	name;		/* copy here & Fs to ease error reporting */
135e96a66cSDavid du Colombier 	char*	dev;
145e96a66cSDavid du Colombier 	char*	venti;
155e96a66cSDavid du Colombier 
165e96a66cSDavid du Colombier 	Fs*	fs;
175e96a66cSDavid du Colombier 	VtSession* session;
185e96a66cSDavid du Colombier 	int	ref;
195e96a66cSDavid du Colombier 
205e96a66cSDavid du Colombier 	int	noauth;
215e96a66cSDavid du Colombier 	int	noperm;
225e96a66cSDavid du Colombier 	int	wstatallow;
235e96a66cSDavid du Colombier 
245e96a66cSDavid du Colombier 	Fsys*	next;
257abd426fSDavid du Colombier };
265e96a66cSDavid du Colombier 
27b8a11165SDavid du Colombier int mempcnt;			/* from fossil.c */
28b8a11165SDavid du Colombier 
29b8a11165SDavid du Colombier int	fsGetBlockSize(Fs *fs);
30b8a11165SDavid du Colombier 
315e96a66cSDavid du Colombier static struct {
325e96a66cSDavid du Colombier 	VtLock*	lock;
335e96a66cSDavid du Colombier 	Fsys*	head;
345e96a66cSDavid du Colombier 	Fsys*	tail;
355e96a66cSDavid du Colombier 
365e96a66cSDavid du Colombier 	char*	curfsys;
375e96a66cSDavid du Colombier } sbox;
385e96a66cSDavid du Colombier 
395e96a66cSDavid du Colombier static char *_argv0;
405e96a66cSDavid du Colombier #define argv0 _argv0
415e96a66cSDavid du Colombier 
4281cf8742SDavid du Colombier static char FsysAll[] = "all";
4381cf8742SDavid du Colombier 
445e96a66cSDavid du Colombier static char EFsysBusy[] = "fsys: '%s' busy";
455e96a66cSDavid du Colombier static char EFsysExists[] = "fsys: '%s' already exists";
465e96a66cSDavid du Colombier static char EFsysNoCurrent[] = "fsys: no current fsys";
475e96a66cSDavid du Colombier static char EFsysNotFound[] = "fsys: '%s' not found";
485e96a66cSDavid du Colombier static char EFsysNotOpen[] = "fsys: '%s' not open";
495e96a66cSDavid du Colombier 
50ea58ad6fSDavid du Colombier static char *
51ea58ad6fSDavid du Colombier ventihost(char *host)
52ea58ad6fSDavid du Colombier {
53ea58ad6fSDavid du Colombier 	if(host != nil)
54*1bdadbfaSDavid du Colombier 		return vtStrDup(host);
55ea58ad6fSDavid du Colombier 	host = getenv("venti");
56ea58ad6fSDavid du Colombier 	if(host == nil)
57*1bdadbfaSDavid du Colombier 		host = vtStrDup("$venti");
58ea58ad6fSDavid du Colombier 	return host;
59ea58ad6fSDavid du Colombier }
60ea58ad6fSDavid du Colombier 
61ea58ad6fSDavid du Colombier static void
62ea58ad6fSDavid du Colombier prventihost(char *host)
63ea58ad6fSDavid du Colombier {
64ea58ad6fSDavid du Colombier 	char *vh;
65ea58ad6fSDavid du Colombier 
66ea58ad6fSDavid du Colombier 	vh = ventihost(host);
67ea58ad6fSDavid du Colombier 	fprint(2, "%s: dialing venti at %s\n",
68ea58ad6fSDavid du Colombier 		argv0, netmkaddr(vh, 0, "venti"));
69ea58ad6fSDavid du Colombier 	free(vh);
70ea58ad6fSDavid du Colombier }
71ea58ad6fSDavid du Colombier 
72ea58ad6fSDavid du Colombier static VtSession *
73ea58ad6fSDavid du Colombier myDial(char *host, int canfail)
74ea58ad6fSDavid du Colombier {
75ea58ad6fSDavid du Colombier 	prventihost(host);
76ea58ad6fSDavid du Colombier 	return vtDial(host, canfail);
77ea58ad6fSDavid du Colombier }
78ea58ad6fSDavid du Colombier 
79ea58ad6fSDavid du Colombier static int
80ea58ad6fSDavid du Colombier myRedial(VtSession *z, char *host)
81ea58ad6fSDavid du Colombier {
82ea58ad6fSDavid du Colombier 	prventihost(host);
83ea58ad6fSDavid du Colombier 	return vtRedial(z, host);
84ea58ad6fSDavid du Colombier }
85ea58ad6fSDavid du Colombier 
865e96a66cSDavid du Colombier static Fsys*
875e96a66cSDavid du Colombier _fsysGet(char* name)
885e96a66cSDavid du Colombier {
895e96a66cSDavid du Colombier 	Fsys *fsys;
905e96a66cSDavid du Colombier 
915e96a66cSDavid du Colombier 	if(name == nil || name[0] == '\0')
925e96a66cSDavid du Colombier 		name = "main";
935e96a66cSDavid du Colombier 
945e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
955e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
965e96a66cSDavid du Colombier 		if(strcmp(name, fsys->name) == 0){
975e96a66cSDavid du Colombier 			fsys->ref++;
985e96a66cSDavid du Colombier 			break;
995e96a66cSDavid du Colombier 		}
1005e96a66cSDavid du Colombier 	}
101dc5a79c1SDavid du Colombier 	vtRUnlock(sbox.lock);
1025e96a66cSDavid du Colombier 	if(fsys == nil)
1035e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
1045e96a66cSDavid du Colombier 	return fsys;
1055e96a66cSDavid du Colombier }
1065e96a66cSDavid du Colombier 
1075e96a66cSDavid du Colombier static int
1085e96a66cSDavid du Colombier cmdPrintConfig(int argc, char* argv[])
1095e96a66cSDavid du Colombier {
1105e96a66cSDavid du Colombier 	Fsys *fsys;
1115e96a66cSDavid du Colombier 	char *usage = "usage: printconfig";
1125e96a66cSDavid du Colombier 
1135e96a66cSDavid du Colombier 	ARGBEGIN{
1145e96a66cSDavid du Colombier 	default:
1155e96a66cSDavid du Colombier 		return cliError(usage);
1165e96a66cSDavid du Colombier 	}ARGEND
1175e96a66cSDavid du Colombier 
1185e96a66cSDavid du Colombier 	if(argc)
1195e96a66cSDavid du Colombier 		return cliError(usage);
1205e96a66cSDavid du Colombier 
1215e96a66cSDavid du Colombier 	vtRLock(sbox.lock);
1225e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
1235e96a66cSDavid du Colombier 		consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev);
1245e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
1250c6300e7SDavid du Colombier 			consPrint("\tfsys %s venti %q\n", fsys->name,
1260c6300e7SDavid du Colombier 				fsys->venti);
1275e96a66cSDavid du Colombier 	}
1285e96a66cSDavid du Colombier 	vtRUnlock(sbox.lock);
1295e96a66cSDavid du Colombier 	return 1;
1305e96a66cSDavid du Colombier }
1315e96a66cSDavid du Colombier 
1325e96a66cSDavid du Colombier Fsys*
1335e96a66cSDavid du Colombier fsysGet(char* name)
1345e96a66cSDavid du Colombier {
1355e96a66cSDavid du Colombier 	Fsys *fsys;
1365e96a66cSDavid du Colombier 
1375e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
1385e96a66cSDavid du Colombier 		return nil;
1395e96a66cSDavid du Colombier 
1405e96a66cSDavid du Colombier 	vtLock(fsys->lock);
1415e96a66cSDavid du Colombier 	if(fsys->fs == nil){
1425e96a66cSDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
1435e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
1445e96a66cSDavid du Colombier 		fsysPut(fsys);
1455e96a66cSDavid du Colombier 		return nil;
1465e96a66cSDavid du Colombier 	}
1475e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
1485e96a66cSDavid du Colombier 
1495e96a66cSDavid du Colombier 	return fsys;
1505e96a66cSDavid du Colombier }
1515e96a66cSDavid du Colombier 
15261201b97SDavid du Colombier char*
15361201b97SDavid du Colombier fsysGetName(Fsys* fsys)
15461201b97SDavid du Colombier {
15561201b97SDavid du Colombier 	return fsys->name;
15661201b97SDavid du Colombier }
15761201b97SDavid du Colombier 
1585e96a66cSDavid du Colombier Fsys*
1595e96a66cSDavid du Colombier fsysIncRef(Fsys* fsys)
1605e96a66cSDavid du Colombier {
1615e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1625e96a66cSDavid du Colombier 	fsys->ref++;
1635e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1645e96a66cSDavid du Colombier 
1655e96a66cSDavid du Colombier 	return fsys;
1665e96a66cSDavid du Colombier }
1675e96a66cSDavid du Colombier 
1685e96a66cSDavid du Colombier void
1695e96a66cSDavid du Colombier fsysPut(Fsys* fsys)
1705e96a66cSDavid du Colombier {
1715e96a66cSDavid du Colombier 	vtLock(sbox.lock);
1725e96a66cSDavid du Colombier 	assert(fsys->ref > 0);
1735e96a66cSDavid du Colombier 	fsys->ref--;
1745e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1755e96a66cSDavid du Colombier }
1765e96a66cSDavid du Colombier 
1775e96a66cSDavid du Colombier Fs*
1785e96a66cSDavid du Colombier fsysGetFs(Fsys* fsys)
1795e96a66cSDavid du Colombier {
1805e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
1815e96a66cSDavid du Colombier 
1825e96a66cSDavid du Colombier 	return fsys->fs;
1835e96a66cSDavid du Colombier }
1845e96a66cSDavid du Colombier 
1855e96a66cSDavid du Colombier void
1865e96a66cSDavid du Colombier fsysFsRlock(Fsys* fsys)
1875e96a66cSDavid du Colombier {
1885e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
1895e96a66cSDavid du Colombier }
1905e96a66cSDavid du Colombier 
1915e96a66cSDavid du Colombier void
1925e96a66cSDavid du Colombier fsysFsRUnlock(Fsys* fsys)
1935e96a66cSDavid du Colombier {
1945e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
1955e96a66cSDavid du Colombier }
1965e96a66cSDavid du Colombier 
1975e96a66cSDavid du Colombier int
1985e96a66cSDavid du Colombier fsysNoAuthCheck(Fsys* fsys)
1995e96a66cSDavid du Colombier {
2005e96a66cSDavid du Colombier 	return fsys->noauth;
2015e96a66cSDavid du Colombier }
2025e96a66cSDavid du Colombier 
2035e96a66cSDavid du Colombier int
2045e96a66cSDavid du Colombier fsysNoPermCheck(Fsys* fsys)
2055e96a66cSDavid du Colombier {
2065e96a66cSDavid du Colombier 	return fsys->noperm;
2075e96a66cSDavid du Colombier }
2085e96a66cSDavid du Colombier 
2095e96a66cSDavid du Colombier int
2105e96a66cSDavid du Colombier fsysWstatAllow(Fsys* fsys)
2115e96a66cSDavid du Colombier {
2125e96a66cSDavid du Colombier 	return fsys->wstatallow;
2135e96a66cSDavid du Colombier }
2145e96a66cSDavid du Colombier 
2155e96a66cSDavid du Colombier static char modechars[] = "YUGalLdHSATs";
2165e96a66cSDavid du Colombier static ulong modebits[] = {
2175e96a66cSDavid du Colombier 	ModeSticky,
2185e96a66cSDavid du Colombier 	ModeSetUid,
2195e96a66cSDavid du Colombier 	ModeSetGid,
2205e96a66cSDavid du Colombier 	ModeAppend,
2215e96a66cSDavid du Colombier 	ModeExclusive,
2225e96a66cSDavid du Colombier 	ModeLink,
2235e96a66cSDavid du Colombier 	ModeDir,
2245e96a66cSDavid du Colombier 	ModeHidden,
2255e96a66cSDavid du Colombier 	ModeSystem,
2265e96a66cSDavid du Colombier 	ModeArchive,
2275e96a66cSDavid du Colombier 	ModeTemporary,
2285e96a66cSDavid du Colombier 	ModeSnapshot,
2295e96a66cSDavid du Colombier 	0
2305e96a66cSDavid du Colombier };
2315e96a66cSDavid du Colombier 
2325e96a66cSDavid du Colombier char*
2335e96a66cSDavid du Colombier fsysModeString(ulong mode, char *buf)
2345e96a66cSDavid du Colombier {
2355e96a66cSDavid du Colombier 	int i;
2365e96a66cSDavid du Colombier 	char *p;
2375e96a66cSDavid du Colombier 
2385e96a66cSDavid du Colombier 	p = buf;
2395e96a66cSDavid du Colombier 	for(i=0; modebits[i]; i++)
2405e96a66cSDavid du Colombier 		if(mode & modebits[i])
2415e96a66cSDavid du Colombier 			*p++ = modechars[i];
2425e96a66cSDavid du Colombier 	sprint(p, "%luo", mode&0777);
2435e96a66cSDavid du Colombier 	return buf;
2445e96a66cSDavid du Colombier }
2455e96a66cSDavid du Colombier 
2465e96a66cSDavid du Colombier int
2475e96a66cSDavid du Colombier fsysParseMode(char* s, ulong* mode)
2485e96a66cSDavid du Colombier {
2495e96a66cSDavid du Colombier 	ulong x, y;
2505e96a66cSDavid du Colombier 	char *p;
2515e96a66cSDavid du Colombier 
2525e96a66cSDavid du Colombier 	x = 0;
2535e96a66cSDavid du Colombier 	for(; *s < '0' || *s > '9'; s++){
2545e96a66cSDavid du Colombier 		if(*s == 0)
2555e96a66cSDavid du Colombier 			return 0;
2565e96a66cSDavid du Colombier 		p = strchr(modechars, *s);
2575e96a66cSDavid du Colombier 		if(p == nil)
2585e96a66cSDavid du Colombier 			return 0;
2595e96a66cSDavid du Colombier 		x |= modebits[p-modechars];
2605e96a66cSDavid du Colombier 	}
2615e96a66cSDavid du Colombier 	y = strtoul(s, &p, 8);
2625e96a66cSDavid du Colombier 	if(*p != '\0' || y > 0777)
2635e96a66cSDavid du Colombier 		return 0;
2645e96a66cSDavid du Colombier 	*mode = x|y;
2655e96a66cSDavid du Colombier 	return 1;
2665e96a66cSDavid du Colombier }
2675e96a66cSDavid du Colombier 
2685e96a66cSDavid du Colombier File*
2695e96a66cSDavid du Colombier fsysGetRoot(Fsys* fsys, char* name)
2705e96a66cSDavid du Colombier {
2715e96a66cSDavid du Colombier 	File *root, *sub;
2725e96a66cSDavid du Colombier 
2735e96a66cSDavid du Colombier 	assert(fsys != nil && fsys->fs != nil);
2745e96a66cSDavid du Colombier 
2755e96a66cSDavid du Colombier 	root = fsGetRoot(fsys->fs);
2765e96a66cSDavid du Colombier 	if(name == nil || strcmp(name, "") == 0)
2775e96a66cSDavid du Colombier 		return root;
2785e96a66cSDavid du Colombier 
2795e96a66cSDavid du Colombier 	sub = fileWalk(root, name);
2805e96a66cSDavid du Colombier 	fileDecRef(root);
2815e96a66cSDavid du Colombier 
2825e96a66cSDavid du Colombier 	return sub;
2835e96a66cSDavid du Colombier }
2845e96a66cSDavid du Colombier 
2855e96a66cSDavid du Colombier static Fsys*
2865e96a66cSDavid du Colombier fsysAlloc(char* name, char* dev)
2875e96a66cSDavid du Colombier {
2885e96a66cSDavid du Colombier 	Fsys *fsys;
2895e96a66cSDavid du Colombier 
2905e96a66cSDavid du Colombier 	vtLock(sbox.lock);
2915e96a66cSDavid du Colombier 	for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
2925e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) != 0)
2935e96a66cSDavid du Colombier 			continue;
2945e96a66cSDavid du Colombier 		vtSetError(EFsysExists, name);
2955e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
2965e96a66cSDavid du Colombier 		return nil;
2975e96a66cSDavid du Colombier 	}
2985e96a66cSDavid du Colombier 
2995e96a66cSDavid du Colombier 	fsys = vtMemAllocZ(sizeof(Fsys));
3005e96a66cSDavid du Colombier 	fsys->lock = vtLockAlloc();
3015e96a66cSDavid du Colombier 	fsys->name = vtStrDup(name);
3025e96a66cSDavid du Colombier 	fsys->dev = vtStrDup(dev);
3035e96a66cSDavid du Colombier 
3045e96a66cSDavid du Colombier 	fsys->ref = 1;
3055e96a66cSDavid du Colombier 
3065e96a66cSDavid du Colombier 	if(sbox.tail != nil)
3075e96a66cSDavid du Colombier 		sbox.tail->next = fsys;
3085e96a66cSDavid du Colombier 	else
3095e96a66cSDavid du Colombier 		sbox.head = fsys;
3105e96a66cSDavid du Colombier 	sbox.tail = fsys;
3115e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
3125e96a66cSDavid du Colombier 
3135e96a66cSDavid du Colombier 	return fsys;
3145e96a66cSDavid du Colombier }
3155e96a66cSDavid du Colombier 
3165e96a66cSDavid du Colombier static int
3175e96a66cSDavid du Colombier fsysClose(Fsys* fsys, int argc, char* argv[])
3185e96a66cSDavid du Colombier {
3195e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] close";
3205e96a66cSDavid du Colombier 
3215e96a66cSDavid du Colombier 	ARGBEGIN{
3225e96a66cSDavid du Colombier 	default:
3235e96a66cSDavid du Colombier 		return cliError(usage);
3245e96a66cSDavid du Colombier 	}ARGEND
3255e96a66cSDavid du Colombier 	if(argc)
3265e96a66cSDavid du Colombier 		return cliError(usage);
3275e96a66cSDavid du Colombier 
32868412abfSDavid du Colombier 	return cliError("close isn't working yet; halt %s and then kill fossil",
32968412abfSDavid du Colombier 		fsys->name);
3305e96a66cSDavid du Colombier 
3315e96a66cSDavid du Colombier 	/*
3325e96a66cSDavid du Colombier 	 * Oooh. This could be hard. What if fsys->ref != 1?
3335e96a66cSDavid du Colombier 	 * Also, fsClose() either does the job or panics, can we
3345e96a66cSDavid du Colombier 	 * gracefully detect it's still busy?
3355e96a66cSDavid du Colombier 	 *
3365e96a66cSDavid du Colombier 	 * More thought and care needed here.
3375e96a66cSDavid du Colombier 	fsClose(fsys->fs);
3385e96a66cSDavid du Colombier 	fsys->fs = nil;
3395e96a66cSDavid du Colombier 	vtClose(fsys->session);
3405e96a66cSDavid du Colombier 	fsys->session = nil;
3415e96a66cSDavid du Colombier 
3425e96a66cSDavid du Colombier 	if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){
3435e96a66cSDavid du Colombier 		sbox.curfsys = nil;
3445e96a66cSDavid du Colombier 		consPrompt(nil);
3455e96a66cSDavid du Colombier 	}
3465e96a66cSDavid du Colombier 
3475e96a66cSDavid du Colombier 	return 1;
34868412abfSDavid du Colombier 	 */
3495e96a66cSDavid du Colombier }
3505e96a66cSDavid du Colombier 
3515e96a66cSDavid du Colombier static int
3525e96a66cSDavid du Colombier fsysVac(Fsys* fsys, int argc, char* argv[])
3535e96a66cSDavid du Colombier {
3545e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
3555e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] vac path";
3565e96a66cSDavid du Colombier 
3575e96a66cSDavid du Colombier 	ARGBEGIN{
3585e96a66cSDavid du Colombier 	default:
3595e96a66cSDavid du Colombier 		return cliError(usage);
3605e96a66cSDavid du Colombier 	}ARGEND
3615e96a66cSDavid du Colombier 	if(argc != 1)
3625e96a66cSDavid du Colombier 		return cliError(usage);
3635e96a66cSDavid du Colombier 
3645e96a66cSDavid du Colombier 	if(!fsVac(fsys->fs, argv[0], score))
3655e96a66cSDavid du Colombier 		return 0;
3665e96a66cSDavid du Colombier 
3675e96a66cSDavid du Colombier 	consPrint("vac:%V\n", score);
3685e96a66cSDavid du Colombier 	return 1;
3695e96a66cSDavid du Colombier }
3705e96a66cSDavid du Colombier 
3715e96a66cSDavid du Colombier static int
3725e96a66cSDavid du Colombier fsysSnap(Fsys* fsys, int argc, char* argv[])
3735e96a66cSDavid du Colombier {
3745e96a66cSDavid du Colombier 	int doarchive;
375c3c4501eSDavid du Colombier 	char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]";
376c3c4501eSDavid du Colombier 	char *src, *dst;
3775e96a66cSDavid du Colombier 
378c3c4501eSDavid du Colombier 	src = nil;
379c3c4501eSDavid du Colombier 	dst = nil;
3805e96a66cSDavid du Colombier 	doarchive = 0;
3815e96a66cSDavid du Colombier 	ARGBEGIN{
3825e96a66cSDavid du Colombier 	default:
3835e96a66cSDavid du Colombier 		return cliError(usage);
3845e96a66cSDavid du Colombier 	case 'a':
3855e96a66cSDavid du Colombier 		doarchive = 1;
3865e96a66cSDavid du Colombier 		break;
387c3c4501eSDavid du Colombier 	case 'd':
388c3c4501eSDavid du Colombier 		if((dst = ARGF()) == nil)
389c3c4501eSDavid du Colombier 			return cliError(usage);
390c3c4501eSDavid du Colombier 		break;
391c3c4501eSDavid du Colombier 	case 's':
392c3c4501eSDavid du Colombier 		if((src = ARGF()) == nil)
393c3c4501eSDavid du Colombier 			return cliError(usage);
394c3c4501eSDavid du Colombier 		break;
3955e96a66cSDavid du Colombier 	}ARGEND
3965e96a66cSDavid du Colombier 	if(argc)
3975e96a66cSDavid du Colombier 		return cliError(usage);
3985e96a66cSDavid du Colombier 
399c3c4501eSDavid du Colombier 	if(!fsSnapshot(fsys->fs, src, dst, doarchive))
4005e96a66cSDavid du Colombier 		return 0;
4015e96a66cSDavid du Colombier 
4025e96a66cSDavid du Colombier 	return 1;
4035e96a66cSDavid du Colombier }
4045e96a66cSDavid du Colombier 
4055e96a66cSDavid du Colombier static int
406dc5a79c1SDavid du Colombier fsysSnapClean(Fsys *fsys, int argc, char* argv[])
407dc5a79c1SDavid du Colombier {
408dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
409dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snapclean [maxminutes]\n";
410dc5a79c1SDavid du Colombier 
411dc5a79c1SDavid du Colombier 	ARGBEGIN{
412dc5a79c1SDavid du Colombier 	default:
413dc5a79c1SDavid du Colombier 		return cliError(usage);
414dc5a79c1SDavid du Colombier 	}ARGEND
415dc5a79c1SDavid du Colombier 
416dc5a79c1SDavid du Colombier 	if(argc > 1)
417dc5a79c1SDavid du Colombier 		return cliError(usage);
418dc5a79c1SDavid du Colombier 	if(argc == 1)
419f83f9c78SDavid du Colombier 		life = atoi(argv[0]);
420dc5a79c1SDavid du Colombier 	else
421dc5a79c1SDavid du Colombier 		snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
422dc5a79c1SDavid du Colombier 
423dc5a79c1SDavid du Colombier 	fsSnapshotCleanup(fsys->fs, life);
424dc5a79c1SDavid du Colombier 	return 1;
425dc5a79c1SDavid du Colombier }
426dc5a79c1SDavid du Colombier 
427dc5a79c1SDavid du Colombier static int
4285e96a66cSDavid du Colombier fsysSnapTime(Fsys* fsys, int argc, char* argv[])
4295e96a66cSDavid du Colombier {
430dc5a79c1SDavid du Colombier 	char buf[128], *x;
431dc5a79c1SDavid du Colombier 	int hh, mm, changed;
432dc5a79c1SDavid du Colombier 	u32int arch, snap, life;
433dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]";
4345e96a66cSDavid du Colombier 
435dc5a79c1SDavid du Colombier 	changed = 0;
436dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
4375e96a66cSDavid du Colombier 	ARGBEGIN{
4385e96a66cSDavid du Colombier 	case 'a':
439dc5a79c1SDavid du Colombier 		changed = 1;
4405e96a66cSDavid du Colombier 		x = ARGF();
4415e96a66cSDavid du Colombier 		if(x == nil)
4425e96a66cSDavid du Colombier 			return cliError(usage);
4435e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4445e96a66cSDavid du Colombier 			arch = ~(u32int)0;
4455e96a66cSDavid du Colombier 			break;
4465e96a66cSDavid du Colombier 		}
4475e96a66cSDavid du Colombier 		if(strlen(x) != 4 || strspn(x, "0123456789") != 4)
4485e96a66cSDavid du Colombier 			return cliError(usage);
4495e96a66cSDavid du Colombier 		hh = (x[0]-'0')*10 + x[1]-'0';
4505e96a66cSDavid du Colombier 		mm = (x[2]-'0')*10 + x[3]-'0';
4515e96a66cSDavid du Colombier 		if(hh >= 24 || mm >= 60)
4525e96a66cSDavid du Colombier 			return cliError(usage);
4535e96a66cSDavid du Colombier 		arch = hh*60+mm;
4545e96a66cSDavid du Colombier 		break;
4555e96a66cSDavid du Colombier 	case 's':
456dc5a79c1SDavid du Colombier 		changed = 1;
4575e96a66cSDavid du Colombier 		x = ARGF();
4585e96a66cSDavid du Colombier 		if(x == nil)
4595e96a66cSDavid du Colombier 			return cliError(usage);
4605e96a66cSDavid du Colombier 		if(strcmp(x, "none") == 0){
4615e96a66cSDavid du Colombier 			snap = ~(u32int)0;
4625e96a66cSDavid du Colombier 			break;
4635e96a66cSDavid du Colombier 		}
4645e96a66cSDavid du Colombier 		snap = atoi(x);
4655e96a66cSDavid du Colombier 		break;
466dc5a79c1SDavid du Colombier 	case 't':
467dc5a79c1SDavid du Colombier 		changed = 1;
468dc5a79c1SDavid du Colombier 		x = ARGF();
469dc5a79c1SDavid du Colombier 		if(x == nil)
470dc5a79c1SDavid du Colombier 			return cliError(usage);
471dc5a79c1SDavid du Colombier 		if(strcmp(x, "none") == 0){
472dc5a79c1SDavid du Colombier 			life = ~(u32int)0;
473dc5a79c1SDavid du Colombier 			break;
474dc5a79c1SDavid du Colombier 		}
475dc5a79c1SDavid du Colombier 		life = atoi(x);
476dc5a79c1SDavid du Colombier 		break;
4775e96a66cSDavid du Colombier 	default:
4785e96a66cSDavid du Colombier 		return cliError(usage);
4795e96a66cSDavid du Colombier 	}ARGEND
4805e96a66cSDavid du Colombier 	if(argc > 0)
4815e96a66cSDavid du Colombier 		return cliError(usage);
4825e96a66cSDavid du Colombier 
483dc5a79c1SDavid du Colombier 	if(changed){
484dc5a79c1SDavid du Colombier 		snapSetTimes(fsys->fs->snap, arch, snap, life);
485dc5a79c1SDavid du Colombier 		return 1;
486dc5a79c1SDavid du Colombier 	}
487dc5a79c1SDavid du Colombier 	snapGetTimes(fsys->fs->snap, &arch, &snap, &life);
4885e96a66cSDavid du Colombier 	if(arch != ~(u32int)0)
4895e96a66cSDavid du Colombier 		sprint(buf, "-a %02d%02d", arch/60, arch%60);
4905e96a66cSDavid du Colombier 	else
4915e96a66cSDavid du Colombier 		sprint(buf, "-a none");
4925e96a66cSDavid du Colombier 	if(snap != ~(u32int)0)
4935e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s %d", snap);
4945e96a66cSDavid du Colombier 	else
4955e96a66cSDavid du Colombier 		sprint(buf+strlen(buf), " -s none");
496dc5a79c1SDavid du Colombier 	if(life != ~(u32int)0)
497dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t %ud", life);
498dc5a79c1SDavid du Colombier 	else
499dc5a79c1SDavid du Colombier 		sprint(buf+strlen(buf), " -t none");
5005e96a66cSDavid du Colombier 	consPrint("\tsnaptime %s\n", buf);
5015e96a66cSDavid du Colombier 	return 1;
5025e96a66cSDavid du Colombier }
5035e96a66cSDavid du Colombier 
5045e96a66cSDavid du Colombier static int
5055e96a66cSDavid du Colombier fsysSync(Fsys* fsys, int argc, char* argv[])
5065e96a66cSDavid du Colombier {
5075e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] sync";
5080b9a5132SDavid du Colombier 	int n;
5095e96a66cSDavid du Colombier 
5105e96a66cSDavid du Colombier 	ARGBEGIN{
5115e96a66cSDavid du Colombier 	default:
5125e96a66cSDavid du Colombier 		return cliError(usage);
5135e96a66cSDavid du Colombier 	}ARGEND
5145e96a66cSDavid du Colombier 	if(argc > 0)
5155e96a66cSDavid du Colombier 		return cliError(usage);
5165e96a66cSDavid du Colombier 
5170b9a5132SDavid du Colombier 	n = cacheDirty(fsys->fs->cache);
5185e96a66cSDavid du Colombier 	fsSync(fsys->fs);
5190b9a5132SDavid du Colombier 	consPrint("\t%s sync: wrote %d blocks\n", fsys->name, n);
52081cf8742SDavid du Colombier 	return 1;
52181cf8742SDavid du Colombier }
5225e96a66cSDavid du Colombier 
52381cf8742SDavid du Colombier static int
52481cf8742SDavid du Colombier fsysHalt(Fsys *fsys, int argc, char* argv[])
52581cf8742SDavid du Colombier {
52681cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] halt";
52781cf8742SDavid du Colombier 
52881cf8742SDavid du Colombier 	ARGBEGIN{
52981cf8742SDavid du Colombier 	default:
53081cf8742SDavid du Colombier 		return cliError(usage);
53181cf8742SDavid du Colombier 	}ARGEND
53281cf8742SDavid du Colombier 	if(argc > 0)
53381cf8742SDavid du Colombier 		return cliError(usage);
53481cf8742SDavid du Colombier 
53581cf8742SDavid du Colombier 	fsHalt(fsys->fs);
53681cf8742SDavid du Colombier 	return 1;
53781cf8742SDavid du Colombier }
53881cf8742SDavid du Colombier 
53981cf8742SDavid du Colombier static int
54081cf8742SDavid du Colombier fsysUnhalt(Fsys *fsys, int argc, char* argv[])
54181cf8742SDavid du Colombier {
54281cf8742SDavid du Colombier 	char *usage = "usage: [fsys name] unhalt";
54381cf8742SDavid du Colombier 
54481cf8742SDavid du Colombier 	ARGBEGIN{
54581cf8742SDavid du Colombier 	default:
54681cf8742SDavid du Colombier 		return cliError(usage);
54781cf8742SDavid du Colombier 	}ARGEND
54881cf8742SDavid du Colombier 	if(argc > 0)
54981cf8742SDavid du Colombier 		return cliError(usage);
55081cf8742SDavid du Colombier 
55181cf8742SDavid du Colombier 	if(!fsys->fs->halted)
55281cf8742SDavid du Colombier 		return cliError("file system %s not halted", fsys->name);
55381cf8742SDavid du Colombier 
55481cf8742SDavid du Colombier 	fsUnhalt(fsys->fs);
5555e96a66cSDavid du Colombier 	return 1;
5565e96a66cSDavid du Colombier }
5575e96a66cSDavid du Colombier 
5585e96a66cSDavid du Colombier static int
5595e96a66cSDavid du Colombier fsysRemove(Fsys* fsys, int argc, char* argv[])
5605e96a66cSDavid du Colombier {
5615e96a66cSDavid du Colombier 	File *file;
5625e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] remove path ...";
5635e96a66cSDavid du Colombier 
5645e96a66cSDavid du Colombier 	ARGBEGIN{
5655e96a66cSDavid du Colombier 	default:
5665e96a66cSDavid du Colombier 		return cliError(usage);
5675e96a66cSDavid du Colombier 	}ARGEND
5685e96a66cSDavid du Colombier 	if(argc == 0)
5695e96a66cSDavid du Colombier 		return cliError(usage);
5705e96a66cSDavid du Colombier 
5715e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
5725e96a66cSDavid du Colombier 	while(argc > 0){
5735e96a66cSDavid du Colombier 		if((file = fileOpen(fsys->fs, argv[0])) == nil)
5745e96a66cSDavid du Colombier 			consPrint("%s: %R\n", argv[0]);
5755e96a66cSDavid du Colombier 		else{
5765e96a66cSDavid du Colombier 			if(!fileRemove(file, uidadm))
5775e96a66cSDavid du Colombier 				consPrint("%s: %R\n", argv[0]);
5785e96a66cSDavid du Colombier 			fileDecRef(file);
5795e96a66cSDavid du Colombier 		}
5805e96a66cSDavid du Colombier 		argc--;
5815e96a66cSDavid du Colombier 		argv++;
5825e96a66cSDavid du Colombier 	}
5835e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
5845e96a66cSDavid du Colombier 
5855e96a66cSDavid du Colombier 	return 1;
5865e96a66cSDavid du Colombier }
5875e96a66cSDavid du Colombier 
5885e96a66cSDavid du Colombier static int
5895e96a66cSDavid du Colombier fsysClri(Fsys* fsys, int argc, char* argv[])
5905e96a66cSDavid du Colombier {
5915e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clri path ...";
5925e96a66cSDavid du Colombier 
5935e96a66cSDavid du Colombier 	ARGBEGIN{
5945e96a66cSDavid du Colombier 	default:
5955e96a66cSDavid du Colombier 		return cliError(usage);
5965e96a66cSDavid du Colombier 	}ARGEND
5975e96a66cSDavid du Colombier 	if(argc == 0)
5985e96a66cSDavid du Colombier 		return cliError(usage);
5995e96a66cSDavid du Colombier 
6005e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
6015e96a66cSDavid du Colombier 	while(argc > 0){
602dc5a79c1SDavid du Colombier 		if(!fileClriPath(fsys->fs, argv[0], uidadm))
6035e96a66cSDavid du Colombier 			consPrint("clri %s: %R\n", argv[0]);
6045e96a66cSDavid du Colombier 		argc--;
6055e96a66cSDavid du Colombier 		argv++;
6065e96a66cSDavid du Colombier 	}
6075e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
6085e96a66cSDavid du Colombier 
6095e96a66cSDavid du Colombier 	return 1;
6105e96a66cSDavid du Colombier }
6115e96a66cSDavid du Colombier 
6125e96a66cSDavid du Colombier /*
6135e96a66cSDavid du Colombier  * Inspect and edit the labels for blocks on disk.
6145e96a66cSDavid du Colombier  */
6155e96a66cSDavid du Colombier static int
6165e96a66cSDavid du Colombier fsysLabel(Fsys* fsys, int argc, char* argv[])
6175e96a66cSDavid du Colombier {
6185e96a66cSDavid du Colombier 	Fs *fs;
6195e96a66cSDavid du Colombier 	Label l;
6205e96a66cSDavid du Colombier 	int n, r;
6215e96a66cSDavid du Colombier 	u32int addr;
6225e96a66cSDavid du Colombier 	Block *b, *bb;
6235e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]";
6245e96a66cSDavid du Colombier 
6255e96a66cSDavid du Colombier 	ARGBEGIN{
6265e96a66cSDavid du Colombier 	default:
6275e96a66cSDavid du Colombier 		return cliError(usage);
6285e96a66cSDavid du Colombier 	}ARGEND
6295e96a66cSDavid du Colombier 	if(argc != 1 && argc != 6)
6305e96a66cSDavid du Colombier 		return cliError(usage);
6315e96a66cSDavid du Colombier 
6325e96a66cSDavid du Colombier 	r = 0;
6335e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
6345e96a66cSDavid du Colombier 
6355e96a66cSDavid du Colombier 	fs = fsys->fs;
6365e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
6375e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
6385e96a66cSDavid du Colombier 	if(b == nil)
6395e96a66cSDavid du Colombier 		goto Out0;
6405e96a66cSDavid du Colombier 
6415e96a66cSDavid du Colombier 	l = b->l;
6425e96a66cSDavid du Colombier 	consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n",
6435e96a66cSDavid du Colombier 		argc==6 ? "old: " : "", addr, l.type, l.state,
6445e96a66cSDavid du Colombier 		l.epoch, l.epochClose, l.tag);
6455e96a66cSDavid du Colombier 
6465e96a66cSDavid du Colombier 	if(argc == 6){
6475e96a66cSDavid du Colombier 		if(strcmp(argv[1], "-") != 0)
6485e96a66cSDavid du Colombier 			l.type = atoi(argv[1]);
6495e96a66cSDavid du Colombier 		if(strcmp(argv[2], "-") != 0)
6505e96a66cSDavid du Colombier 			l.state = atoi(argv[2]);
6515e96a66cSDavid du Colombier 		if(strcmp(argv[3], "-") != 0)
6525e96a66cSDavid du Colombier 			l.epoch = strtoul(argv[3], 0, 0);
6535e96a66cSDavid du Colombier 		if(strcmp(argv[4], "-") != 0)
6545e96a66cSDavid du Colombier 			l.epochClose = strtoul(argv[4], 0, 0);
6555e96a66cSDavid du Colombier 		if(strcmp(argv[5], "-") != 0)
6565e96a66cSDavid du Colombier 			l.tag = strtoul(argv[5], 0, 0);
6575e96a66cSDavid du Colombier 
6585e96a66cSDavid du Colombier 		consPrint("new: label %#ux %ud %ud %ud %ud %#x\n",
6595e96a66cSDavid du Colombier 			addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
6605e96a66cSDavid du Colombier 		bb = _blockSetLabel(b, &l);
6615e96a66cSDavid du Colombier 		if(bb == nil)
6625e96a66cSDavid du Colombier 			goto Out1;
6635e96a66cSDavid du Colombier 		n = 0;
6645e96a66cSDavid du Colombier 		for(;;){
6655e96a66cSDavid du Colombier 			if(blockWrite(bb)){
6665e96a66cSDavid du Colombier 				while(bb->iostate != BioClean){
6675e96a66cSDavid du Colombier 					assert(bb->iostate == BioWriting);
6685e96a66cSDavid du Colombier 					vtSleep(bb->ioready);
6695e96a66cSDavid du Colombier 				}
6705e96a66cSDavid du Colombier 				break;
6715e96a66cSDavid du Colombier 			}
6725e96a66cSDavid du Colombier 			consPrint("blockWrite: %R\n");
6735e96a66cSDavid du Colombier 			if(n++ >= 5){
6745e96a66cSDavid du Colombier 				consPrint("giving up\n");
6755e96a66cSDavid du Colombier 				break;
6765e96a66cSDavid du Colombier 			}
6775e96a66cSDavid du Colombier 			sleep(5*1000);
6785e96a66cSDavid du Colombier 		}
6795e96a66cSDavid du Colombier 		blockPut(bb);
6805e96a66cSDavid du Colombier 	}
6815e96a66cSDavid du Colombier 	r = 1;
6825e96a66cSDavid du Colombier Out1:
6835e96a66cSDavid du Colombier 	blockPut(b);
6845e96a66cSDavid du Colombier Out0:
6855e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
6865e96a66cSDavid du Colombier 
6875e96a66cSDavid du Colombier 	return r;
6885e96a66cSDavid du Colombier }
6895e96a66cSDavid du Colombier 
6905e96a66cSDavid du Colombier /*
6915e96a66cSDavid du Colombier  * Inspect and edit the blocks on disk.
6925e96a66cSDavid du Colombier  */
6935e96a66cSDavid du Colombier static int
6945e96a66cSDavid du Colombier fsysBlock(Fsys* fsys, int argc, char* argv[])
6955e96a66cSDavid du Colombier {
6965e96a66cSDavid du Colombier 	Fs *fs;
6975e96a66cSDavid du Colombier 	char *s;
6985e96a66cSDavid du Colombier 	Block *b;
6995e96a66cSDavid du Colombier 	uchar *buf;
7005e96a66cSDavid du Colombier 	u32int addr;
7015e96a66cSDavid du Colombier 	int c, count, i, offset;
7025e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] block addr offset [count [data]]";
7035e96a66cSDavid du Colombier 
7045e96a66cSDavid du Colombier 	ARGBEGIN{
7055e96a66cSDavid du Colombier 	default:
7065e96a66cSDavid du Colombier 		return cliError(usage);
7075e96a66cSDavid du Colombier 	}ARGEND
7085e96a66cSDavid du Colombier 	if(argc < 2 || argc > 4)
7095e96a66cSDavid du Colombier 		return cliError(usage);
7105e96a66cSDavid du Colombier 
7115e96a66cSDavid du Colombier 	fs = fsys->fs;
7125e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
7135e96a66cSDavid du Colombier 	offset = strtoul(argv[1], 0, 0);
7145e96a66cSDavid du Colombier 	if(offset < 0 || offset >= fs->blockSize){
7155e96a66cSDavid du Colombier 		vtSetError("bad offset");
7165e96a66cSDavid du Colombier 		return 0;
7175e96a66cSDavid du Colombier 	}
7185e96a66cSDavid du Colombier 	if(argc > 2)
7195e96a66cSDavid du Colombier 		count = strtoul(argv[2], 0, 0);
7205e96a66cSDavid du Colombier 	else
7215e96a66cSDavid du Colombier 		count = 100000000;
7225e96a66cSDavid du Colombier 	if(offset+count > fs->blockSize)
7235e96a66cSDavid du Colombier 		count = fs->blockSize - count;
7245e96a66cSDavid du Colombier 
7255e96a66cSDavid du Colombier 	vtRLock(fs->elk);
7265e96a66cSDavid du Colombier 
7275e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
7285e96a66cSDavid du Colombier 	if(b == nil){
7295e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
7305e96a66cSDavid du Colombier 		vtRUnlock(fs->elk);
7315e96a66cSDavid du Colombier 		return 0;
7325e96a66cSDavid du Colombier 	}
7335e96a66cSDavid du Colombier 
7345e96a66cSDavid du Colombier 	consPrint("\t%sblock %#ux %ud %ud %.*H\n",
7355e96a66cSDavid du Colombier 		argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset);
7365e96a66cSDavid du Colombier 
7375e96a66cSDavid du Colombier 	if(argc == 4){
7385e96a66cSDavid du Colombier 		s = argv[3];
7395e96a66cSDavid du Colombier 		if(strlen(s) != 2*count){
7405e96a66cSDavid du Colombier 			vtSetError("bad data count");
7415e96a66cSDavid du Colombier 			goto Out;
7425e96a66cSDavid du Colombier 		}
7435e96a66cSDavid du Colombier 		buf = vtMemAllocZ(count);
7445e96a66cSDavid du Colombier 		for(i = 0; i < count*2; i++){
7455e96a66cSDavid du Colombier 			if(s[i] >= '0' && s[i] <= '9')
7465e96a66cSDavid du Colombier 				c = s[i] - '0';
7475e96a66cSDavid du Colombier 			else if(s[i] >= 'a' && s[i] <= 'f')
7485e96a66cSDavid du Colombier 				c = s[i] - 'a' + 10;
7495e96a66cSDavid du Colombier 			else if(s[i] >= 'A' && s[i] <= 'F')
7505e96a66cSDavid du Colombier 				c = s[i] - 'A' + 10;
7515e96a66cSDavid du Colombier 			else{
7525e96a66cSDavid du Colombier 				vtSetError("bad hex");
7535e96a66cSDavid du Colombier 				vtMemFree(buf);
7545e96a66cSDavid du Colombier 				goto Out;
7555e96a66cSDavid du Colombier 			}
7565e96a66cSDavid du Colombier 			if((i & 1) == 0)
7575e96a66cSDavid du Colombier 				c <<= 4;
7585e96a66cSDavid du Colombier 			buf[i>>1] |= c;
7595e96a66cSDavid du Colombier 		}
7605e96a66cSDavid du Colombier 		memmove(b->data+offset, buf, count);
7615e96a66cSDavid du Colombier 		consPrint("\tnew: block %#ux %ud %ud %.*H\n",
7625e96a66cSDavid du Colombier 			addr, offset, count, count, b->data+offset);
7635e96a66cSDavid du Colombier 		blockDirty(b);
7645e96a66cSDavid du Colombier 	}
7655e96a66cSDavid du Colombier 
7665e96a66cSDavid du Colombier Out:
7675e96a66cSDavid du Colombier 	blockPut(b);
7685e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
7695e96a66cSDavid du Colombier 
7705e96a66cSDavid du Colombier 	return 1;
7715e96a66cSDavid du Colombier }
7725e96a66cSDavid du Colombier 
7735e96a66cSDavid du Colombier /*
7745e96a66cSDavid du Colombier  * Free a disk block.
7755e96a66cSDavid du Colombier  */
7765e96a66cSDavid du Colombier static int
7775e96a66cSDavid du Colombier fsysBfree(Fsys* fsys, int argc, char* argv[])
7785e96a66cSDavid du Colombier {
7795e96a66cSDavid du Colombier 	Fs *fs;
7805e96a66cSDavid du Colombier 	Label l;
7815e96a66cSDavid du Colombier 	char *p;
7825e96a66cSDavid du Colombier 	Block *b;
7835e96a66cSDavid du Colombier 	u32int addr;
7845e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] bfree addr ...";
7855e96a66cSDavid du Colombier 
7865e96a66cSDavid du Colombier 	ARGBEGIN{
7875e96a66cSDavid du Colombier 	default:
7885e96a66cSDavid du Colombier 		return cliError(usage);
7895e96a66cSDavid du Colombier 	}ARGEND
7905e96a66cSDavid du Colombier 	if(argc == 0)
7915e96a66cSDavid du Colombier 		return cliError(usage);
7925e96a66cSDavid du Colombier 
7935e96a66cSDavid du Colombier 	fs = fsys->fs;
7945e96a66cSDavid du Colombier 	vtRLock(fs->elk);
7955e96a66cSDavid du Colombier 	while(argc > 0){
7965e96a66cSDavid du Colombier 		addr = strtoul(argv[0], &p, 0);
7975e96a66cSDavid du Colombier 		if(*p != '\0'){
7980c6300e7SDavid du Colombier 			consPrint("bad address - '%ud'\n", addr);
7995e96a66cSDavid du Colombier 			/* syntax error; let's stop */
8005e96a66cSDavid du Colombier 			vtRUnlock(fs->elk);
8015e96a66cSDavid du Colombier 			return 0;
8025e96a66cSDavid du Colombier 		}
8035e96a66cSDavid du Colombier 		b = cacheLocal(fs->cache, PartData, addr, OReadOnly);
8045e96a66cSDavid du Colombier 		if(b == nil){
8055e96a66cSDavid du Colombier 			consPrint("loading %#ux: %R\n", addr);
8065e96a66cSDavid du Colombier 			continue;
8075e96a66cSDavid du Colombier 		}
8085e96a66cSDavid du Colombier 		l = b->l;
809e569ccb5SDavid du Colombier 		if(l.state == BsFree)
810e569ccb5SDavid du Colombier 			consPrint("%#ux is already free\n", addr);
811e569ccb5SDavid du Colombier 		else{
8125e96a66cSDavid du Colombier 			consPrint("label %#ux %ud %ud %ud %ud %#x\n",
8135e96a66cSDavid du Colombier 				addr, l.type, l.state, l.epoch, l.epochClose, l.tag);
8145e96a66cSDavid du Colombier 			l.state = BsFree;
8155e96a66cSDavid du Colombier 			l.type = BtMax;
8165e96a66cSDavid du Colombier 			l.tag = 0;
8175e96a66cSDavid du Colombier 			l.epoch = 0;
8185e96a66cSDavid du Colombier 			l.epochClose = 0;
819e569ccb5SDavid du Colombier 			if(!blockSetLabel(b, &l, 0))
8205e96a66cSDavid du Colombier 				consPrint("freeing %#ux: %R\n", addr);
821e569ccb5SDavid du Colombier 		}
8225e96a66cSDavid du Colombier 		blockPut(b);
8235e96a66cSDavid du Colombier 		argc--;
8245e96a66cSDavid du Colombier 		argv++;
8255e96a66cSDavid du Colombier 	}
8265e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
8275e96a66cSDavid du Colombier 
8285e96a66cSDavid du Colombier 	return 1;
8295e96a66cSDavid du Colombier }
8305e96a66cSDavid du Colombier 
8317abd426fSDavid du Colombier static int
8327abd426fSDavid du Colombier fsysDf(Fsys *fsys, int argc, char* argv[])
8337abd426fSDavid du Colombier {
8347abd426fSDavid du Colombier 	char *usage = "usage: [fsys name] df";
8357abd426fSDavid du Colombier 	u32int used, tot, bsize;
8367abd426fSDavid du Colombier 	Fs *fs;
8377abd426fSDavid du Colombier 
8387abd426fSDavid du Colombier 	ARGBEGIN{
8397abd426fSDavid du Colombier 	default:
8407abd426fSDavid du Colombier 		return cliError(usage);
8417abd426fSDavid du Colombier 	}ARGEND
8427abd426fSDavid du Colombier 	if(argc != 0)
8437abd426fSDavid du Colombier 		return cliError(usage);
8447abd426fSDavid du Colombier 
8457abd426fSDavid du Colombier 	fs = fsys->fs;
8467abd426fSDavid du Colombier 	cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize);
8470c6300e7SDavid du Colombier 	consPrint("\t%s: %,llud used + %,llud free = %,llud (%llud%% used)\n",
848dc5a79c1SDavid du Colombier 		fsys->name, used*(vlong)bsize, (tot-used)*(vlong)bsize,
849208510e1SDavid du Colombier 		tot*(vlong)bsize, used*100LL/tot);
8507abd426fSDavid du Colombier 	return 1;
8517abd426fSDavid du Colombier }
8527abd426fSDavid du Colombier 
8535e96a66cSDavid du Colombier /*
8545e96a66cSDavid du Colombier  * Zero an entry or a pointer.
8555e96a66cSDavid du Colombier  */
8565e96a66cSDavid du Colombier static int
8575e96a66cSDavid du Colombier fsysClrep(Fsys* fsys, int argc, char* argv[], int ch)
8585e96a66cSDavid du Colombier {
8595e96a66cSDavid du Colombier 	Fs *fs;
8605e96a66cSDavid du Colombier 	Entry e;
8615e96a66cSDavid du Colombier 	Block *b;
8625e96a66cSDavid du Colombier 	u32int addr;
8635e96a66cSDavid du Colombier 	int i, max, offset, sz;
8645e96a66cSDavid du Colombier 	uchar zero[VtEntrySize];
8655e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] clr%c addr offset ...";
8665e96a66cSDavid du Colombier 
8675e96a66cSDavid du Colombier 	ARGBEGIN{
8685e96a66cSDavid du Colombier 	default:
8695e96a66cSDavid du Colombier 		return cliError(usage, ch);
8705e96a66cSDavid du Colombier 	}ARGEND
8715e96a66cSDavid du Colombier 	if(argc < 2)
8725e96a66cSDavid du Colombier 		return cliError(usage, ch);
8735e96a66cSDavid du Colombier 
8745e96a66cSDavid du Colombier 	fs = fsys->fs;
8755e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
8765e96a66cSDavid du Colombier 
8775e96a66cSDavid du Colombier 	addr = strtoul(argv[0], 0, 0);
8785e96a66cSDavid du Colombier 	b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly);
8795e96a66cSDavid du Colombier 	if(b == nil){
8805e96a66cSDavid du Colombier 		vtSetError("cacheLocal %#ux: %R", addr);
8815e96a66cSDavid du Colombier 	Err:
8825e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
8835e96a66cSDavid du Colombier 		return 0;
8845e96a66cSDavid du Colombier 	}
8855e96a66cSDavid du Colombier 
8865e96a66cSDavid du Colombier 	switch(ch){
8875e96a66cSDavid du Colombier 	default:
8885e96a66cSDavid du Colombier 		vtSetError("clrep");
8895e96a66cSDavid du Colombier 		goto Err;
8905e96a66cSDavid du Colombier 	case 'e':
8915e96a66cSDavid du Colombier 		if(b->l.type != BtDir){
8925e96a66cSDavid du Colombier 			vtSetError("wrong block type");
8935e96a66cSDavid du Colombier 			goto Err;
8945e96a66cSDavid du Colombier 		}
8955e96a66cSDavid du Colombier 		sz = VtEntrySize;
8965e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
8975e96a66cSDavid du Colombier 		entryPack(&e, zero, 0);
8985e96a66cSDavid du Colombier 		break;
8995e96a66cSDavid du Colombier 	case 'p':
9005e96a66cSDavid du Colombier 		if(b->l.type == BtDir || b->l.type == BtData){
9015e96a66cSDavid du Colombier 			vtSetError("wrong block type");
9025e96a66cSDavid du Colombier 			goto Err;
9035e96a66cSDavid du Colombier 		}
9045e96a66cSDavid du Colombier 		sz = VtScoreSize;
9055e96a66cSDavid du Colombier 		memmove(zero, vtZeroScore, VtScoreSize);
9065e96a66cSDavid du Colombier 		break;
9075e96a66cSDavid du Colombier 	}
9085e96a66cSDavid du Colombier 	max = fs->blockSize/sz;
9095e96a66cSDavid du Colombier 
9105e96a66cSDavid du Colombier 	for(i = 1; i < argc; i++){
9115e96a66cSDavid du Colombier 		offset = atoi(argv[i]);
9125e96a66cSDavid du Colombier 		if(offset >= max){
9135e96a66cSDavid du Colombier 			consPrint("\toffset %d too large (>= %d)\n", i, max);
9145e96a66cSDavid du Colombier 			continue;
9155e96a66cSDavid du Colombier 		}
9165e96a66cSDavid du Colombier 		consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz);
9175e96a66cSDavid du Colombier 		memmove(b->data+offset*sz, zero, sz);
9185e96a66cSDavid du Colombier 	}
9195e96a66cSDavid du Colombier 	blockDirty(b);
9205e96a66cSDavid du Colombier 	blockPut(b);
9215e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
9225e96a66cSDavid du Colombier 
9235e96a66cSDavid du Colombier 	return 1;
9245e96a66cSDavid du Colombier }
9255e96a66cSDavid du Colombier 
9265e96a66cSDavid du Colombier static int
9275e96a66cSDavid du Colombier fsysClre(Fsys* fsys, int argc, char* argv[])
9285e96a66cSDavid du Colombier {
9295e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'e');
9305e96a66cSDavid du Colombier }
9315e96a66cSDavid du Colombier 
9325e96a66cSDavid du Colombier static int
9335e96a66cSDavid du Colombier fsysClrp(Fsys* fsys, int argc, char* argv[])
9345e96a66cSDavid du Colombier {
9355e96a66cSDavid du Colombier 	return fsysClrep(fsys, argc, argv, 'p');
9365e96a66cSDavid du Colombier }
9375e96a66cSDavid du Colombier 
9385e96a66cSDavid du Colombier static int
9395e96a66cSDavid du Colombier fsysEsearch1(File* f, char* s, u32int elo)
9405e96a66cSDavid du Colombier {
9415e96a66cSDavid du Colombier 	int n, r;
9425e96a66cSDavid du Colombier 	DirEntry de;
9435e96a66cSDavid du Colombier 	DirEntryEnum *dee;
9445e96a66cSDavid du Colombier 	File *ff;
9455e96a66cSDavid du Colombier 	Entry e, ee;
9465e96a66cSDavid du Colombier 	char *t;
9475e96a66cSDavid du Colombier 
9485e96a66cSDavid du Colombier 	dee = deeOpen(f);
9495e96a66cSDavid du Colombier 	if(dee == nil)
9505e96a66cSDavid du Colombier 		return 0;
9515e96a66cSDavid du Colombier 
9525e96a66cSDavid du Colombier 	n = 0;
9535e96a66cSDavid du Colombier 	for(;;){
9545e96a66cSDavid du Colombier 		r = deeRead(dee, &de);
9555e96a66cSDavid du Colombier 		if(r < 0){
9565e96a66cSDavid du Colombier 			consPrint("\tdeeRead %s/%s: %R\n", s, de.elem);
9575e96a66cSDavid du Colombier 			break;
9585e96a66cSDavid du Colombier 		}
9595e96a66cSDavid du Colombier 		if(r == 0)
9605e96a66cSDavid du Colombier 			break;
9615e96a66cSDavid du Colombier 		if(de.mode & ModeSnapshot){
9625e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
9635e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
9645e96a66cSDavid du Colombier 			else{
965e569ccb5SDavid du Colombier 				if(!fileGetSources(ff, &e, &ee))
9665e96a66cSDavid du Colombier 					consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem);
9675e96a66cSDavid du Colombier 				else if(e.snap != 0 && e.snap < elo){
9685e96a66cSDavid du Colombier 					consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem);
9695e96a66cSDavid du Colombier 					n++;
9705e96a66cSDavid du Colombier 				}
9715e96a66cSDavid du Colombier 				fileDecRef(ff);
9725e96a66cSDavid du Colombier 			}
9735e96a66cSDavid du Colombier 		}
9745e96a66cSDavid du Colombier 		else if(de.mode & ModeDir){
9755e96a66cSDavid du Colombier 			if((ff = fileWalk(f, de.elem)) == nil)
9765e96a66cSDavid du Colombier 				consPrint("\tcannot walk %s/%s: %R\n", s, de.elem);
9775e96a66cSDavid du Colombier 			else{
978f8e525acSDavid du Colombier 				t = smprint("%s/%s", s, de.elem);
9795e96a66cSDavid du Colombier 				n += fsysEsearch1(ff, t, elo);
9805e96a66cSDavid du Colombier 				vtMemFree(t);
9815e96a66cSDavid du Colombier 				fileDecRef(ff);
9825e96a66cSDavid du Colombier 			}
9835e96a66cSDavid du Colombier 		}
9845e96a66cSDavid du Colombier 		deCleanup(&de);
9855e96a66cSDavid du Colombier 		if(r < 0)
9865e96a66cSDavid du Colombier 			break;
9875e96a66cSDavid du Colombier 	}
9885e96a66cSDavid du Colombier 	deeClose(dee);
9895e96a66cSDavid du Colombier 
9905e96a66cSDavid du Colombier 	return n;
9915e96a66cSDavid du Colombier }
9925e96a66cSDavid du Colombier 
9935e96a66cSDavid du Colombier static int
9945e96a66cSDavid du Colombier fsysEsearch(Fs* fs, char* path, u32int elo)
9955e96a66cSDavid du Colombier {
9965e96a66cSDavid du Colombier 	int n;
9975e96a66cSDavid du Colombier 	File *f;
9985e96a66cSDavid du Colombier 	DirEntry de;
9995e96a66cSDavid du Colombier 
10005e96a66cSDavid du Colombier 	f = fileOpen(fs, path);
10015e96a66cSDavid du Colombier 	if(f == nil)
10025e96a66cSDavid du Colombier 		return 0;
10035e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
10045e96a66cSDavid du Colombier 		consPrint("\tfileGetDir %s failed: %R\n", path);
10055e96a66cSDavid du Colombier 		fileDecRef(f);
10065e96a66cSDavid du Colombier 		return 0;
10075e96a66cSDavid du Colombier 	}
10085e96a66cSDavid du Colombier 	if((de.mode & ModeDir) == 0){
10095e96a66cSDavid du Colombier 		fileDecRef(f);
10105e96a66cSDavid du Colombier 		deCleanup(&de);
10115e96a66cSDavid du Colombier 		return 0;
10125e96a66cSDavid du Colombier 	}
10135e96a66cSDavid du Colombier 	deCleanup(&de);
10145e96a66cSDavid du Colombier 	n = fsysEsearch1(f, path, elo);
10155e96a66cSDavid du Colombier 	fileDecRef(f);
10165e96a66cSDavid du Colombier 	return n;
10175e96a66cSDavid du Colombier }
10185e96a66cSDavid du Colombier 
10195e96a66cSDavid du Colombier static int
10205e96a66cSDavid du Colombier fsysEpoch(Fsys* fsys, int argc, char* argv[])
10215e96a66cSDavid du Colombier {
10225e96a66cSDavid du Colombier 	Fs *fs;
1023dc5a79c1SDavid du Colombier 	int force, n, remove;
10245e96a66cSDavid du Colombier 	u32int low, old;
1025dc5a79c1SDavid du Colombier 	char *usage = "usage: [fsys name] epoch [[-ry] low]";
10265e96a66cSDavid du Colombier 
10275e96a66cSDavid du Colombier 	force = 0;
1028dc5a79c1SDavid du Colombier 	remove = 0;
10295e96a66cSDavid du Colombier 	ARGBEGIN{
10305e96a66cSDavid du Colombier 	case 'y':
10315e96a66cSDavid du Colombier 		force = 1;
10325e96a66cSDavid du Colombier 		break;
1033dc5a79c1SDavid du Colombier 	case 'r':
1034dc5a79c1SDavid du Colombier 		remove = 1;
1035dc5a79c1SDavid du Colombier 		break;
10365e96a66cSDavid du Colombier 	default:
10375e96a66cSDavid du Colombier 		return cliError(usage);
10385e96a66cSDavid du Colombier 	}ARGEND
10395e96a66cSDavid du Colombier 	if(argc > 1)
10405e96a66cSDavid du Colombier 		return cliError(usage);
10415e96a66cSDavid du Colombier 	if(argc > 0)
10425e96a66cSDavid du Colombier 		low = strtoul(argv[0], 0, 0);
10435e96a66cSDavid du Colombier 	else
10445e96a66cSDavid du Colombier 		low = ~(u32int)0;
10455e96a66cSDavid du Colombier 
10468a2c5ad0SDavid du Colombier 	if(low == 0)
10478a2c5ad0SDavid du Colombier 		return cliError("low epoch cannot be zero");
10488a2c5ad0SDavid du Colombier 
10495e96a66cSDavid du Colombier 	fs = fsys->fs;
10505e96a66cSDavid du Colombier 
10515e96a66cSDavid du Colombier 	vtRLock(fs->elk);
10525e96a66cSDavid du Colombier 	consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi);
105357195852SDavid du Colombier 	if(low == ~(u32int)0){
105457195852SDavid du Colombier 		vtRUnlock(fs->elk);
105557195852SDavid du Colombier 		return 1;
105657195852SDavid du Colombier 	}
10575e96a66cSDavid du Colombier 	n = fsysEsearch(fsys->fs, "/archive", low);
10585e96a66cSDavid du Colombier 	n += fsysEsearch(fsys->fs, "/snapshot", low);
10595e96a66cSDavid du Colombier 	consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low);
10605e96a66cSDavid du Colombier 	vtRUnlock(fs->elk);
10615e96a66cSDavid du Colombier 
10625e96a66cSDavid du Colombier 	/*
10635e96a66cSDavid du Colombier 	 * There's a small race here -- a new snapshot with epoch < low might
10645e96a66cSDavid du Colombier 	 * get introduced now that we unlocked fs->elk.  Low has to
10655e96a66cSDavid du Colombier 	 * be <= fs->ehi.  Of course, in order for this to happen low has
10665e96a66cSDavid du Colombier 	 * to be equal to the current fs->ehi _and_ a snapshot has to
10675e96a66cSDavid du Colombier 	 * run right now.  This is a small enough window that I don't care.
10685e96a66cSDavid du Colombier 	 */
10695e96a66cSDavid du Colombier 	if(n != 0 && !force){
10705e96a66cSDavid du Colombier 		consPrint("\tnot setting low epoch\n");
10715e96a66cSDavid du Colombier 		return 1;
10725e96a66cSDavid du Colombier 	}
10735e96a66cSDavid du Colombier 	old = fs->elo;
10745e96a66cSDavid du Colombier 	if(!fsEpochLow(fs, low))
10755e96a66cSDavid du Colombier 		consPrint("\tfsEpochLow: %R\n");
10765e96a66cSDavid du Colombier 	else{
10775e96a66cSDavid du Colombier 		consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old);
10785e96a66cSDavid du Colombier 		consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo);
10795e96a66cSDavid du Colombier 		if(fs->elo < low)
10805e96a66cSDavid du Colombier 			consPrint("\twarning: new low epoch < old low epoch\n");
1081dc5a79c1SDavid du Colombier 		if(force && remove)
1082dc5a79c1SDavid du Colombier 			fsSnapshotRemove(fs);
10835e96a66cSDavid du Colombier 	}
10845e96a66cSDavid du Colombier 
10855e96a66cSDavid du Colombier 	return 1;
10865e96a66cSDavid du Colombier }
10875e96a66cSDavid du Colombier 
10885e96a66cSDavid du Colombier static int
10895e96a66cSDavid du Colombier fsysCreate(Fsys* fsys, int argc, char* argv[])
10905e96a66cSDavid du Colombier {
10915e96a66cSDavid du Colombier 	int r;
10925e96a66cSDavid du Colombier 	ulong mode;
10935e96a66cSDavid du Colombier 	char *elem, *p, *path;
10945e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] create path uid gid perm";
10955e96a66cSDavid du Colombier 	DirEntry de;
10965e96a66cSDavid du Colombier 	File *file, *parent;
10975e96a66cSDavid du Colombier 
10985e96a66cSDavid du Colombier 	ARGBEGIN{
10995e96a66cSDavid du Colombier 	default:
11005e96a66cSDavid du Colombier 		return cliError(usage);
11015e96a66cSDavid du Colombier 	}ARGEND
11025e96a66cSDavid du Colombier 	if(argc != 4)
11035e96a66cSDavid du Colombier 		return cliError(usage);
11045e96a66cSDavid du Colombier 
11055e96a66cSDavid du Colombier 	if(!fsysParseMode(argv[3], &mode))
11065e96a66cSDavid du Colombier 		return cliError(usage);
11075e96a66cSDavid du Colombier 	if(mode&ModeSnapshot)
11085e96a66cSDavid du Colombier 		return cliError("create - cannot create with snapshot bit set");
11095e96a66cSDavid du Colombier 
11105e96a66cSDavid du Colombier 	if(strcmp(argv[1], uidnoworld) == 0)
11115e96a66cSDavid du Colombier 		return cliError("permission denied");
11125e96a66cSDavid du Colombier 
11135e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
11145e96a66cSDavid du Colombier 	path = vtStrDup(argv[0]);
11155e96a66cSDavid du Colombier 	if((p = strrchr(path, '/')) != nil){
11165e96a66cSDavid du Colombier 		*p++ = '\0';
11175e96a66cSDavid du Colombier 		elem = p;
11185e96a66cSDavid du Colombier 		p = path;
11195e96a66cSDavid du Colombier 		if(*p == '\0')
11205e96a66cSDavid du Colombier 			p = "/";
11215e96a66cSDavid du Colombier 	}
11225e96a66cSDavid du Colombier 	else{
11235e96a66cSDavid du Colombier 		p = "/";
11245e96a66cSDavid du Colombier 		elem = path;
11255e96a66cSDavid du Colombier 	}
1126f8e525acSDavid du Colombier 
11275e96a66cSDavid du Colombier 	r = 0;
1128f8e525acSDavid du Colombier 	if((parent = fileOpen(fsys->fs, p)) == nil)
1129f8e525acSDavid du Colombier 		goto out;
1130f8e525acSDavid du Colombier 
11315e96a66cSDavid du Colombier 	file = fileCreate(parent, elem, mode, argv[1]);
11325e96a66cSDavid du Colombier 	fileDecRef(parent);
1133f8e525acSDavid du Colombier 	if(file == nil){
1134f8e525acSDavid du Colombier 		vtSetError("create %s/%s: %R", p, elem);
1135f8e525acSDavid du Colombier 		goto out;
1136f8e525acSDavid du Colombier 	}
1137f8e525acSDavid du Colombier 
1138f8e525acSDavid du Colombier 	if(!fileGetDir(file, &de)){
1139f8e525acSDavid du Colombier 		vtSetError("stat failed after create: %R");
1140f8e525acSDavid du Colombier 		goto out1;
1141f8e525acSDavid du Colombier 	}
1142f8e525acSDavid du Colombier 
11435e96a66cSDavid du Colombier 	if(strcmp(de.gid, argv[2]) != 0){
11445e96a66cSDavid du Colombier 		vtMemFree(de.gid);
11455e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[2]);
1146f8e525acSDavid du Colombier 		if(!fileSetDir(file, &de, argv[1])){
1147f8e525acSDavid du Colombier 			vtSetError("wstat failed after create: %R");
1148f8e525acSDavid du Colombier 			goto out2;
11495e96a66cSDavid du Colombier 		}
1150f8e525acSDavid du Colombier 	}
1151f8e525acSDavid du Colombier 	r = 1;
1152f8e525acSDavid du Colombier 
1153f8e525acSDavid du Colombier out2:
11545e96a66cSDavid du Colombier 	deCleanup(&de);
1155f8e525acSDavid du Colombier out1:
11565e96a66cSDavid du Colombier 	fileDecRef(file);
1157f8e525acSDavid du Colombier out:
11585e96a66cSDavid du Colombier 	vtMemFree(path);
11595e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
11605e96a66cSDavid du Colombier 
11615e96a66cSDavid du Colombier 	return r;
11625e96a66cSDavid du Colombier }
11635e96a66cSDavid du Colombier 
11645e96a66cSDavid du Colombier static void
11655e96a66cSDavid du Colombier fsysPrintStat(char *prefix, char *file, DirEntry *de)
11665e96a66cSDavid du Colombier {
11675e96a66cSDavid du Colombier 	char buf[64];
11685e96a66cSDavid du Colombier 
11695e96a66cSDavid du Colombier 	if(prefix == nil)
11705e96a66cSDavid du Colombier 		prefix = "";
11715e96a66cSDavid du Colombier 	consPrint("%sstat %q %q %q %q %s %llud\n", prefix,
11725e96a66cSDavid du Colombier 		file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size);
11735e96a66cSDavid du Colombier }
11745e96a66cSDavid du Colombier 
11755e96a66cSDavid du Colombier static int
11765e96a66cSDavid du Colombier fsysStat(Fsys* fsys, int argc, char* argv[])
11775e96a66cSDavid du Colombier {
11785e96a66cSDavid du Colombier 	int i;
11795e96a66cSDavid du Colombier 	File *f;
11805e96a66cSDavid du Colombier 	DirEntry de;
11815e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] stat files...";
11825e96a66cSDavid du Colombier 
11835e96a66cSDavid du Colombier 	ARGBEGIN{
11845e96a66cSDavid du Colombier 	default:
11855e96a66cSDavid du Colombier 		return cliError(usage);
11865e96a66cSDavid du Colombier 	}ARGEND
11875e96a66cSDavid du Colombier 
11885e96a66cSDavid du Colombier 	if(argc == 0)
11895e96a66cSDavid du Colombier 		return cliError(usage);
11905e96a66cSDavid du Colombier 
11915e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
11925e96a66cSDavid du Colombier 	for(i=0; i<argc; i++){
11935e96a66cSDavid du Colombier 		if((f = fileOpen(fsys->fs, argv[i])) == nil){
11940c6300e7SDavid du Colombier 			consPrint("%s: %R\n", argv[i]);
11955e96a66cSDavid du Colombier 			continue;
11965e96a66cSDavid du Colombier 		}
11975e96a66cSDavid du Colombier 		if(!fileGetDir(f, &de)){
11980c6300e7SDavid du Colombier 			consPrint("%s: %R\n", argv[i]);
11995e96a66cSDavid du Colombier 			fileDecRef(f);
12005e96a66cSDavid du Colombier 			continue;
12015e96a66cSDavid du Colombier 		}
12025e96a66cSDavid du Colombier 		fsysPrintStat("\t", argv[i], &de);
12035e96a66cSDavid du Colombier 		deCleanup(&de);
12045e96a66cSDavid du Colombier 		fileDecRef(f);
12055e96a66cSDavid du Colombier 	}
12065e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
12075e96a66cSDavid du Colombier 	return 1;
12085e96a66cSDavid du Colombier }
12095e96a66cSDavid du Colombier 
12105e96a66cSDavid du Colombier static int
12115e96a66cSDavid du Colombier fsysWstat(Fsys *fsys, int argc, char* argv[])
12125e96a66cSDavid du Colombier {
12135e96a66cSDavid du Colombier 	File *f;
12145e96a66cSDavid du Colombier 	char *p;
12155e96a66cSDavid du Colombier 	DirEntry de;
12165e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n"
12175e96a66cSDavid du Colombier 		"\tuse - for any field to mean don't change";
12185e96a66cSDavid du Colombier 
12195e96a66cSDavid du Colombier 	ARGBEGIN{
12205e96a66cSDavid du Colombier 	default:
12215e96a66cSDavid du Colombier 		return cliError(usage);
12225e96a66cSDavid du Colombier 	}ARGEND
12235e96a66cSDavid du Colombier 
12245e96a66cSDavid du Colombier 	if(argc != 6)
12255e96a66cSDavid du Colombier 		return cliError(usage);
12265e96a66cSDavid du Colombier 
12275e96a66cSDavid du Colombier 	vtRLock(fsys->fs->elk);
12285e96a66cSDavid du Colombier 	if((f = fileOpen(fsys->fs, argv[0])) == nil){
12295e96a66cSDavid du Colombier 		vtSetError("console wstat - walk - %R");
12305e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
12315e96a66cSDavid du Colombier 		return 0;
12325e96a66cSDavid du Colombier 	}
12335e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
12345e96a66cSDavid du Colombier 		vtSetError("console wstat - stat - %R");
12355e96a66cSDavid du Colombier 		fileDecRef(f);
12365e96a66cSDavid du Colombier 		vtRUnlock(fsys->fs->elk);
12375e96a66cSDavid du Colombier 		return 0;
12385e96a66cSDavid du Colombier 	}
12395e96a66cSDavid du Colombier 	fsysPrintStat("\told: w", argv[0], &de);
12405e96a66cSDavid du Colombier 
12415e96a66cSDavid du Colombier 	if(strcmp(argv[1], "-") != 0){
12425e96a66cSDavid du Colombier 		if(!validFileName(argv[1])){
12435e96a66cSDavid du Colombier 			vtSetError("console wstat - bad elem");
12445e96a66cSDavid du Colombier 			goto error;
12455e96a66cSDavid du Colombier 		}
12465e96a66cSDavid du Colombier 		vtMemFree(de.elem);
12475e96a66cSDavid du Colombier 		de.elem = vtStrDup(argv[1]);
12485e96a66cSDavid du Colombier 	}
12495e96a66cSDavid du Colombier 	if(strcmp(argv[2], "-") != 0){
12505e96a66cSDavid du Colombier 		if(!validUserName(argv[2])){
12515e96a66cSDavid du Colombier 			vtSetError("console wstat - bad uid");
12525e96a66cSDavid du Colombier 			goto error;
12535e96a66cSDavid du Colombier 		}
12545e96a66cSDavid du Colombier 		vtMemFree(de.uid);
12555e96a66cSDavid du Colombier 		de.uid = vtStrDup(argv[2]);
12565e96a66cSDavid du Colombier 	}
12575e96a66cSDavid du Colombier 	if(strcmp(argv[3], "-") != 0){
12585e96a66cSDavid du Colombier 		if(!validUserName(argv[3])){
12595e96a66cSDavid du Colombier 			vtSetError("console wstat - bad gid");
12605e96a66cSDavid du Colombier 			goto error;
12615e96a66cSDavid du Colombier 		}
12625e96a66cSDavid du Colombier 		vtMemFree(de.gid);
12635e96a66cSDavid du Colombier 		de.gid = vtStrDup(argv[3]);
12645e96a66cSDavid du Colombier 	}
12655e96a66cSDavid du Colombier 	if(strcmp(argv[4], "-") != 0){
12665e96a66cSDavid du Colombier 		if(!fsysParseMode(argv[4], &de.mode)){
12675e96a66cSDavid du Colombier 			vtSetError("console wstat - bad mode");
12685e96a66cSDavid du Colombier 			goto error;
12695e96a66cSDavid du Colombier 		}
12705e96a66cSDavid du Colombier 	}
12715e96a66cSDavid du Colombier 	if(strcmp(argv[5], "-") != 0){
12725e96a66cSDavid du Colombier 		de.size = strtoull(argv[5], &p, 0);
127322a127bbSDavid du Colombier 		if(argv[5][0] == '\0' || *p != '\0' || (vlong)de.size < 0){
12745e96a66cSDavid du Colombier 			vtSetError("console wstat - bad length");
12755e96a66cSDavid du Colombier 			goto error;
12765e96a66cSDavid du Colombier 		}
12775e96a66cSDavid du Colombier 	}
12785e96a66cSDavid du Colombier 
12795e96a66cSDavid du Colombier 	if(!fileSetDir(f, &de, uidadm)){
12805e96a66cSDavid du Colombier 		vtSetError("console wstat - %R");
12815e96a66cSDavid du Colombier 		goto error;
12825e96a66cSDavid du Colombier 	}
12835e96a66cSDavid du Colombier 	deCleanup(&de);
12845e96a66cSDavid du Colombier 
12855e96a66cSDavid du Colombier 	if(!fileGetDir(f, &de)){
12865e96a66cSDavid du Colombier 		vtSetError("console wstat - stat2 - %R");
12875e96a66cSDavid du Colombier 		goto error;
12885e96a66cSDavid du Colombier 	}
12895e96a66cSDavid du Colombier 	fsysPrintStat("\tnew: w", argv[0], &de);
12905e96a66cSDavid du Colombier 	deCleanup(&de);
12915e96a66cSDavid du Colombier 	fileDecRef(f);
12925e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
12935e96a66cSDavid du Colombier 
12945e96a66cSDavid du Colombier 	return 1;
12955e96a66cSDavid du Colombier 
12965e96a66cSDavid du Colombier error:
12975e96a66cSDavid du Colombier 	deCleanup(&de);	/* okay to do this twice */
12985e96a66cSDavid du Colombier 	fileDecRef(f);
12995e96a66cSDavid du Colombier 	vtRUnlock(fsys->fs->elk);
13005e96a66cSDavid du Colombier 	return 0;
13015e96a66cSDavid du Colombier }
13025e96a66cSDavid du Colombier 
1303e569ccb5SDavid du Colombier static void
1304e569ccb5SDavid du Colombier fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b)
1305e569ccb5SDavid du Colombier {
1306e569ccb5SDavid du Colombier 	USED(name);
1307e569ccb5SDavid du Colombier 
1308e569ccb5SDavid du Colombier 	if((fsck->flags&DoClri) == 0)
1309e569ccb5SDavid du Colombier 		return;
1310e569ccb5SDavid du Colombier 
1311e569ccb5SDavid du Colombier 	mbDelete(mb, i);
1312e569ccb5SDavid du Colombier 	mbPack(mb);
1313e569ccb5SDavid du Colombier 	blockDirty(b);
1314e569ccb5SDavid du Colombier }
1315e569ccb5SDavid du Colombier 
1316e569ccb5SDavid du Colombier static void
1317e569ccb5SDavid du Colombier fsckClose(Fsck *fsck, Block *b, u32int epoch)
1318e569ccb5SDavid du Colombier {
1319e569ccb5SDavid du Colombier 	Label l;
1320e569ccb5SDavid du Colombier 
1321e569ccb5SDavid du Colombier 	if((fsck->flags&DoClose) == 0)
1322e569ccb5SDavid du Colombier 		return;
1323e569ccb5SDavid du Colombier 	l = b->l;
1324e569ccb5SDavid du Colombier 	if(l.state == BsFree || (l.state&BsClosed)){
1325e569ccb5SDavid du Colombier 		consPrint("%#ux is already closed\n", b->addr);
1326e569ccb5SDavid du Colombier 		return;
1327e569ccb5SDavid du Colombier 	}
1328e569ccb5SDavid du Colombier 	if(epoch){
1329e569ccb5SDavid du Colombier 		l.state |= BsClosed;
1330e569ccb5SDavid du Colombier 		l.epochClose = epoch;
1331e569ccb5SDavid du Colombier 	}else
1332e569ccb5SDavid du Colombier 		l.state = BsFree;
1333e569ccb5SDavid du Colombier 
1334e569ccb5SDavid du Colombier 	if(!blockSetLabel(b, &l, 0))
1335e569ccb5SDavid du Colombier 		consPrint("%#ux setlabel: %R\n", b->addr);
1336e569ccb5SDavid du Colombier }
1337e569ccb5SDavid du Colombier 
1338e569ccb5SDavid du Colombier static void
1339e569ccb5SDavid du Colombier fsckClre(Fsck *fsck, Block *b, int offset)
1340e569ccb5SDavid du Colombier {
1341e569ccb5SDavid du Colombier 	Entry e;
1342e569ccb5SDavid du Colombier 
1343e569ccb5SDavid du Colombier 	if((fsck->flags&DoClre) == 0)
1344e569ccb5SDavid du Colombier 		return;
1345e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtEntrySize >= fsck->bsize){
1346e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1347e569ccb5SDavid du Colombier 		return;
1348e569ccb5SDavid du Colombier 	}
1349e569ccb5SDavid du Colombier 	memset(&e, 0, sizeof e);
1350e569ccb5SDavid du Colombier 	entryPack(&e, b->data, offset);
1351e569ccb5SDavid du Colombier 	blockDirty(b);
1352e569ccb5SDavid du Colombier }
1353e569ccb5SDavid du Colombier 
1354e569ccb5SDavid du Colombier static void
1355e569ccb5SDavid du Colombier fsckClrp(Fsck *fsck, Block *b, int offset)
1356e569ccb5SDavid du Colombier {
1357e569ccb5SDavid du Colombier 	if((fsck->flags&DoClrp) == 0)
1358e569ccb5SDavid du Colombier 		return;
1359e569ccb5SDavid du Colombier 	if(offset<0 || offset*VtScoreSize >= fsck->bsize){
1360e569ccb5SDavid du Colombier 		consPrint("bad clre\n");
1361e569ccb5SDavid du Colombier 		return;
1362e569ccb5SDavid du Colombier 	}
1363e569ccb5SDavid du Colombier 	memmove(b->data+offset*VtScoreSize, vtZeroScore, VtScoreSize);
1364e569ccb5SDavid du Colombier 	blockDirty(b);
1365e569ccb5SDavid du Colombier }
1366e569ccb5SDavid du Colombier 
1367e569ccb5SDavid du Colombier static int
1368e569ccb5SDavid du Colombier fsysCheck(Fsys *fsys, int argc, char *argv[])
1369e569ccb5SDavid du Colombier {
1370e569ccb5SDavid du Colombier 	int i, halting;
1371e569ccb5SDavid du Colombier 	char *usage = "usage: [fsys name] check [-v] [options]";
1372e569ccb5SDavid du Colombier 	Fsck fsck;
1373e569ccb5SDavid du Colombier 	Block *b;
1374e569ccb5SDavid du Colombier 	Super super;
1375e569ccb5SDavid du Colombier 
1376e569ccb5SDavid du Colombier 	memset(&fsck, 0, sizeof fsck);
1377e569ccb5SDavid du Colombier 	fsck.fs = fsys->fs;
1378e569ccb5SDavid du Colombier 	fsck.clri = fsckClri;
1379e569ccb5SDavid du Colombier 	fsck.clre = fsckClre;
1380e569ccb5SDavid du Colombier 	fsck.clrp = fsckClrp;
1381e569ccb5SDavid du Colombier 	fsck.close = fsckClose;
1382e569ccb5SDavid du Colombier 	fsck.print = consPrint;
1383e569ccb5SDavid du Colombier 
1384e569ccb5SDavid du Colombier 	ARGBEGIN{
1385e569ccb5SDavid du Colombier 	default:
1386e569ccb5SDavid du Colombier 		return cliError(usage);
1387e569ccb5SDavid du Colombier 	}ARGEND
1388e569ccb5SDavid du Colombier 
1389e569ccb5SDavid du Colombier 	for(i=0; i<argc; i++){
1390e569ccb5SDavid du Colombier 		if(strcmp(argv[i], "pblock") == 0)
1391e569ccb5SDavid du Colombier 			fsck.printblocks = 1;
1392e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pdir") == 0)
1393e569ccb5SDavid du Colombier 			fsck.printdirs = 1;
1394e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "pfile") == 0)
1395e569ccb5SDavid du Colombier 			fsck.printfiles = 1;
1396e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "bclose") == 0)
1397e569ccb5SDavid du Colombier 			fsck.flags |= DoClose;
1398e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clri") == 0)
1399e569ccb5SDavid du Colombier 			fsck.flags |= DoClri;
1400e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clre") == 0)
1401e569ccb5SDavid du Colombier 			fsck.flags |= DoClre;
1402e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "clrp") == 0)
1403e569ccb5SDavid du Colombier 			fsck.flags |= DoClrp;
1404e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "fix") == 0)
1405e569ccb5SDavid du Colombier 			fsck.flags |= DoClose|DoClri|DoClre|DoClrp;
1406e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "venti") == 0)
1407e569ccb5SDavid du Colombier 			fsck.useventi = 1;
1408e569ccb5SDavid du Colombier 		else if(strcmp(argv[i], "snapshot") == 0)
1409e569ccb5SDavid du Colombier 			fsck.walksnapshots = 1;
1410e569ccb5SDavid du Colombier 		else{
1411e569ccb5SDavid du Colombier 			consPrint("unknown option '%s'\n", argv[i]);
1412e569ccb5SDavid du Colombier 			return cliError(usage);
1413e569ccb5SDavid du Colombier 		}
1414e569ccb5SDavid du Colombier 	}
1415e569ccb5SDavid du Colombier 
1416e569ccb5SDavid du Colombier 	halting = fsys->fs->halted==0;
1417e569ccb5SDavid du Colombier 	if(halting)
1418e569ccb5SDavid du Colombier 		fsHalt(fsys->fs);
1419e569ccb5SDavid du Colombier 	if(fsys->fs->arch){
1420e569ccb5SDavid du Colombier 		b = superGet(fsys->fs->cache, &super);
1421e569ccb5SDavid du Colombier 		if(b == nil){
1422e569ccb5SDavid du Colombier 			consPrint("could not load super block\n");
1423e569ccb5SDavid du Colombier 			goto Out;
1424e569ccb5SDavid du Colombier 		}
1425e569ccb5SDavid du Colombier 		blockPut(b);
1426e569ccb5SDavid du Colombier 		if(super.current != NilBlock){
1427225077b0SDavid du Colombier 			consPrint("cannot check fs while archiver is running; "
1428225077b0SDavid du Colombier 				"wait for it to finish\n");
1429e569ccb5SDavid du Colombier 			goto Out;
1430e569ccb5SDavid du Colombier 		}
1431e569ccb5SDavid du Colombier 	}
1432e569ccb5SDavid du Colombier 	fsCheck(&fsck);
1433e569ccb5SDavid du Colombier 	consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n",
1434e569ccb5SDavid du Colombier 		fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose);
1435e569ccb5SDavid du Colombier Out:
1436e569ccb5SDavid du Colombier 	if(halting)
1437e569ccb5SDavid du Colombier 		fsUnhalt(fsys->fs);
1438e569ccb5SDavid du Colombier 	return 1;
1439e569ccb5SDavid du Colombier }
1440e569ccb5SDavid du Colombier 
14415e96a66cSDavid du Colombier static int
14425e96a66cSDavid du Colombier fsysVenti(char* name, int argc, char* argv[])
14435e96a66cSDavid du Colombier {
14445e96a66cSDavid du Colombier 	int r;
14455e96a66cSDavid du Colombier 	char *host;
14465e96a66cSDavid du Colombier 	char *usage = "usage: [fsys name] venti [address]";
14475e96a66cSDavid du Colombier 	Fsys *fsys;
14485e96a66cSDavid du Colombier 
14495e96a66cSDavid du Colombier 	ARGBEGIN{
14505e96a66cSDavid du Colombier 	default:
14515e96a66cSDavid du Colombier 		return cliError(usage);
14525e96a66cSDavid du Colombier 	}ARGEND
14535e96a66cSDavid du Colombier 
14545e96a66cSDavid du Colombier 	if(argc == 0)
14555e96a66cSDavid du Colombier 		host = nil;
14565e96a66cSDavid du Colombier 	else if(argc == 1)
14575e96a66cSDavid du Colombier 		host = argv[0];
14585e96a66cSDavid du Colombier 	else
14595e96a66cSDavid du Colombier 		return cliError(usage);
14605e96a66cSDavid du Colombier 
14615e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
14625e96a66cSDavid du Colombier 		return 0;
14635e96a66cSDavid du Colombier 
14645e96a66cSDavid du Colombier 	vtLock(fsys->lock);
14655e96a66cSDavid du Colombier 	if(host == nil)
14665e96a66cSDavid du Colombier 		host = fsys->venti;
14675e96a66cSDavid du Colombier 	else{
14685e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
14695e96a66cSDavid du Colombier 		if(host[0])
14705e96a66cSDavid du Colombier 			fsys->venti = vtStrDup(host);
14715e96a66cSDavid du Colombier 		else{
14725e96a66cSDavid du Colombier 			host = nil;
14735e96a66cSDavid du Colombier 			fsys->venti = nil;
14745e96a66cSDavid du Colombier 		}
14755e96a66cSDavid du Colombier 	}
14765e96a66cSDavid du Colombier 
14775e96a66cSDavid du Colombier 	/* already open: do a redial */
14785e96a66cSDavid du Colombier 	if(fsys->fs != nil){
14796042bf6dSDavid du Colombier 		if(fsys->session == nil){
14806042bf6dSDavid du Colombier 			vtSetError("file system was opened with -V");
14816042bf6dSDavid du Colombier 			r = 0;
14826042bf6dSDavid du Colombier 			goto out;
14836042bf6dSDavid du Colombier 		}
14845e96a66cSDavid du Colombier 		r = 1;
1485ea58ad6fSDavid du Colombier 		if(!myRedial(fsys->session, host)
14865e96a66cSDavid du Colombier 		|| !vtConnect(fsys->session, 0))
14875e96a66cSDavid du Colombier 			r = 0;
14886042bf6dSDavid du Colombier 		goto out;
14895e96a66cSDavid du Colombier 	}
14905e96a66cSDavid du Colombier 
14915e96a66cSDavid du Colombier 	/* not yet open: try to dial */
14925e96a66cSDavid du Colombier 	if(fsys->session)
14935e96a66cSDavid du Colombier 		vtClose(fsys->session);
14945e96a66cSDavid du Colombier 	r = 1;
1495ea58ad6fSDavid du Colombier 	if((fsys->session = myDial(host, 0)) == nil
14965e96a66cSDavid du Colombier 	|| !vtConnect(fsys->session, 0))
14975e96a66cSDavid du Colombier 		r = 0;
14986042bf6dSDavid du Colombier out:
14995e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
15005e96a66cSDavid du Colombier 	fsysPut(fsys);
15015e96a66cSDavid du Colombier 	return r;
15025e96a66cSDavid du Colombier }
15035e96a66cSDavid du Colombier 
1504b8a11165SDavid du Colombier static ulong
1505b8a11165SDavid du Colombier freemem(void)
1506b8a11165SDavid du Colombier {
1507b8a11165SDavid du Colombier 	int nf, pgsize = 0;
1508b8a11165SDavid du Colombier 	uvlong size, userpgs = 0, userused = 0;
1509b8a11165SDavid du Colombier 	char *ln, *sl;
1510b8a11165SDavid du Colombier 	char *fields[2];
1511b8a11165SDavid du Colombier 	Biobuf *bp;
1512b8a11165SDavid du Colombier 
1513b8a11165SDavid du Colombier 	size = 64*1024*1024;
1514b8a11165SDavid du Colombier 	bp = Bopen("#c/swap", OREAD);
1515b8a11165SDavid du Colombier 	if (bp != nil) {
1516b8a11165SDavid du Colombier 		while ((ln = Brdline(bp, '\n')) != nil) {
1517b8a11165SDavid du Colombier 			ln[Blinelen(bp)-1] = '\0';
1518b8a11165SDavid du Colombier 			nf = tokenize(ln, fields, nelem(fields));
1519b8a11165SDavid du Colombier 			if (nf != 2)
1520b8a11165SDavid du Colombier 				continue;
1521b8a11165SDavid du Colombier 			if (strcmp(fields[1], "pagesize") == 0)
1522b8a11165SDavid du Colombier 				pgsize = atoi(fields[0]);
1523b8a11165SDavid du Colombier 			else if (strcmp(fields[1], "user") == 0) {
1524b8a11165SDavid du Colombier 				sl = strchr(fields[0], '/');
1525b8a11165SDavid du Colombier 				if (sl == nil)
1526b8a11165SDavid du Colombier 					continue;
1527b8a11165SDavid du Colombier 				userpgs = atoll(sl+1);
1528b8a11165SDavid du Colombier 				userused = atoll(fields[0]);
1529b8a11165SDavid du Colombier 			}
1530b8a11165SDavid du Colombier 		}
1531b8a11165SDavid du Colombier 		Bterm(bp);
1532b8a11165SDavid du Colombier 		if (pgsize > 0 && userpgs > 0)
1533b8a11165SDavid du Colombier 			size = (userpgs - userused) * pgsize;
1534b8a11165SDavid du Colombier 	}
1535b8a11165SDavid du Colombier 	/* cap it to keep the size within 32 bits */
1536b8a11165SDavid du Colombier 	if (size >= 3840UL * 1024 * 1024)
1537b8a11165SDavid du Colombier 		size = 3840UL * 1024 * 1024;
1538b8a11165SDavid du Colombier 	return size;
1539b8a11165SDavid du Colombier }
1540b8a11165SDavid du Colombier 
15415e96a66cSDavid du Colombier static int
15425e96a66cSDavid du Colombier fsysOpen(char* name, int argc, char* argv[])
15435e96a66cSDavid du Colombier {
15445e96a66cSDavid du Colombier 	char *p, *host;
15455e96a66cSDavid du Colombier 	Fsys *fsys;
1546f4051287SDavid du Colombier 	int noauth, noventi, noperm, rflag, wstatallow, noatimeupd;
1547b8a11165SDavid du Colombier 	long ncache;
15486042bf6dSDavid du Colombier 	char *usage = "usage: fsys name open [-APVWr] [-c ncache]";
15495e96a66cSDavid du Colombier 
15505e96a66cSDavid du Colombier 	ncache = 1000;
1551f4051287SDavid du Colombier 	noauth = noperm = wstatallow = noventi = noatimeupd = 0;
15525e96a66cSDavid du Colombier 	rflag = OReadWrite;
15535e96a66cSDavid du Colombier 
15545e96a66cSDavid du Colombier 	ARGBEGIN{
15555e96a66cSDavid du Colombier 	default:
15565e96a66cSDavid du Colombier 		return cliError(usage);
15575e96a66cSDavid du Colombier 	case 'A':
15585e96a66cSDavid du Colombier 		noauth = 1;
15595e96a66cSDavid du Colombier 		break;
15605e96a66cSDavid du Colombier 	case 'P':
15615e96a66cSDavid du Colombier 		noperm = 1;
15625e96a66cSDavid du Colombier 		break;
15636042bf6dSDavid du Colombier 	case 'V':
15646042bf6dSDavid du Colombier 		noventi = 1;
15656042bf6dSDavid du Colombier 		break;
15665e96a66cSDavid du Colombier 	case 'W':
15675e96a66cSDavid du Colombier 		wstatallow = 1;
15685e96a66cSDavid du Colombier 		break;
1569f4051287SDavid du Colombier 	case 'a':
1570f4051287SDavid du Colombier 		noatimeupd = 1;
1571f4051287SDavid du Colombier 		break;
15725e96a66cSDavid du Colombier 	case 'c':
15735e96a66cSDavid du Colombier 		p = ARGF();
15745e96a66cSDavid du Colombier 		if(p == nil)
15755e96a66cSDavid du Colombier 			return cliError(usage);
15765e96a66cSDavid du Colombier 		ncache = strtol(argv[0], &p, 0);
15775e96a66cSDavid du Colombier 		if(ncache <= 0 || p == argv[0] || *p != '\0')
15785e96a66cSDavid du Colombier 			return cliError(usage);
15795e96a66cSDavid du Colombier 		break;
15805e96a66cSDavid du Colombier 	case 'r':
15815e96a66cSDavid du Colombier 		rflag = OReadOnly;
15825e96a66cSDavid du Colombier 		break;
15835e96a66cSDavid du Colombier 	}ARGEND
15845e96a66cSDavid du Colombier 	if(argc)
15855e96a66cSDavid du Colombier 		return cliError(usage);
15865e96a66cSDavid du Colombier 
15875e96a66cSDavid du Colombier 	if((fsys = _fsysGet(name)) == nil)
15885e96a66cSDavid du Colombier 		return 0;
15895e96a66cSDavid du Colombier 
1590b8a11165SDavid du Colombier 	/* automatic memory sizing? */
1591b8a11165SDavid du Colombier 	if(mempcnt > 0) {
1592b8a11165SDavid du Colombier 		/* TODO: 8K is a hack; use the actual block size */
1593b8a11165SDavid du Colombier 		ncache = (((vlong)freemem() * mempcnt) / 100) / (8*1024);
1594b8a11165SDavid du Colombier 		if (ncache < 100)
1595b8a11165SDavid du Colombier 			ncache = 100;
1596b8a11165SDavid du Colombier 	}
1597b8a11165SDavid du Colombier 
15985e96a66cSDavid du Colombier 	vtLock(fsys->lock);
15995e96a66cSDavid du Colombier 	if(fsys->fs != nil){
16005e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
16015e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
16025e96a66cSDavid du Colombier 		fsysPut(fsys);
16035e96a66cSDavid du Colombier 		return 0;
16045e96a66cSDavid du Colombier 	}
16055e96a66cSDavid du Colombier 
16067611b47fSDavid du Colombier 	if(noventi){
16077611b47fSDavid du Colombier 		if(fsys->session){
16087611b47fSDavid du Colombier 			vtClose(fsys->session);
16097611b47fSDavid du Colombier 			fsys->session = nil;
16107611b47fSDavid du Colombier 		}
16117611b47fSDavid du Colombier 	}
16127611b47fSDavid du Colombier 	else if(fsys->session == nil){
16135e96a66cSDavid du Colombier 		if(fsys->venti && fsys->venti[0])
16145e96a66cSDavid du Colombier 			host = fsys->venti;
16155e96a66cSDavid du Colombier 		else
16165e96a66cSDavid du Colombier 			host = nil;
1617ea58ad6fSDavid du Colombier 		fsys->session = myDial(host, 1);
16186042bf6dSDavid du Colombier 		if(!vtConnect(fsys->session, nil) && !noventi)
161961201b97SDavid du Colombier 			fprint(2, "warning: connecting to venti: %R\n");
16205e96a66cSDavid du Colombier 	}
16215e96a66cSDavid du Colombier 	if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){
1622dc5a79c1SDavid du Colombier 		vtSetError("fsOpen: %R");
16235e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
16245e96a66cSDavid du Colombier 		fsysPut(fsys);
16255e96a66cSDavid du Colombier 		return 0;
16265e96a66cSDavid du Colombier 	}
16270c6300e7SDavid du Colombier 	fsys->fs->name = fsys->name;	/* for better error messages */
16285e96a66cSDavid du Colombier 	fsys->noauth = noauth;
16295e96a66cSDavid du Colombier 	fsys->noperm = noperm;
16305e96a66cSDavid du Colombier 	fsys->wstatallow = wstatallow;
1631f4051287SDavid du Colombier 	fsys->fs->noatimeupd = noatimeupd;
16325e96a66cSDavid du Colombier 	vtUnlock(fsys->lock);
16335e96a66cSDavid du Colombier 	fsysPut(fsys);
16345e96a66cSDavid du Colombier 
163581cf8742SDavid du Colombier 	if(strcmp(name, "main") == 0)
163681cf8742SDavid du Colombier 		usersFileRead(nil);
163781cf8742SDavid du Colombier 
16385e96a66cSDavid du Colombier 	return 1;
16395e96a66cSDavid du Colombier }
16405e96a66cSDavid du Colombier 
16415e96a66cSDavid du Colombier static int
16425e96a66cSDavid du Colombier fsysUnconfig(char* name, int argc, char* argv[])
16435e96a66cSDavid du Colombier {
16445e96a66cSDavid du Colombier 	Fsys *fsys, **fp;
16455e96a66cSDavid du Colombier 	char *usage = "usage: fsys name unconfig";
16465e96a66cSDavid du Colombier 
16475e96a66cSDavid du Colombier 	ARGBEGIN{
16485e96a66cSDavid du Colombier 	default:
16495e96a66cSDavid du Colombier 		return cliError(usage);
16505e96a66cSDavid du Colombier 	}ARGEND
16515e96a66cSDavid du Colombier 	if(argc)
16525e96a66cSDavid du Colombier 		return cliError(usage);
16535e96a66cSDavid du Colombier 
16545e96a66cSDavid du Colombier 	vtLock(sbox.lock);
16555e96a66cSDavid du Colombier 	fp = &sbox.head;
16565e96a66cSDavid du Colombier 	for(fsys = *fp; fsys != nil; fsys = fsys->next){
16575e96a66cSDavid du Colombier 		if(strcmp(fsys->name, name) == 0)
16585e96a66cSDavid du Colombier 			break;
16595e96a66cSDavid du Colombier 		fp = &fsys->next;
16605e96a66cSDavid du Colombier 	}
16615e96a66cSDavid du Colombier 	if(fsys == nil){
16625e96a66cSDavid du Colombier 		vtSetError(EFsysNotFound, name);
16635e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
16645e96a66cSDavid du Colombier 		return 0;
16655e96a66cSDavid du Colombier 	}
16665e96a66cSDavid du Colombier 	if(fsys->ref != 0 || fsys->fs != nil){
16675e96a66cSDavid du Colombier 		vtSetError(EFsysBusy, fsys->name);
16685e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
16695e96a66cSDavid du Colombier 		return 0;
16705e96a66cSDavid du Colombier 	}
16715e96a66cSDavid du Colombier 	*fp = fsys->next;
16725e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
16735e96a66cSDavid du Colombier 
16745e96a66cSDavid du Colombier 	if(fsys->session != nil){
16755e96a66cSDavid du Colombier 		vtClose(fsys->session);
16765e96a66cSDavid du Colombier 		vtFree(fsys->session);
16775e96a66cSDavid du Colombier 	}
16785e96a66cSDavid du Colombier 	if(fsys->venti != nil)
16795e96a66cSDavid du Colombier 		vtMemFree(fsys->venti);
16805e96a66cSDavid du Colombier 	if(fsys->dev != nil)
16815e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
16825e96a66cSDavid du Colombier 	if(fsys->name != nil)
16835e96a66cSDavid du Colombier 		vtMemFree(fsys->name);
16845e96a66cSDavid du Colombier 	vtMemFree(fsys);
16855e96a66cSDavid du Colombier 
16865e96a66cSDavid du Colombier 	return 1;
16875e96a66cSDavid du Colombier }
16885e96a66cSDavid du Colombier 
16895e96a66cSDavid du Colombier static int
16905e96a66cSDavid du Colombier fsysConfig(char* name, int argc, char* argv[])
16915e96a66cSDavid du Colombier {
16925e96a66cSDavid du Colombier 	Fsys *fsys;
1693*1bdadbfaSDavid du Colombier 	char *part;
1694*1bdadbfaSDavid du Colombier 	char *usage = "usage: fsys name config [dev]";
16955e96a66cSDavid du Colombier 
16965e96a66cSDavid du Colombier 	ARGBEGIN{
16975e96a66cSDavid du Colombier 	default:
16985e96a66cSDavid du Colombier 		return cliError(usage);
16995e96a66cSDavid du Colombier 	}ARGEND
1700*1bdadbfaSDavid du Colombier 	if(argc > 1)
17015e96a66cSDavid du Colombier 		return cliError(usage);
17025e96a66cSDavid du Colombier 
1703*1bdadbfaSDavid du Colombier 	if(argc == 0)
1704*1bdadbfaSDavid du Colombier 		part = foptname;
1705*1bdadbfaSDavid du Colombier 	else
1706*1bdadbfaSDavid du Colombier 		part = argv[0];
1707*1bdadbfaSDavid du Colombier 
1708*1bdadbfaSDavid du Colombier 	if((fsys = _fsysGet(part)) != nil){
17095e96a66cSDavid du Colombier 		vtLock(fsys->lock);
17105e96a66cSDavid du Colombier 		if(fsys->fs != nil){
17115e96a66cSDavid du Colombier 			vtSetError(EFsysBusy, fsys->name);
17125e96a66cSDavid du Colombier 			vtUnlock(fsys->lock);
17135e96a66cSDavid du Colombier 			fsysPut(fsys);
17145e96a66cSDavid du Colombier 			return 0;
17155e96a66cSDavid du Colombier 		}
17165e96a66cSDavid du Colombier 		vtMemFree(fsys->dev);
1717*1bdadbfaSDavid du Colombier 		fsys->dev = vtStrDup(part);
17185e96a66cSDavid du Colombier 		vtUnlock(fsys->lock);
17195e96a66cSDavid du Colombier 	}
1720*1bdadbfaSDavid du Colombier 	else if((fsys = fsysAlloc(name, part)) == nil)
17215e96a66cSDavid du Colombier 		return 0;
17225e96a66cSDavid du Colombier 
17235e96a66cSDavid du Colombier 	fsysPut(fsys);
17245e96a66cSDavid du Colombier 	return 1;
17255e96a66cSDavid du Colombier }
17265e96a66cSDavid du Colombier 
17275e96a66cSDavid du Colombier static struct {
17285e96a66cSDavid du Colombier 	char*	cmd;
17295e96a66cSDavid du Colombier 	int	(*f)(Fsys*, int, char**);
17305e96a66cSDavid du Colombier 	int	(*f1)(char*, int, char**);
17315e96a66cSDavid du Colombier } fsyscmd[] = {
17325e96a66cSDavid du Colombier 	{ "close",	fsysClose, },
17335e96a66cSDavid du Colombier 	{ "config",	nil, fsysConfig, },
17345e96a66cSDavid du Colombier 	{ "open",	nil, fsysOpen, },
17355e96a66cSDavid du Colombier 	{ "unconfig",	nil, fsysUnconfig, },
17365e96a66cSDavid du Colombier 	{ "venti",	nil, fsysVenti, },
17375e96a66cSDavid du Colombier 
17385e96a66cSDavid du Colombier 	{ "bfree",	fsysBfree, },
17395e96a66cSDavid du Colombier 	{ "block",	fsysBlock, },
1740e569ccb5SDavid du Colombier 	{ "check",	fsysCheck, },
17415e96a66cSDavid du Colombier 	{ "clre",	fsysClre, },
17425e96a66cSDavid du Colombier 	{ "clri",	fsysClri, },
17435e96a66cSDavid du Colombier 	{ "clrp",	fsysClrp, },
17445e96a66cSDavid du Colombier 	{ "create",	fsysCreate, },
17457abd426fSDavid du Colombier 	{ "df",		fsysDf, },
17465e96a66cSDavid du Colombier 	{ "epoch",	fsysEpoch, },
174781cf8742SDavid du Colombier 	{ "halt",	fsysHalt, },
17485e96a66cSDavid du Colombier 	{ "label",	fsysLabel, },
17495e96a66cSDavid du Colombier 	{ "remove",	fsysRemove, },
17505e96a66cSDavid du Colombier 	{ "snap",	fsysSnap, },
17515e96a66cSDavid du Colombier 	{ "snaptime",	fsysSnapTime, },
1752dc5a79c1SDavid du Colombier 	{ "snapclean",	fsysSnapClean, },
17535e96a66cSDavid du Colombier 	{ "stat",	fsysStat, },
17545e96a66cSDavid du Colombier 	{ "sync",	fsysSync, },
175581cf8742SDavid du Colombier 	{ "unhalt",	fsysUnhalt, },
17565e96a66cSDavid du Colombier 	{ "wstat",	fsysWstat, },
17575e96a66cSDavid du Colombier 	{ "vac",	fsysVac, },
17585e96a66cSDavid du Colombier 
17595e96a66cSDavid du Colombier 	{ nil,		nil, },
17605e96a66cSDavid du Colombier };
17615e96a66cSDavid du Colombier 
17625e96a66cSDavid du Colombier static int
176381cf8742SDavid du Colombier fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
176481cf8742SDavid du Colombier {
176581cf8742SDavid du Colombier 	int r;
176681cf8742SDavid du Colombier 
176781cf8742SDavid du Colombier 	vtLock(fsys->lock);
176881cf8742SDavid du Colombier 	if(fsys->fs == nil){
176981cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
177081cf8742SDavid du Colombier 		vtSetError(EFsysNotOpen, fsys->name);
177181cf8742SDavid du Colombier 		return 0;
177281cf8742SDavid du Colombier 	}
177381cf8742SDavid du Colombier 
1774e569ccb5SDavid du Colombier 	if(fsys->fs->halted
1775e569ccb5SDavid du Colombier 	&& fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){
177681cf8742SDavid du Colombier 		vtSetError("file system %s is halted", fsys->name);
177781cf8742SDavid du Colombier 		vtUnlock(fsys->lock);
177881cf8742SDavid du Colombier 		return 0;
177981cf8742SDavid du Colombier 	}
178081cf8742SDavid du Colombier 
178181cf8742SDavid du Colombier 	r = (*fsyscmd[i].f)(fsys, argc, argv);
178281cf8742SDavid du Colombier 	vtUnlock(fsys->lock);
178381cf8742SDavid du Colombier 	return r;
178481cf8742SDavid du Colombier }
178581cf8742SDavid du Colombier 
178681cf8742SDavid du Colombier static int
17875e96a66cSDavid du Colombier fsysXXX(char* name, int argc, char* argv[])
17885e96a66cSDavid du Colombier {
17895e96a66cSDavid du Colombier 	int i, r;
17905e96a66cSDavid du Colombier 	Fsys *fsys;
17915e96a66cSDavid du Colombier 
17925e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
17935e96a66cSDavid du Colombier 		if(strcmp(fsyscmd[i].cmd, argv[0]) == 0)
17945e96a66cSDavid du Colombier 			break;
17955e96a66cSDavid du Colombier 	}
17965e96a66cSDavid du Colombier 
17975e96a66cSDavid du Colombier 	if(fsyscmd[i].cmd == nil){
17985e96a66cSDavid du Colombier 		vtSetError("unknown command - '%s'", argv[0]);
17995e96a66cSDavid du Colombier 		return 0;
18005e96a66cSDavid du Colombier 	}
18015e96a66cSDavid du Colombier 
18025e96a66cSDavid du Colombier 	/* some commands want the name... */
180381cf8742SDavid du Colombier 	if(fsyscmd[i].f1 != nil){
180481cf8742SDavid du Colombier 		if(strcmp(name, FsysAll) == 0){
180581cf8742SDavid du Colombier 			vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
18065e96a66cSDavid du Colombier 			return 0;
18075e96a66cSDavid du Colombier 		}
180881cf8742SDavid du Colombier 		return (*fsyscmd[i].f1)(name, argc, argv);
180981cf8742SDavid du Colombier 	}
18105e96a66cSDavid du Colombier 
181181cf8742SDavid du Colombier 	/* ... but most commands want the Fsys */
181281cf8742SDavid du Colombier 	if(strcmp(name, FsysAll) == 0){
181381cf8742SDavid du Colombier 		r = 1;
181481cf8742SDavid du Colombier 		vtRLock(sbox.lock);
181581cf8742SDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
181681cf8742SDavid du Colombier 			fsys->ref++;
181781cf8742SDavid du Colombier 			r = fsysXXX1(fsys, i, argc, argv) && r;
181881cf8742SDavid du Colombier 			fsys->ref--;
181981cf8742SDavid du Colombier 		}
182081cf8742SDavid du Colombier 		vtRUnlock(sbox.lock);
182181cf8742SDavid du Colombier 	}else{
182281cf8742SDavid du Colombier 		if((fsys = _fsysGet(name)) == nil)
182381cf8742SDavid du Colombier 			return 0;
182481cf8742SDavid du Colombier 		r = fsysXXX1(fsys, i, argc, argv);
18255e96a66cSDavid du Colombier 		fsysPut(fsys);
182681cf8742SDavid du Colombier 	}
18275e96a66cSDavid du Colombier 	return r;
18285e96a66cSDavid du Colombier }
18295e96a66cSDavid du Colombier 
18305e96a66cSDavid du Colombier static int
18315e96a66cSDavid du Colombier cmdFsysXXX(int argc, char* argv[])
18325e96a66cSDavid du Colombier {
18335e96a66cSDavid du Colombier 	char *name;
18345e96a66cSDavid du Colombier 
18355e96a66cSDavid du Colombier 	if((name = sbox.curfsys) == nil){
18365e96a66cSDavid du Colombier 		vtSetError(EFsysNoCurrent, argv[0]);
18375e96a66cSDavid du Colombier 		return 0;
18385e96a66cSDavid du Colombier 	}
18395e96a66cSDavid du Colombier 
18405e96a66cSDavid du Colombier 	return fsysXXX(name, argc, argv);
18415e96a66cSDavid du Colombier }
18425e96a66cSDavid du Colombier 
18435e96a66cSDavid du Colombier static int
18445e96a66cSDavid du Colombier cmdFsys(int argc, char* argv[])
18455e96a66cSDavid du Colombier {
18465e96a66cSDavid du Colombier 	Fsys *fsys;
18475e96a66cSDavid du Colombier 	char *usage = "usage: fsys [name ...]";
18485e96a66cSDavid du Colombier 
18495e96a66cSDavid du Colombier 	ARGBEGIN{
18505e96a66cSDavid du Colombier 	default:
18515e96a66cSDavid du Colombier 		return cliError(usage);
18525e96a66cSDavid du Colombier 	}ARGEND
18535e96a66cSDavid du Colombier 
18545e96a66cSDavid du Colombier 	if(argc == 0){
18555e96a66cSDavid du Colombier 		vtRLock(sbox.lock);
1856b8a11165SDavid du Colombier 		currfsysname = sbox.head->name;
18575e96a66cSDavid du Colombier 		for(fsys = sbox.head; fsys != nil; fsys = fsys->next)
18585e96a66cSDavid du Colombier 			consPrint("\t%s\n", fsys->name);
18595e96a66cSDavid du Colombier 		vtRUnlock(sbox.lock);
18605e96a66cSDavid du Colombier 		return 1;
18615e96a66cSDavid du Colombier 	}
18625e96a66cSDavid du Colombier 	if(argc == 1){
186381cf8742SDavid du Colombier 		fsys = nil;
186481cf8742SDavid du Colombier 		if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
18655e96a66cSDavid du Colombier 			return 0;
186681cf8742SDavid du Colombier 		sbox.curfsys = vtStrDup(argv[0]);
18675e96a66cSDavid du Colombier 		consPrompt(sbox.curfsys);
186881cf8742SDavid du Colombier 		if(fsys)
18695e96a66cSDavid du Colombier 			fsysPut(fsys);
18705e96a66cSDavid du Colombier 		return 1;
18715e96a66cSDavid du Colombier 	}
18725e96a66cSDavid du Colombier 
18735e96a66cSDavid du Colombier 	return fsysXXX(argv[0], argc-1, argv+1);
18745e96a66cSDavid du Colombier }
18755e96a66cSDavid du Colombier 
18765e96a66cSDavid du Colombier int
18775e96a66cSDavid du Colombier fsysInit(void)
18785e96a66cSDavid du Colombier {
18795e96a66cSDavid du Colombier 	int i;
18805e96a66cSDavid du Colombier 
18815e96a66cSDavid du Colombier 	fmtinstall('H', encodefmt);
18825e96a66cSDavid du Colombier 	fmtinstall('V', scoreFmt);
18835e96a66cSDavid du Colombier 	fmtinstall('R', vtErrFmt);
18845e96a66cSDavid du Colombier 	fmtinstall('L', labelFmt);
18855e96a66cSDavid du Colombier 
18865e96a66cSDavid du Colombier 	sbox.lock = vtLockAlloc();
18875e96a66cSDavid du Colombier 
18885e96a66cSDavid du Colombier 	cliAddCmd("fsys", cmdFsys);
18895e96a66cSDavid du Colombier 	for(i = 0; fsyscmd[i].cmd != nil; i++){
18905e96a66cSDavid du Colombier 		if(fsyscmd[i].f != nil)
18915e96a66cSDavid du Colombier 			cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX);
18925e96a66cSDavid du Colombier 	}
18935e96a66cSDavid du Colombier 	/* the venti cmd is special: the fs can be either open or closed */
18945e96a66cSDavid du Colombier 	cliAddCmd("venti", cmdFsysXXX);
18955e96a66cSDavid du Colombier 	cliAddCmd("printconfig", cmdPrintConfig);
18965e96a66cSDavid du Colombier 
18975e96a66cSDavid du Colombier 	return 1;
18985e96a66cSDavid du Colombier }
1899