Browse Source

Plan 9 from Bell Labs 2003-04-17

David du Colombier 21 years ago
parent
commit
10d4676273

+ 12 - 12
dist/replica/plan9.db

@@ -94,7 +94,7 @@
 386/bin/aux/cropmarks - 775 sys sys 1020319062 1808
 386/bin/aux/data2s - 775 sys sys 1039758538 59178
 386/bin/aux/depend - 775 sys sys 1045537948 145890
-386/bin/aux/disksim - 775 sys sys 1048745013 145153
+386/bin/aux/disksim - 775 sys sys 1050521403 145858
 386/bin/aux/download - 775 sys sys 1048745014 175067
 386/bin/aux/faxreceive - 775 sys sys 1045537949 83421
 386/bin/aux/faxsend - 775 sys sys 1045537950 88819
@@ -4858,7 +4858,7 @@ sys/man/8/cpurc - 664 sys sys 971455510 1275
 sys/man/8/cron - 664 sys sys 944959679 1750
 sys/man/8/dhcpd - 664 sys sys 1032654987 5237
 sys/man/8/drawterm - 664 sys sys 958419689 2458
-sys/man/8/fossilcons - 664 sys sys 1044478450 13360
+sys/man/8/fossilcons - 664 sys sys 1050520258 14126
 sys/man/8/fs - 664 sys sys 1045570953 14693
 sys/man/8/fsconfig - 664 sys sys 1045501600 8142
 sys/man/8/httpd - 664 sys sys 1037690024 4516
@@ -6643,7 +6643,7 @@ sys/src/cmd/aux/consolefs.c - 664 sys sys 1014925110 20022
 sys/src/cmd/aux/conswdir.c - 664 sys sys 1045504955 2077
 sys/src/cmd/aux/data2s.c - 664 sys sys 1032059295 796
 sys/src/cmd/aux/depend.c - 664 sys sys 1015008684 25780
-sys/src/cmd/aux/disksim.c - 664 sys sys 1032325930 10218
+sys/src/cmd/aux/disksim.c - 664 sys sys 1050521402 10227
 sys/src/cmd/aux/flashfs - 20000000775 sys sys 1015009082 0
 sys/src/cmd/aux/flashfs/aux.c - 664 sys sys 1015009080 699
 sys/src/cmd/aux/flashfs/aux.h - 664 sys sys 1015009080 111
@@ -7114,20 +7114,20 @@ sys/src/cmd/file.c - 664 sys sys 1048635557 20358
 sys/src/cmd/fmt.c - 664 sys sys 1025298248 3897
 sys/src/cmd/fortune.c - 664 sys sys 1035832953 1674
 sys/src/cmd/fossil - 20000000775 sys sys 1042005512 0
-sys/src/cmd/fossil/9.h - 664 sys sys 1045576809 3987
-sys/src/cmd/fossil/9auth.c - 664 sys sys 1045600016 3149
+sys/src/cmd/fossil/9.h - 664 sys sys 1050518982 4067
+sys/src/cmd/fossil/9auth.c - 664 sys sys 1050518977 3394
 sys/src/cmd/fossil/9dir.c - 664 sys sys 1042005502 1995
 sys/src/cmd/fossil/9excl.c - 664 sys sys 1042005502 1887
 sys/src/cmd/fossil/9fid.c - 664 sys sys 1045600016 5521
-sys/src/cmd/fossil/9fsys.c - 664 sys sys 1048859381 27349
+sys/src/cmd/fossil/9fsys.c - 664 sys sys 1050518978 28719
 sys/src/cmd/fossil/9lstn.c - 664 sys sys 1042005503 2865
 sys/src/cmd/fossil/9p.c - 664 sys sys 1048644482 21360
 sys/src/cmd/fossil/9ping.c - 664 sys sys 1042005503 1563
-sys/src/cmd/fossil/9proc.c - 664 sys sys 1045576808 13707
+sys/src/cmd/fossil/9proc.c - 664 sys sys 1050518978 15245
 sys/src/cmd/fossil/9srv.c - 664 sys sys 1045600018 3291
