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