-sys/src/cmd/fossil/9user.c - 664 sys sys 1045600019 17457
+sys/src/cmd/fossil/9user.c - 664 sys sys 1050518979 17211
 sys/src/cmd/fossil/Ccli.c - 664 sys sys 1042005504 1624
-sys/src/cmd/fossil/Ccmd.c - 664 sys sys 1045600019 7160
+sys/src/cmd/fossil/Ccmd.c - 664 sys sys 1050518979 7246
 sys/src/cmd/fossil/Ccons.c - 664 sys sys 1042005504 6524
 sys/src/cmd/fossil/Clog.c - 664 sys sys 1042005505 591
 sys/src/cmd/fossil/archive.c - 664 sys sys 1045600020 9112
@@ -7135,7 +7135,7 @@ sys/src/cmd/fossil/build - 664 sys sys 1042005505 449
 sys/src/cmd/fossil/buildsh - 775 sys sys 1042005505 561
 sys/src/cmd/fossil/bwatch.c - 664 sys sys 1042005505 6754
 sys/src/cmd/fossil/cache.c - 664 sys sys 1048859382 42848
-sys/src/cmd/fossil/dat.h - 664 sys sys 1042311689 7790
+sys/src/cmd/fossil/dat.h - 664 sys sys 1050518981 7855
 sys/src/cmd/fossil/deadlock - 775 sys sys 1042005506 413
 sys/src/cmd/fossil/disk.c - 664 sys sys 1042497769 5736
 sys/src/cmd/fossil/dump.c - 664 sys sys 1042005506 1340
@@ -7149,8 +7149,8 @@ sys/src/cmd/fossil/flproto - 664 sys sys 1042005508 210
 sys/src/cmd/fossil/fns.h - 664 sys sys 1048859327 3022
 sys/src/cmd/fossil/fossil-acid - 664 sys sys 1042005508 3965
 sys/src/cmd/fossil/fossil.c - 664 sys sys 1045600029 1267
-sys/src/cmd/fossil/fs.c - 664 sys sys 1048859383 16614
-sys/src/cmd/fossil/fs.h - 664 sys sys 1042005509 1222
+sys/src/cmd/fossil/fs.c - 664 sys sys 1050518980 16944
+sys/src/cmd/fossil/fs.h - 664 sys sys 1050518982 1258
 sys/src/cmd/fossil/history - 664 sys sys 1045600133 1150
 sys/src/cmd/fossil/invariants - 664 sys sys 1042005509 4073
 sys/src/cmd/fossil/mkfile - 664 sys sys 1048859379 1551

+ 13 - 0
dist/replica/plan9.log

@@ -19105,3 +19105,16 @@
 1050435578 0 c 386/bin/acme - 775 sys sys 1050435573 417767
 1050435578 1 c 386/bin/htmlfmt - 775 sys sys 1050435574 159132
 1050442304 0 c sys/src/cmd/aux/acidleak.c - 664 sys sys 1050441591 5931
+1050519678 0 c sys/man/8/fossilcons - 664 sys sys 1050518986 14126
+1050519678 1 c sys/src/cmd/fossil/9.h - 664 sys sys 1050518982 4067
+1050519678 2 c sys/src/cmd/fossil/9auth.c - 664 sys sys 1050518977 3394
+1050519678 3 c sys/src/cmd/fossil/9fsys.c - 664 sys sys 1050518978 28719
+1050519678 4 c sys/src/cmd/fossil/9proc.c - 664 sys sys 1050518978 15245
+1050519678 5 c sys/src/cmd/fossil/9user.c - 664 sys sys 1050518979 17211
+1050519678 6 c sys/src/cmd/fossil/Ccmd.c - 664 sys sys 1050518979 7246
+1050519678 7 c sys/src/cmd/fossil/dat.h - 664 sys sys 1050518981 7855
+1050519678 8 c sys/src/cmd/fossil/fs.c - 664 sys sys 1050518980 16944
+1050519678 9 c sys/src/cmd/fossil/fs.h - 664 sys sys 1050518982 1258
+1050521413 0 c 386/bin/aux/disksim - 775 sys sys 1050521403 145858
+1050521413 1 c sys/man/8/fossilcons - 664 sys sys 1050520258 14126
+1050521413 2 c sys/src/cmd/aux/disksim.c - 664 sys sys 1050521402 10227

+ 91 - 32
sys/man/8/fossilcons

@@ -42,6 +42,12 @@ con /srv/fscons
 .I nproc
 ]
 .PP
+.B srv
+[
+.B -dp
+]
+.I name
+.PP
 .B uname
 .I name
 [
@@ -65,11 +71,7 @@ con /srv/fscons
 .I file
 ]
 .PP
-.B srv
-[
-.B -dp
-]
-.I name
+.B who
 .sp
 .PP
 .B fsys
@@ -169,6 +171,12 @@ con /srv/fscons
 .B fsys
 .I name
 ]
+.B df
+.PP
+[
+.B fsys
+.I name
+]
 .B epoch
 [
 .B -y
@@ -179,6 +187,12 @@ con /srv/fscons
 .B fsys
 .I name
 ]
+.B halt
+.PP
+[
+.B fsys
+.I name
+]
 .B label
 .I addr
 [
@@ -237,6 +251,12 @@ con /srv/fscons
 .B fsys
 .I name
 ]
+.B unhalt
+.PP
+[
+.B fsys
+.I name
+]
 .B vac
 .I dir
 .PP
@@ -273,6 +293,7 @@ treating each line as a command to be executed.
 Blank lines and lines beginning with a 
 .L #
 character are ignored.
+Errors during execution are printed but do not stop the script.
 Note that
 .I file
 is a file in the name space in which
@@ -325,6 +346,16 @@ and
 .B -p
 options set the two variables.
 .PP
+.I Srv
+behaves like listen but uses
+.BI /srv/ name
+rather than a network address.
+With the
+.B -p
+flag, 
+.I srv 
+edits a list of console services rather than 9P services.
+.PP
 .I Uname
 manipulates entries in the user table.
 There is no distinction between users and groups:
@@ -434,51 +465,57 @@ is printed, in the form
 The end of this manual page gives examples.
 .PP
 .I Users
-reads
-.IR file
-from the file system named
-.B main
-and uses it to initialize the user table.
-With no arguments,
-.I users
-prints the file name of the current user table.
-.PP
+manipulates the user table.
 The user table is a list of lines in the form printed
 by the
 .I uname
 command.
 The
 .B -d
-flag resets the user table to the default:
+flag resets the user table with the default:
 .IP
 .EX
 adm:adm:adm:sys
 none:none::
 noworld:noworld::
 sys:sys::
-.EE
 .PP
-These users are mandatory and must appear in all user files read.
+These users are mandatory and must appear in all user files.
 It is not possible to rename these unames.
+.EE
 .PP
 The
+.B -r
+flag reads a user table from the named
+.I file
+in file system
+.BR main .
+The
 .B -w
-flag causes the file
-.I /active/adm/users
-to be written with the current in-memory table.
-The path
-.I /active/adm
-must exist.
+flag writes the table to
+.B /active/adm/users
+on the file system
+.BR main .
+.B /active/adm
+and
+.B /active/adm/users
+will be created if they do not exist.
 .PP
-.I Srv
-behaves like listen but uses
-.BI /srv/ name
-rather than a network address.
-With the
-.B -p
-flag, 
-.I srv 
-edits a list of console services rather than 9P services.
+.I Users
+.B -r
+.B /active/adm/users
+is automatically executed when the file system
+.B main
+is opened.
+.PP
+.I Users
+.B -w
+is automatically executed after each change to the user
+table by the
+.I uname
+command.
+.I Who
+prints a list of users attached to each active connection.
 .SS File system configuration
 .I Fsys
 sets the current file system to
@@ -486,6 +523,20 @@ sets the current file system to
 which must be configured and open (q.v.).
 The current file system name is
 displayed as the file server prompt.
+The special name
+.B all
+stands for all file systems;
+commands applied to
+.B all
+are applied to each file system in turn.
+The commands
+.BR config ,
+.BR open ,
+.BR venti ,
+and
+.B close
+cannot be applied to
+.BR all .
 .PP
 .I Fsys
 takes as an optional argument
@@ -650,6 +701,9 @@ and
 .B -l
 flags set the append-only, directory, and lock bits.
 .PP
+.I Df
+prints the amount of used disk space in the write buffer.
+.PP
 .I Epoch
 sets the low file system epoch.
 Snapshots in the file system are given increasing epoch numbers.
@@ -692,6 +746,11 @@ the archiver should take care
 of those snapshots (moving the blocks from disk to Venti)
 if you give it more time.
 .PP
+.I Halt
+suspends file system activity;
+.I unhalt
+resumes activity.
+.PP
 .I Label
 displays and edits the label associated with a block.
 When editing, a parameter of

+ 1 - 1
sys/src/cmd/aux/disksim.c

@@ -312,7 +312,7 @@ dirgen(int off, Dir *d, void*)
 			continue;
 		if(n == off){
 			d->name = estrdup9p(tab[j].name);
-			d->length = tab[j].length;
+			d->length = tab[j].length*sectsize;
 			d->mode = tab[j].mode;
 			d->qid.path = Qpart+j;
 			d->qid.vers = tab[j].vers;

+ 2 - 0
sys/src/cmd/fossil/9.h

@@ -105,6 +105,7 @@ struct Fid {
 	AuthRpc* rpc;
 	char*	cuname;
 
+	Fid*	sort;				/* sorted by uname in cmdWho */
 	Fid*	hash;			/* lookup by fidno */
 	Fid*	next;			/* clunk session with Tversion */
 	Fid*	prev;
@@ -202,6 +203,7 @@ extern int groupWriteMember(char*);
 extern char* unameByUid(char*);
 extern char* uidByUname(char*);
 extern int usersInit(void);
+extern int usersFileRead(char*);
 extern int validUserName(char*);
 
 extern char* uidadm;

+ 16 - 5
sys/src/cmd/fossil/9auth.c

@@ -8,16 +8,22 @@ authRead(Fid* afid, void* data, int count)
 	AuthInfo *ai;
 	AuthRpc *rpc;
 
-	if((rpc = afid->rpc) == nil)
+	if((rpc = afid->rpc) == nil){
+		vtSetError("not an auth fid");
 		return -1;
+	}
 
 	switch(auth_rpc(rpc, "read", nil, 0)){
 	default:
+		vtSetError("auth protocol not finished");
 		return -1;
 	case ARdone:
-		if((ai = auth_getinfo(rpc)) == nil)
+		if((ai = auth_getinfo(rpc)) == nil){
+			vtSetError("%r");
 			break;
+		}
 		if(ai->cuid == nil || *ai->cuid == '\0'){
+			vtSetError("auth with no cuid");
 			auth_freeAI(ai);
 			break;
 		}
@@ -27,15 +33,20 @@ authRead(Fid* afid, void* data, int count)
 		if(Dflag)
 			fprint(2, "authRead cuname %s\n", afid->cuname);
 		assert(afid->uid == nil);
-		if((afid->uid = uidByUname(afid->cuname)) == nil)
+		if((afid->uid = uidByUname(afid->cuname)) == nil){
+			vtSetError("unknown user %#q", afid->cuname);
 			break;
+		}
 		return 0;
 	case ARok:
-		if(count < rpc->narg)
+		if(count < rpc->narg){
+			vtSetError("not enough data in auth read");
 			break;
+		}
 		memmove(data, rpc->arg, rpc->narg);
 		return rpc->narg;
 	case ARphase:
+		vtSetError("%r");
 		break;
 	}
 	return -1;
@@ -112,7 +123,7 @@ authCheck(Fcall* t, Fid* fid, Fs* fsys)
 	if(afid->cuname == nil){
 		if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){
 			vtUnlock(afid->alock);
-			consPrint("attach %s as %s: auth protocol not finished\n", fsysGetName(fsys), fid->uname);
+			consPrint("attach %s as %s: %R\n", fsysGetName(fsys), fid->uname);
 			fidPut(afid);
 			return 0;
 		}

+ 88 - 17
sys/src/cmd/fossil/9fsys.c

@@ -35,6 +35,8 @@ static struct {
 static char *_argv0;
 #define argv0 _argv0
 
+static char FsysAll[] = "all";
+
 static char EFsysBusy[] = "fsys: '%s' busy";
 static char EFsysExists[] = "fsys: '%s' already exists";
 static char EFsysNoCurrent[] = "fsys: no current fsys";
@@ -417,7 +419,41 @@ fsysSync(Fsys* fsys, int argc, char* argv[])
 		return cliError(usage);
 
 	fsSync(fsys->fs);
+	return 1;
+}
+
+static int
+fsysHalt(Fsys *fsys, int argc, char* argv[])
+{
+	char *usage = "usage: [fsys name] halt";
+
+	ARGBEGIN{
+	default:
+		return cliError(usage);
+	}ARGEND
+	if(argc > 0)
+		return cliError(usage);
+
+	fsHalt(fsys->fs);
+	return 1;
+}
+
+static int
+fsysUnhalt(Fsys *fsys, int argc, char* argv[])
+{
+	char *usage = "usage: [fsys name] unhalt";
+
+	ARGBEGIN{
+	default:
+		return cliError(usage);
+	}ARGEND
+	if(argc > 0)
+		return cliError(usage);
+
+	if(!fsys->fs->halted)
+		return cliError("file system %s not halted", fsys->name);
 
+	fsUnhalt(fsys->fs);
 	return 1;
 }
 
@@ -1276,9 +1312,11 @@ fsysOpen(char* name, int argc, char* argv[])
 	fsys->noperm = noperm;
 	fsys->wstatallow = wstatallow;
 	vtUnlock(fsys->lock);
-
 	fsysPut(fsys);
 
+	if(strcmp(name, "main") == 0)
+		usersFileRead(nil);
+
 	return 1;
 }
 
@@ -1382,18 +1420,43 @@ static struct {
 	{ "create",	fsysCreate, },
 	{ "df",	fsysDf, },
 	{ "epoch",	fsysEpoch, },
+	{ "halt",	fsysHalt, },
 	{ "label",	fsysLabel, },
 	{ "remove",	fsysRemove, },
 	{ "snap",	fsysSnap, },
 	{ "snaptime",	fsysSnapTime, },
 	{ "stat",	fsysStat, },
 	{ "sync",	fsysSync, },
+	{ "unhalt",	fsysUnhalt, },
 	{ "wstat",	fsysWstat, },
 	{ "vac",	fsysVac, },
 
 	{ nil,		nil, },
 };
 
+static int
+fsysXXX1(Fsys *fsys, int i, int argc, char* argv[])
+{
+	int r;
+
+	vtLock(fsys->lock);
+	if(fsys->fs == nil){
+		vtUnlock(fsys->lock);
+		vtSetError(EFsysNotOpen, fsys->name);
+		return 0;
+	}
+
+	if(fsys->fs->halted && fsyscmd[i].f != fsysUnhalt){
+		vtSetError("file system %s is halted", fsys->name);
+		vtUnlock(fsys->lock);
+		return 0;
+	}
+
+	r = (*fsyscmd[i].f)(fsys, argc, argv);
+	vtUnlock(fsys->lock);
+	return r;
+}
+
 static int
 fsysXXX(char* name, int argc, char* argv[])
 {
@@ -1411,24 +1474,30 @@ fsysXXX(char* name, int argc, char* argv[])
 	}
 
 	/* some commands want the name... */
-	if(fsyscmd[i].f1 != nil)
+	if(fsyscmd[i].f1 != nil){
+		if(strcmp(name, FsysAll) == 0){
+			vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]);
+			return 0;
+		}
 		return (*fsyscmd[i].f1)(name, argc, argv);
+	}
 
 	/* ... but most commands want the Fsys */
-	if((fsys = _fsysGet(name)) == nil)
-		return 0;
-
-	vtLock(fsys->lock);
-	if(fsys->fs == nil){
-		vtUnlock(fsys->lock);
-		vtSetError(EFsysNotOpen, name);
+	if(strcmp(name, FsysAll) == 0){
+		r = 1;
+		vtRLock(sbox.lock);
+		for(fsys = sbox.head; fsys != nil; fsys = fsys->next){
+			fsys->ref++;
+			r = fsysXXX1(fsys, i, argc, argv) && r;
+			fsys->ref--;
+		}
+		vtRUnlock(sbox.lock);
+	}else{
+		if((fsys = _fsysGet(name)) == nil)
+			return 0;
+		r = fsysXXX1(fsys, i, argc, argv);
 		fsysPut(fsys);
-		return 0;
 	}
-
-	r = (*fsyscmd[i].f)(fsys, argc, argv);
-	vtUnlock(fsys->lock);
-	fsysPut(fsys);
 	return r;
 }
 
@@ -1464,11 +1533,13 @@ cmdFsys(int argc, char* argv[])
 		return 1;
 	}
 	if(argc == 1){
-		if((fsys = fsysGet(argv[0])) == nil)
+		fsys = nil;
+		if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil)
 			return 0;
-		sbox.curfsys = vtStrDup(fsys->name);
+		sbox.curfsys = vtStrDup(argv[0]);
 		consPrompt(sbox.curfsys);
-		fsysPut(fsys);
+		if(fsys)
+			fsysPut(fsys);
 		return 1;
 	}
 

+ 103 - 0
sys/src/cmd/fossil/9proc.c

@@ -669,6 +669,108 @@ cmdMsg(int argc, char* argv[])
 	return 1;
 }
 
+static int
+scmp(Fid *a, Fid *b)
+{
+	if(a == 0)
+		return 1;
+	if(b == 0)
+		return -1;
+	return strcmp(a->uname, b->uname);
+}
+
+static Fid*
+fidMerge(Fid *a, Fid *b)
+{
+	Fid *s, **l;
+
+	l = &s;
+	while(a || b){
+		if(scmp(a, b) < 0){
+			*l = a;
+			l = &a->sort;
+			a = a->sort;
+		}else{
+			*l = b;
+			l = &b->sort;
+			b = b->sort;
+		}
+	}
+	*l = 0;
+	return s;
+}
+
+static Fid*
+fidMergeSort(Fid *f)
+{
+	int delay;
+	Fid *a, *b;
+
+	if(f == nil)
+		return nil;
+	if(f->sort == nil)
+		return f;
+
+	a = b = f;
+	delay = 1;
+	while(a && b){
+		if(delay)	/* easy way to handle 2-element list */
+			delay = 0;
+		else
+			a = a->sort;
+		if(b = b->sort)
+			b = b->sort;
+	}
+
+	b = a->sort;
+	a->sort = nil;
+
+	a = fidMergeSort(f);
+	b = fidMergeSort(b);
+
+	return fidMerge(a, b);
+}
+
+
+static int
+cmdWho(int argc, char* argv[])
+{
+	char *usage = "usage: who";
+	int i;
+	Con *con;
+	Fid *fid, *last;
+
+	ARGBEGIN{
+	default:
+		return cliError(usage);
+	}ARGEND
+
+	if(argc > 0)
+		return cliError(usage);
+
+	vtRLock(cbox.clock);
+	for(con=cbox.chead; con; con=con->cnext){
+		consPrint("\t%q:", con->name);
+		vtLock(con->fidlock);
+		last = nil;
+		for(i=0; i<NFidHash; i++)
+			for(fid=con->fidhash[i]; fid; fid=fid->hash)
+				if(fid->fidno != NOFID && fid->uname){
+					fid->sort = last;
+					last = fid;
+				}
+		fid = fidMergeSort(last);
+		last = nil;
+		for(; fid; last=fid, fid=fid->sort)
+			if(last==nil || strcmp(fid->uname, last->uname) != 0)
+				consPrint(" %q", fid->uname);
+		vtUnlock(con->fidlock);
+		consPrint("\n");
+	}
+	vtRUnlock(cbox.clock);
+	return 1;
+}	
+
 void
 msgInit(void)
 {
@@ -742,4 +844,5 @@ conInit(void)
 	cbox.msize = NMsizeInit;
 
 	cliAddCmd("con", cmdCon);
+	cliAddCmd("who", cmdWho);
 }

+ 33 - 42
sys/src/cmd/fossil/9user.c

@@ -26,7 +26,6 @@ typedef struct User {
 typedef struct Ubox {
 	User*	head;
 	User*	tail;
-	char*	name;
 	int	nuser;
 	int	len;
 
@@ -509,13 +508,11 @@ uboxFree(Ubox* box)
 		next = u->next;
 		userFree(u);
 	}
-	if(box->name != nil)
-		vtMemFree(box->name);
 	vtMemFree(box);
 }
 
 static int
-uboxInit(char* name, char* users, int len)
+uboxInit(char* users, int len)
 {
 	User *g, *u;
 	Ubox *box, *obox;
@@ -565,11 +562,9 @@ uboxInit(char* name, char* users, int len)
 	fprint(2, "nuser %d\n", nuser);
 
 	/*
-	 * Everything us updated in a local Ubox until verified.
+	 * Everything is updated in a local Ubox until verified.
 	 */
 	box = vtMemAllocZ(sizeof(Ubox));
-	if(name != nil)
-		box->name = vtStrDup(name);
 
 	/*
 	 * First pass - check format, check for duplicates
@@ -659,11 +654,6 @@ uboxInit(char* name, char* users, int len)
 	}
 
 	vtLock(ubox.lock);
-	if(name != nil && usersFileWrite(box) == 0){
-		/*
-		 * What to do here? How much whining?
-		 */
-	}
 	obox = ubox.box;
 	ubox.box = box;
 	vtUnlock(ubox.lock);
@@ -674,7 +664,7 @@ uboxInit(char* name, char* users, int len)
 	return 1;
 }
 
-static int
+int
 usersFileRead(char* path)
 {
 	char *p;
@@ -687,6 +677,9 @@ usersFileRead(char* path)
 		return 0;
 	fsysFsRlock(fsys);
 
+	if(path == nil)
+		path = "/active/adm/users";
+
 	r = 0;
 	if((file = fileOpen(fsysGetFs(fsys), path)) != nil){
 		if(fileGetSize(file, &size)){
@@ -694,7 +687,7 @@ usersFileRead(char* path)
 			p = vtMemAlloc(size+1);
 			if(fileRead(file, p, len, 0) == len){
 				p[len] = '\0';
-				r = uboxInit(path, p, len);
+				r = uboxInit(p, len);
 			}
 		}
 		fileDecRef(file);
@@ -895,9 +888,11 @@ cmdUsers(int argc, char* argv[])
 {
 	Ubox *box;
 	int dflag, r, wflag;
-	char *usage = "usage: users [-dw] [file]";
+	char *file;
+	char *usage = "usage: users [-d | -r file] [-w]";
 
 	dflag = wflag = 0;
+	file = nil;
 
 	ARGBEGIN{
 	default:
@@ -905,42 +900,38 @@ cmdUsers(int argc, char* argv[])
 	case 'd':
 		dflag = 1;
 		break;
+	case 'r':
+		file = ARGF();
+		if(file == nil)
+			return cliError(usage);
+		break;
 	case 'w':
 		wflag = 1;
 		break;
 	}ARGEND
 
-	switch(argc){
-	default:
+	if(argc)
 		return cliError(usage);
-	case 0:
-		if(dflag)
-			uboxInit(nil, usersDefault, sizeof(usersDefault));
-		vtRLock(ubox.lock);
-		box = ubox.box;
-		if(box->name != nil)
-			consPrint("\tfile %s\n", box->name);
-		else
-			consPrint("\tno file\n");
-		consPrint("\tnuser %d len %d\n", box->nuser, box->len);
-		vtRUnlock(ubox.lock);
-		break;
-	case 1:
-		if(dflag)
-			return cliError(usage);
-		if(usersFileRead(argv[0]) == 0)
+
+	if(dflag && file)
+		return cliError("cannot use -d and -r together");
+
+	if(dflag)
+		uboxInit(usersDefault, sizeof(usersDefault));
+	else if(file){
+		if(usersFileRead(file) == 0)
 			return 0;
-		break;
 	}
 
-	if(wflag){
-		vtRLock(ubox.lock);
-		r = usersFileWrite(ubox.box);
-		vtRUnlock(ubox.lock);
-		return r;
-	}
+	vtRLock(ubox.lock);
+	box = ubox.box;
+	consPrint("\tnuser %d len %d\n", box->nuser, box->len);
 
-	return 1;
+	r = 1;
+	if(wflag)
+		r = usersFileWrite(box);
+	vtRUnlock(ubox.lock);
+	return r;
 }
 
 int
@@ -949,7 +940,7 @@ usersInit(void)
 	fmtinstall('U', userFmt);
 
 	ubox.lock = vtLockAlloc();
-	uboxInit(nil, usersDefault, sizeof(usersDefault));
+	uboxInit(usersDefault, sizeof(usersDefault));
 
 	cliAddCmd("users", cmdUsers);
 	cliAddCmd("uname", cmdUname);

+ 7 - 3
sys/src/cmd/fossil/Ccmd.c

@@ -309,7 +309,7 @@ cmdDot(int argc, char* argv[])
 	length = dir->length;
 	free(dir);
 
-	r = 0;
+	r = 1;
 	if(length != 0){
 		/*
 		 * Read the whole file in.
@@ -331,14 +331,18 @@ cmdDot(int argc, char* argv[])
 		for(p = s = f; *p != '\0'; p++){
 			if(*p == '\n'){
 				*p = '\0';
-				if((r = cliExec(s)) == 0)
-					break;
+				if(cliExec(s) == 0){
+					r = 0;
+					consPrint("%s: %R\n", s);
+				}
 				s = p+1;
 			}
 		}
 		vtMemFree(f);
 	}
 
+	if(r == 0)
+		vtSetError("errors in . %#q", argv[0]);
 	return r;
 }
 

+ 2 - 2
sys/src/cmd/fossil/dat.h

@@ -67,8 +67,6 @@ struct Fs {
 
 	Periodic *metaFlush;	/* periodically flushes meta data cached in files */
 
-	
-
 	/*
 	 * epoch lock.
 	 * Most operations on the fs require a read lock of elk, ensuring that
@@ -81,6 +79,8 @@ struct Fs {
 	u32int ehi;		/* epoch high */
 	u32int elo;		/* epoch low */
 
+	int halted;		/* epoch lock is held to halt (console initiated) */
+
 	Source *source;		/* immutable: root of sources */
 	File *file;		/* immutable: root of files */
 };

+ 26 - 0
sys/src/cmd/fossil/fs.c

@@ -442,6 +442,11 @@ fsSnapshot(Fs *fs, int doarchive)
 
 	dst = nil;
 
+	if(fs->halted){
+		vtSetError("file system is halted");
+		return 0;
+	}
+
 	/*
 	 * Freeze file system activity.
 	 */
@@ -671,11 +676,32 @@ int
 fsSync(Fs *fs)
 {
 	vtLock(fs->elk);
+	fileMetaFlush(fs->file, 1);
 	cacheFlush(fs->cache, 1);
 	vtUnlock(fs->elk);
 	return 1;
 }
 
+int
+fsHalt(Fs *fs)
+{
+	vtLock(fs->elk);
+	fs->halted = 1;
+	fileMetaFlush(fs->file, 1);
+	cacheFlush(fs->cache, 1);
+	return 1;
+}
+
+int
+fsUnhalt(Fs *fs)
+{
+	if(!fs->halted)
+		return 0;
+	fs->halted = 0;
+	vtUnlock(fs->elk);
+	return 1;
+}
+
 int
 fsNextQid(Fs *fs, u64int *qid)
 {

+ 2 - 0
sys/src/cmd/fossil/fs.h

@@ -15,6 +15,8 @@ void fsClose(Fs*);
 File *fsGetRoot(Fs*);
 int fsSnapshot(Fs*, int);
 int fsSync(Fs*);
+int fsHalt(Fs*);
+int fsUnhalt(Fs*);
 int fsVac(Fs*, char*, uchar[VtScoreSize]);
 int fsRedial(Fs*, char*);
 int fsEpochLow(Fs*, u32int);