xref: /plan9/sys/src/cmd/srvold9p/srvold9p.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier #include <fcall.h>
56b6b9ac8SDavid du Colombier #include <libsec.h>
69a747e4fSDavid du Colombier #include "9p1.h"
79a747e4fSDavid du Colombier 
89a747e4fSDavid du Colombier char	*user;
99a747e4fSDavid du Colombier int	newfd;
109a747e4fSDavid du Colombier int	roldfd;
119a747e4fSDavid du Colombier int	woldfd;
129a747e4fSDavid du Colombier int	debug;
139a747e4fSDavid du Colombier int	dofcall;
149a747e4fSDavid du Colombier QLock	servelock;
159a747e4fSDavid du Colombier QLock	fidlock;
169a747e4fSDavid du Colombier QLock	taglock;
179a747e4fSDavid du Colombier int	mainpid;
189a747e4fSDavid du Colombier int	ntag;
199a747e4fSDavid du Colombier int	nfork;
209a747e4fSDavid du Colombier char FLUSHED[] = "FLUSHED";
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier enum{
239a747e4fSDavid du Colombier 	Maxfdata = 8192
249a747e4fSDavid du Colombier };
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier enum{
279a747e4fSDavid du Colombier 	Command,
289a747e4fSDavid du Colombier 	Network,
299a747e4fSDavid du Colombier 	File,
309a747e4fSDavid du Colombier 	Stdio,
319a747e4fSDavid du Colombier };
329a747e4fSDavid du Colombier 
339a747e4fSDavid du Colombier typedef struct Tag Tag;
349a747e4fSDavid du Colombier struct Tag
359a747e4fSDavid du Colombier {
369a747e4fSDavid du Colombier 	int	tag;
379a747e4fSDavid du Colombier 	int	flushed;
389a747e4fSDavid du Colombier 	int	received;
399a747e4fSDavid du Colombier 	int	ref;
409a747e4fSDavid du Colombier 	Tag	*next;
419a747e4fSDavid du Colombier };
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier typedef struct Message Message;
449a747e4fSDavid du Colombier struct Message
459a747e4fSDavid du Colombier {
469a747e4fSDavid du Colombier 	char	*data;
479a747e4fSDavid du Colombier 	int	n;
489a747e4fSDavid du Colombier };
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier typedef struct Fid Fid;
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier struct Fid
539a747e4fSDavid du Colombier {
549a747e4fSDavid du Colombier 	short	busy;
559a747e4fSDavid du Colombier 	short	allocated;
569a747e4fSDavid du Colombier 	int	fid;
579a747e4fSDavid du Colombier 	Qid	qid;
589a747e4fSDavid du Colombier 	ulong	newoffset;
599a747e4fSDavid du Colombier 	ulong	oldoffset;
609a747e4fSDavid du Colombier 	Fid	*next;
619a747e4fSDavid du Colombier };
629a747e4fSDavid du Colombier 
639a747e4fSDavid du Colombier Fid	*fids;
649a747e4fSDavid du Colombier Tag	*tags;
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier char	*rflush(Fcall*, Fcall*, char*),
679a747e4fSDavid du Colombier 	*rversion(Fcall*, Fcall*, char*),
689a747e4fSDavid du Colombier 	*rauth(Fcall*, Fcall*, char*),
699a747e4fSDavid du Colombier 	*rattach(Fcall*, Fcall*, char*),
709a747e4fSDavid du Colombier 	*rwalk(Fcall*, Fcall*, char*),
719a747e4fSDavid du Colombier 	*ropen(Fcall*, Fcall*, char*),
729a747e4fSDavid du Colombier 	*rcreate(Fcall*, Fcall*, char*),
739a747e4fSDavid du Colombier 	*rread(Fcall*, Fcall*, char*),
749a747e4fSDavid du Colombier 	*rwrite(Fcall*, Fcall*, char*),
759a747e4fSDavid du Colombier 	*rclunk(Fcall*, Fcall*, char*),
769a747e4fSDavid du Colombier 	*rremove(Fcall*, Fcall*, char*),
779a747e4fSDavid du Colombier 	*rstat(Fcall*, Fcall*, char*),
789a747e4fSDavid du Colombier 	*rwstat(Fcall*, Fcall*, char*);
799a747e4fSDavid du Colombier 
809a747e4fSDavid du Colombier char 	*(*fcalls[])(Fcall*, Fcall*, char*) = {
819a747e4fSDavid du Colombier 	[Tversion]	rversion,
829a747e4fSDavid du Colombier 	[Tflush]	rflush,
839a747e4fSDavid du Colombier 	[Tauth]	rauth,
849a747e4fSDavid du Colombier 	[Tattach]	rattach,
859a747e4fSDavid du Colombier 	[Twalk]		rwalk,
869a747e4fSDavid du Colombier 	[Topen]		ropen,
879a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
889a747e4fSDavid du Colombier 	[Tread]		rread,
899a747e4fSDavid du Colombier 	[Twrite]	rwrite,
909a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
919a747e4fSDavid du Colombier 	[Tremove]	rremove,
929a747e4fSDavid du Colombier 	[Tstat]		rstat,
939a747e4fSDavid du Colombier 	[Twstat]	rwstat,
949a747e4fSDavid du Colombier };
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier char Etoolong[] = "name too long";
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier void	connect(int, char*);
999a747e4fSDavid du Colombier void	post(int, char*);
1009a747e4fSDavid du Colombier void	serve(void);
1019a747e4fSDavid du Colombier void	demux(void);
1029a747e4fSDavid du Colombier void*	emalloc(ulong);
1039a747e4fSDavid du Colombier char*	transact9p1(Fcall9p1*, Fcall9p1*, char*);
1049a747e4fSDavid du Colombier Fid*	newfid(int);
1059a747e4fSDavid du Colombier 
1069a747e4fSDavid du Colombier struct
1079a747e4fSDavid du Colombier {
1089a747e4fSDavid du Colombier 	char	chal[CHALLEN];		/* my challenge */
1099a747e4fSDavid du Colombier 	char	rchal[CHALLEN];		/* his challenge */
1109a747e4fSDavid du Colombier 	char	authid[NAMEREC];
1119a747e4fSDavid du Colombier 	char	authdom[DOMLEN];
1129a747e4fSDavid du Colombier 	int	id;
1139a747e4fSDavid du Colombier } ai;
1149a747e4fSDavid du Colombier 
1159a747e4fSDavid du Colombier void
usage(void)1169a747e4fSDavid du Colombier usage(void)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier 	fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n");
1199a747e4fSDavid du Colombier 	exits("usage");
1209a747e4fSDavid du Colombier }
1219a747e4fSDavid du Colombier 
1229a747e4fSDavid du Colombier void
main(int argc,char * argv[])1239a747e4fSDavid du Colombier main(int argc, char *argv[])
1249a747e4fSDavid du Colombier {
1259a747e4fSDavid du Colombier 	int method;
1269a747e4fSDavid du Colombier 	char *oldstring;
1279a747e4fSDavid du Colombier 	char *mountpoint, *postname;
1289a747e4fSDavid du Colombier 	int mountflag, mountfd;
1299a747e4fSDavid du Colombier 	int p[2];
1309a747e4fSDavid du Colombier int i;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
1339a747e4fSDavid du Colombier 	fmtinstall('G', fcallfmt9p1);
1349a747e4fSDavid du Colombier 	fmtinstall('D', dirfmt);
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 	user = getuser();
1379a747e4fSDavid du Colombier 	mountpoint = nil;
1389a747e4fSDavid du Colombier 	mountflag = 0;
1399a747e4fSDavid du Colombier 	postname = nil;
1409a747e4fSDavid du Colombier 	oldstring = nil;
1419a747e4fSDavid du Colombier 	method = -1;
1429a747e4fSDavid du Colombier 	mountfd = -1;
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	ARGBEGIN{
1459a747e4fSDavid du Colombier 	case 'a':
1469a747e4fSDavid du Colombier 		mountflag |= MAFTER;
1479a747e4fSDavid du Colombier 		break;
1489a747e4fSDavid du Colombier 	case 'b':
1499a747e4fSDavid du Colombier 		mountflag |= MBEFORE;
1509a747e4fSDavid du Colombier 		break;
1519a747e4fSDavid du Colombier 	case 'c':
1529a747e4fSDavid du Colombier 		mountflag |= MCREATE;
1539a747e4fSDavid du Colombier 		break;
1549a747e4fSDavid du Colombier 	case 'C':
1559a747e4fSDavid du Colombier 		mountflag |= MCACHE;
1569a747e4fSDavid du Colombier 		break;
1579a747e4fSDavid du Colombier 	case 'd':
1589a747e4fSDavid du Colombier 		debug++;
1599a747e4fSDavid du Colombier 		break;
1609a747e4fSDavid du Colombier 	case 'f':
1619a747e4fSDavid du Colombier 		method = File;
1629a747e4fSDavid du Colombier 		oldstring = ARGF();
1639a747e4fSDavid du Colombier 		break;
1649a747e4fSDavid du Colombier 	case 'F':
1659a747e4fSDavid du Colombier 		dofcall++;
1669a747e4fSDavid du Colombier 		break;
1679a747e4fSDavid du Colombier 	case 'm':
1689a747e4fSDavid du Colombier 		mountpoint = EARGF(usage());
1699a747e4fSDavid du Colombier 		break;
1709a747e4fSDavid du Colombier 	case 'n':
1719a747e4fSDavid du Colombier 		method = Network;
1729a747e4fSDavid du Colombier 		oldstring = ARGF();
1739a747e4fSDavid du Colombier 		break;
1749a747e4fSDavid du Colombier 	case 'p':
1759a747e4fSDavid du Colombier 		postname = ARGF();
1769a747e4fSDavid du Colombier 		if(postname == nil)
1779a747e4fSDavid du Colombier 			usage();
1789a747e4fSDavid du Colombier 		break;
1799a747e4fSDavid du Colombier 	case 's':
1809a747e4fSDavid du Colombier 		method = Stdio;
1819a747e4fSDavid du Colombier 		break;
1829a747e4fSDavid du Colombier 	case 'u':
1839a747e4fSDavid du Colombier 		user = EARGF(usage());
1849a747e4fSDavid du Colombier 		break;
1859a747e4fSDavid du Colombier 	case 'x':
1869a747e4fSDavid du Colombier 		method = Command;
1879a747e4fSDavid du Colombier 		oldstring = ARGF();
1889a747e4fSDavid du Colombier 		break;
1899a747e4fSDavid du Colombier 	default:
1909a747e4fSDavid du Colombier 		usage();
1919a747e4fSDavid du Colombier 	}ARGEND;
1929a747e4fSDavid du Colombier 
1939a747e4fSDavid du Colombier 	if(method == Stdio){
1949a747e4fSDavid du Colombier 		if(mountpoint!=nil || argc!=0)
1959a747e4fSDavid du Colombier 			usage();
1969a747e4fSDavid du Colombier 	}else{
1979a747e4fSDavid du Colombier 		if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil))
1989a747e4fSDavid du Colombier 			usage();
1999a747e4fSDavid du Colombier 	}
2009a747e4fSDavid du Colombier 
2019a747e4fSDavid du Colombier 	rfork(RFNOTEG|RFREND);
2029a747e4fSDavid du Colombier 
2039a747e4fSDavid du Colombier 	connect(method, oldstring);
2049a747e4fSDavid du Colombier 
2059a747e4fSDavid du Colombier 	if(method == Stdio)
2069a747e4fSDavid du Colombier 		newfd = 0;
2079a747e4fSDavid du Colombier 	else{
2089a747e4fSDavid du Colombier 		if(pipe(p) < 0)
2099a747e4fSDavid du Colombier 			fatal("pipe: %r");
2109a747e4fSDavid du Colombier 		if(postname != nil)
2119a747e4fSDavid du Colombier 			post(p[0], postname);
2129a747e4fSDavid du Colombier 		mountfd = p[0];
2139a747e4fSDavid du Colombier 		newfd = p[1];
2149a747e4fSDavid du Colombier 	}
2159a747e4fSDavid du Colombier 	if(debug)
2169a747e4fSDavid du Colombier 		fprint(2, "connected and posted\n");
2179a747e4fSDavid du Colombier 
2189a747e4fSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){
2199a747e4fSDavid du Colombier 	case 0:
2209a747e4fSDavid du Colombier 		mainpid = getpid();
2219a747e4fSDavid du Colombier 		/* child does all the work */
2229a747e4fSDavid du Colombier 		if(mountfd >= 0)
2239a747e4fSDavid du Colombier 			close(mountfd);
2249a747e4fSDavid du Colombier 		switch(rfork(RFPROC|RFMEM|RFFDG)){
2259a747e4fSDavid du Colombier 		case 0:
2269a747e4fSDavid du Colombier 			for(i = 0; i < 20; i++)
2279a747e4fSDavid du Colombier 				if (i != roldfd) close(i);
2289a747e4fSDavid du Colombier 			demux();
2299a747e4fSDavid du Colombier 			return;
2309a747e4fSDavid du Colombier 		case -1:
2319a747e4fSDavid du Colombier 			fatal("fork error: %r");
2329a747e4fSDavid du Colombier 			break;
2339a747e4fSDavid du Colombier 		}
2349a747e4fSDavid du Colombier 		for(i = 0; i < 20; i++)
2359a747e4fSDavid du Colombier 			if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i);
2369a747e4fSDavid du Colombier 		serve();
2379a747e4fSDavid du Colombier 		break;
2389a747e4fSDavid du Colombier 	case -1:
2399a747e4fSDavid du Colombier 		fatal("fork error: %r");
2409a747e4fSDavid du Colombier 		break;
2419a747e4fSDavid du Colombier 	default:
2429a747e4fSDavid du Colombier 		/* parent mounts if required, then exits */
2439a747e4fSDavid du Colombier 		if(mountpoint){
2449a747e4fSDavid du Colombier 			if(mount(mountfd, -1, mountpoint, mountflag, "") < 0)
2459a747e4fSDavid du Colombier 				fatal("can't mount: %r");
2469a747e4fSDavid du Colombier 		}
2479a747e4fSDavid du Colombier 		break;
2489a747e4fSDavid du Colombier 	}
2499a747e4fSDavid du Colombier 	exits(nil);
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier 
2529a747e4fSDavid du Colombier void
connect(int method,char * oldstring)2539a747e4fSDavid du Colombier connect(int method, char *oldstring)
2549a747e4fSDavid du Colombier {
2559a747e4fSDavid du Colombier 	char *s;
2569a747e4fSDavid du Colombier 	char dir[256];
2579a747e4fSDavid du Colombier 
2589a747e4fSDavid du Colombier 	switch(method){
2599a747e4fSDavid du Colombier 	default:
2609a747e4fSDavid du Colombier 		roldfd = -1;
2619a747e4fSDavid du Colombier 		woldfd = -1;
2629a747e4fSDavid du Colombier 		fatal("can't handle method type %d", method);
2639a747e4fSDavid du Colombier 		break;
2649a747e4fSDavid du Colombier 	case Network:
2659a747e4fSDavid du Colombier 		s = netmkaddr(oldstring, 0, "9fs");
2669a747e4fSDavid du Colombier 		roldfd = dial(s, 0, dir, 0);
2679a747e4fSDavid du Colombier 		if(roldfd < 0)
2689a747e4fSDavid du Colombier 			fatal("dial %s: %r", s);
2699a747e4fSDavid du Colombier 		woldfd = roldfd;
2709a747e4fSDavid du Colombier 		if(dofcall)
2719a747e4fSDavid du Colombier 			roldfd = fcall(woldfd);
2729a747e4fSDavid du Colombier 		break;
2739a747e4fSDavid du Colombier 	case File:
2749a747e4fSDavid du Colombier 		roldfd = open(oldstring, ORDWR);
2759a747e4fSDavid du Colombier 		if(roldfd < 0)
2769a747e4fSDavid du Colombier 			fatal("can't open %s: %r", oldstring);
2779a747e4fSDavid du Colombier 		woldfd = roldfd;
2789a747e4fSDavid du Colombier 		if(dofcall)
2799a747e4fSDavid du Colombier 			roldfd = fcall(woldfd);
2809a747e4fSDavid du Colombier 		break;
2819a747e4fSDavid du Colombier 	case Stdio:
2829a747e4fSDavid du Colombier 		roldfd = fcall(1);
2839a747e4fSDavid du Colombier 		woldfd = 1;
2849a747e4fSDavid du Colombier 		break;
2859a747e4fSDavid du Colombier 	}
2869a747e4fSDavid du Colombier }
2879a747e4fSDavid du Colombier 
2889a747e4fSDavid du Colombier void
post(int fd,char * srv)2899a747e4fSDavid du Colombier post(int fd, char *srv)
2909a747e4fSDavid du Colombier {
2919a747e4fSDavid du Colombier 	int f;
2929a747e4fSDavid du Colombier 	char buf[128];
2939a747e4fSDavid du Colombier 
2949a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "/srv/%s", srv);
2959a747e4fSDavid du Colombier 	f = create(buf, OWRITE, 0666);
2969a747e4fSDavid du Colombier 	if(f < 0)
2979a747e4fSDavid du Colombier 		fatal("can't create %s: %r", buf);
2989a747e4fSDavid du Colombier 	sprint(buf, "%d", fd);
2999a747e4fSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
3009a747e4fSDavid du Colombier 		fatal("post write: %r");
3019a747e4fSDavid du Colombier 	close(f);
3029a747e4fSDavid du Colombier }
3039a747e4fSDavid du Colombier 
3049a747e4fSDavid du Colombier Fid *
newfid(int fid)3059a747e4fSDavid du Colombier newfid(int fid)
3069a747e4fSDavid du Colombier {
3079a747e4fSDavid du Colombier 	Fid *f, *ff;
3089a747e4fSDavid du Colombier 
3099a747e4fSDavid du Colombier 	ff = 0;
3109a747e4fSDavid du Colombier 	qlock(&fidlock);
3119a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
3129a747e4fSDavid du Colombier 		if(f->fid == fid){
3139a747e4fSDavid du Colombier 			f->allocated = 1;
3149a747e4fSDavid du Colombier 			qunlock(&fidlock);
3159a747e4fSDavid du Colombier 			return f;
3169a747e4fSDavid du Colombier 		}
3179a747e4fSDavid du Colombier 		else if(!ff && !f->allocated)
3189a747e4fSDavid du Colombier 			ff = f;
3199a747e4fSDavid du Colombier 	if(ff){
3209a747e4fSDavid du Colombier 		ff->fid = fid;
3219a747e4fSDavid du Colombier 		ff->allocated = 1;
3229a747e4fSDavid du Colombier 		qunlock(&fidlock);
3239a747e4fSDavid du Colombier 		return ff;
3249a747e4fSDavid du Colombier 	}
3259a747e4fSDavid du Colombier 	f = emalloc(sizeof *f);
3269a747e4fSDavid du Colombier 	f->fid = fid;
3279a747e4fSDavid du Colombier 	f->next = fids;
3289a747e4fSDavid du Colombier 	f->allocated = 1;
3299a747e4fSDavid du Colombier 	fids = f;
3309a747e4fSDavid du Colombier 	qunlock(&fidlock);
3319a747e4fSDavid du Colombier 	return f;
3329a747e4fSDavid du Colombier }
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier /*
3359a747e4fSDavid du Colombier  * Reads returning 9P1 messages and demultiplexes them.
3369a747e4fSDavid du Colombier  * BUG: assumes one read per message.
3379a747e4fSDavid du Colombier  */
3389a747e4fSDavid du Colombier void
demux(void)3399a747e4fSDavid du Colombier demux(void)
3409a747e4fSDavid du Colombier {
3419a747e4fSDavid du Colombier 	int m, n;
3429a747e4fSDavid du Colombier 	char *data;
3439a747e4fSDavid du Colombier 	Fcall9p1 r;
3449a747e4fSDavid du Colombier 	Message *msg;
3459a747e4fSDavid du Colombier 	Tag *t;
3469a747e4fSDavid du Colombier 
3479a747e4fSDavid du Colombier 	for(;;){
3489a747e4fSDavid du Colombier 		data = malloc(IOHDRSZ+Maxfdata);	/* no need to clear memory */
3499a747e4fSDavid du Colombier 		if(data == nil)
3509a747e4fSDavid du Colombier 			fatal("demux malloc: %r");
3519a747e4fSDavid du Colombier 		m = read(roldfd, data, IOHDRSZ+Maxfdata);
3529a747e4fSDavid du Colombier 		if(m <= 0)
3539a747e4fSDavid du Colombier 			fatal("read error talking to old system: %r");
3549a747e4fSDavid du Colombier 		n = convM2S9p1(data, &r, m);
3559a747e4fSDavid du Colombier 		if(n == 0)
3569a747e4fSDavid du Colombier 			fatal("bad conversion receiving from old system");
3579a747e4fSDavid du Colombier 		if(debug)
3589a747e4fSDavid du Colombier 			fprint(2, "srvold9p:<=%G\n", &r);
3599a747e4fSDavid du Colombier 		qlock(&taglock);
3609a747e4fSDavid du Colombier 		for(t=tags; t!=nil; t=t->next)
3619a747e4fSDavid du Colombier 			if(t->tag == r.tag){
3629a747e4fSDavid du Colombier 				t->received = 1;
3639a747e4fSDavid du Colombier 				break;
3649a747e4fSDavid du Colombier 			}
3659a747e4fSDavid du Colombier 		qunlock(&taglock);
3669a747e4fSDavid du Colombier 		/*
3679a747e4fSDavid du Colombier 		 * Fcall9p1 tag is used to rendezvous.
3689a747e4fSDavid du Colombier 		 * Recipient converts message a second time, but that's OK.
3699a747e4fSDavid du Colombier 		 */
3709a747e4fSDavid du Colombier 		msg = emalloc(sizeof(Message));
3719a747e4fSDavid du Colombier 		msg->data = data;
3729a747e4fSDavid du Colombier 		msg->n = n;
373*74f16c81SDavid du Colombier 		rendezvous((void*)r.tag, msg);
3749a747e4fSDavid du Colombier 	}
3759a747e4fSDavid du Colombier }
3769a747e4fSDavid du Colombier 
3779a747e4fSDavid du Colombier Tag*
newtag(int tag)3789a747e4fSDavid du Colombier newtag(int tag)
3799a747e4fSDavid du Colombier {
3809a747e4fSDavid du Colombier 	Tag *t;
3819a747e4fSDavid du Colombier 
3829a747e4fSDavid du Colombier 	t = emalloc(sizeof(Tag));
3839a747e4fSDavid du Colombier 	t->tag = tag;
3849a747e4fSDavid du Colombier 	t->flushed = 0;
3859a747e4fSDavid du Colombier 	t->received = 0;
3869a747e4fSDavid du Colombier 	t->ref = 1;
3879a747e4fSDavid du Colombier 	qlock(&taglock);
3889a747e4fSDavid du Colombier 	t->next = tags;
3899a747e4fSDavid du Colombier 	tags = t;
3909a747e4fSDavid du Colombier 	qunlock(&taglock);
3919a747e4fSDavid du Colombier 	return t;
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier void
freetag(Tag * tag)3959a747e4fSDavid du Colombier freetag(Tag *tag)	/* called with taglock set */
3969a747e4fSDavid du Colombier {
3979a747e4fSDavid du Colombier 	Tag *t, *prev;
3989a747e4fSDavid du Colombier 
3999a747e4fSDavid du Colombier 	if(tag->ref-- == 1){
4009a747e4fSDavid du Colombier 		prev = nil;
4019a747e4fSDavid du Colombier 		for(t=tags; t!=nil; t=t->next){
4029a747e4fSDavid du Colombier 			if(t == tag){
4039a747e4fSDavid du Colombier 				if(prev == nil)
4049a747e4fSDavid du Colombier 					tags = t->next;
4059a747e4fSDavid du Colombier 				else
4069a747e4fSDavid du Colombier 					prev->next = t->next;
4079a747e4fSDavid du Colombier 				break;
4089a747e4fSDavid du Colombier 			}
4099a747e4fSDavid du Colombier 			prev = t;
4109a747e4fSDavid du Colombier 		}
4119a747e4fSDavid du Colombier 		if(t == nil)
4129a747e4fSDavid du Colombier 			sysfatal("freetag");
4139a747e4fSDavid du Colombier 		free(tag);
4149a747e4fSDavid du Colombier 	}
4159a747e4fSDavid du Colombier }
4169a747e4fSDavid du Colombier 
4179a747e4fSDavid du Colombier void
serve(void)4189a747e4fSDavid du Colombier serve(void)
4199a747e4fSDavid du Colombier {
4209a747e4fSDavid du Colombier 	char *err;
4219a747e4fSDavid du Colombier 	int n;
4229a747e4fSDavid du Colombier 	Fcall thdr;
4239a747e4fSDavid du Colombier 	Fcall	rhdr;
4249a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ+Maxfdata];
4259a747e4fSDavid du Colombier 	char mdata9p1[IOHDRSZ+Maxfdata];
4269a747e4fSDavid du Colombier 	Tag *tag;
4279a747e4fSDavid du Colombier 
4289a747e4fSDavid du Colombier 	for(;;){
4299a747e4fSDavid du Colombier 		qlock(&servelock);
4309a747e4fSDavid du Colombier 		for(;;){
4319a747e4fSDavid du Colombier 			n = read9pmsg(newfd, mdata, sizeof mdata);
4329a747e4fSDavid du Colombier 
4339a747e4fSDavid du Colombier 			if(n == 0)
4349a747e4fSDavid du Colombier 				continue;
4359a747e4fSDavid du Colombier 			if(n < 0)
4369a747e4fSDavid du Colombier 				break;
4379a747e4fSDavid du Colombier 			if(n > 0 && convM2S(mdata, n, &thdr) > 0)
4389a747e4fSDavid du Colombier 				break;
4399a747e4fSDavid du Colombier 		}
4409a747e4fSDavid du Colombier 		if(n>0 && servelock.head==nil)	/* no other processes waiting to read */
4419a747e4fSDavid du Colombier 			switch(rfork(RFPROC|RFMEM)){
4429a747e4fSDavid du Colombier 			case 0:
4439a747e4fSDavid du Colombier 				/* child starts serving */
4449a747e4fSDavid du Colombier 				continue;
4459a747e4fSDavid du Colombier 				break;
4469a747e4fSDavid du Colombier 			case -1:
4479a747e4fSDavid du Colombier 				fatal("fork error: %r");
4489a747e4fSDavid du Colombier 				break;
4499a747e4fSDavid du Colombier 			default:
4509a747e4fSDavid du Colombier 				break;
4519a747e4fSDavid du Colombier 			}
4529a747e4fSDavid du Colombier 		qunlock(&servelock);
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier 		if(n < 0)
4559a747e4fSDavid du Colombier 			fatal(nil);	/* exit quietly; remote end has just hung up */
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 		if(debug)
4589a747e4fSDavid du Colombier 			fprint(2, "srvold9p:<-%F\n", &thdr);
4599a747e4fSDavid du Colombier 
4609a747e4fSDavid du Colombier 		tag = newtag(thdr.tag);
4619a747e4fSDavid du Colombier 
4629a747e4fSDavid du Colombier 		if(!fcalls[thdr.type])
4639a747e4fSDavid du Colombier 			err = "bad fcall type";
4649a747e4fSDavid du Colombier 		else
4659a747e4fSDavid du Colombier 			err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1);
4669a747e4fSDavid du Colombier 
4679a747e4fSDavid du Colombier 		qlock(&taglock);
4689a747e4fSDavid du Colombier 		if(tag->flushed){
4699a747e4fSDavid du Colombier 			freetag(tag);
4709a747e4fSDavid du Colombier 			qunlock(&taglock);
4719a747e4fSDavid du Colombier 			continue;
4729a747e4fSDavid du Colombier 		}
4739a747e4fSDavid du Colombier 		qunlock(&taglock);
4749a747e4fSDavid du Colombier 
4759a747e4fSDavid du Colombier 		if(err){
4769a747e4fSDavid du Colombier 			rhdr.type = Rerror;
4779a747e4fSDavid du Colombier 			rhdr.ename = err;
4789a747e4fSDavid du Colombier 		}else{
4799a747e4fSDavid du Colombier 			rhdr.type = thdr.type + 1;
4809a747e4fSDavid du Colombier 			rhdr.fid = thdr.fid;
4819a747e4fSDavid du Colombier 		}
4829a747e4fSDavid du Colombier 		rhdr.tag = thdr.tag;
4839a747e4fSDavid du Colombier 		if(debug)
4849a747e4fSDavid du Colombier 			fprint(2, "srvold9p:->%F\n", &rhdr);/**/
4859a747e4fSDavid du Colombier 		n = convS2M(&rhdr, mdata, sizeof mdata);
4869a747e4fSDavid du Colombier 		if(n == 0)
4879a747e4fSDavid du Colombier 			fatal("convS2M error on write");
4889a747e4fSDavid du Colombier 		if(write(newfd, mdata, n) != n)
4899a747e4fSDavid du Colombier 			fatal("mount write");
4909a747e4fSDavid du Colombier 
4919a747e4fSDavid du Colombier 		qlock(&taglock);
4929a747e4fSDavid du Colombier 		freetag(tag);
4939a747e4fSDavid du Colombier 		qunlock(&taglock);
4949a747e4fSDavid du Colombier 	}
4959a747e4fSDavid du Colombier }
4969a747e4fSDavid du Colombier 
4979a747e4fSDavid du Colombier void
send9p1(Fcall9p1 * t,char * data)4989a747e4fSDavid du Colombier send9p1(Fcall9p1 *t, char *data)
4999a747e4fSDavid du Colombier {
5009a747e4fSDavid du Colombier 	int m, n;
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier 	if(debug)
5039a747e4fSDavid du Colombier 		fprint(2, "srvold9p:=>%G\n", t);
5049a747e4fSDavid du Colombier 	n = convS2M9p1(t, data);
5059a747e4fSDavid du Colombier 	if(n == 0)
5069a747e4fSDavid du Colombier 		fatal("bad conversion sending to old system");
5079a747e4fSDavid du Colombier 	m = write(woldfd, data, n);
5089a747e4fSDavid du Colombier 	if(m != n)
5099a747e4fSDavid du Colombier 		fatal("wrote %d to old system; should be %d", m, n);
5109a747e4fSDavid du Colombier }
5119a747e4fSDavid du Colombier 
5129a747e4fSDavid du Colombier int
recv9p1(Fcall9p1 * r,int tag,char * data)5139a747e4fSDavid du Colombier recv9p1(Fcall9p1 *r, int tag, char *data)
5149a747e4fSDavid du Colombier {
5159a747e4fSDavid du Colombier 	int n;
5169a747e4fSDavid du Colombier 	Message *msg;
5179a747e4fSDavid du Colombier 
518*74f16c81SDavid du Colombier 	msg = rendezvous((void*)tag, 0);
519*74f16c81SDavid du Colombier 	if(msg == (void*)~0)
5209a747e4fSDavid du Colombier 		fatal("rendezvous: %r");
5219a747e4fSDavid du Colombier 	if(msg == nil){
5229a747e4fSDavid du Colombier 		if(debug)
5239a747e4fSDavid du Colombier 			fprint(2, "recv flushed\n");
5249a747e4fSDavid du Colombier 		return -1;
5259a747e4fSDavid du Colombier 	}
5269a747e4fSDavid du Colombier 	/* copy data to local buffer */
5279a747e4fSDavid du Colombier 	memmove(data, msg->data, msg->n);
5289a747e4fSDavid du Colombier 	n = convM2S9p1(data, r, msg->n);
5299a747e4fSDavid du Colombier 	if(n == 0)
5309a747e4fSDavid du Colombier 		fatal("bad conversion receiving from old system");
5319a747e4fSDavid du Colombier 	free(msg->data);
5329a747e4fSDavid du Colombier 	free(msg);
5339a747e4fSDavid du Colombier 	return 1;
5349a747e4fSDavid du Colombier }
5359a747e4fSDavid du Colombier 
5369a747e4fSDavid du Colombier char*
transact9p1(Fcall9p1 * t,Fcall9p1 * r,char * mdata9p1)5379a747e4fSDavid du Colombier transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1)
5389a747e4fSDavid du Colombier {
5399a747e4fSDavid du Colombier 	send9p1(t, mdata9p1);
5409a747e4fSDavid du Colombier 	if(recv9p1(r, t->tag, mdata9p1) < 0)
5419a747e4fSDavid du Colombier 		return FLUSHED;
5429a747e4fSDavid du Colombier 	if(r->type == Rerror9p1)
5439a747e4fSDavid du Colombier 		return r->ename;
5449a747e4fSDavid du Colombier 	if(r->type != t->type+1)
5459a747e4fSDavid du Colombier 		fatal("bad message type; expected %d got %d", t->type+1, r->type);
5469a747e4fSDavid du Colombier 	return nil;
5479a747e4fSDavid du Colombier }
5489a747e4fSDavid du Colombier 
5499a747e4fSDavid du Colombier char*
rflush(Fcall * t,Fcall *,char * mdata9p1)5509a747e4fSDavid du Colombier rflush(Fcall *t, Fcall *, char *mdata9p1)
5519a747e4fSDavid du Colombier {
5529a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
5539a747e4fSDavid du Colombier 	Tag *oldt;
5549a747e4fSDavid du Colombier 
5559a747e4fSDavid du Colombier 	t9.type = Tflush9p1;
5569a747e4fSDavid du Colombier 	t9.tag = t->tag;
5579a747e4fSDavid du Colombier 	t9.oldtag = t->oldtag;
5589a747e4fSDavid du Colombier 	qlock(&taglock);
5599a747e4fSDavid du Colombier 	for(oldt=tags; oldt!=nil; oldt=oldt->next)
5609a747e4fSDavid du Colombier 		if(oldt->tag == t->oldtag){
5619a747e4fSDavid du Colombier 			oldt->flushed = 1;
5629a747e4fSDavid du Colombier 			oldt->ref++;
5639a747e4fSDavid du Colombier 			break;
5649a747e4fSDavid du Colombier 		}
5659a747e4fSDavid du Colombier 	qunlock(&taglock);
5669a747e4fSDavid du Colombier 
5679a747e4fSDavid du Colombier 	if(oldt == nil){	/* nothing to flush */
5689a747e4fSDavid du Colombier 		if(debug)
5699a747e4fSDavid du Colombier 			fprint(2, "no such tag to flush\n");
5709a747e4fSDavid du Colombier 		return 0;
5719a747e4fSDavid du Colombier 	}
5729a747e4fSDavid du Colombier 
5739a747e4fSDavid du Colombier 	transact9p1(&t9, &r9, mdata9p1);	/* can't error */
5749a747e4fSDavid du Colombier 
5759a747e4fSDavid du Colombier 	qlock(&taglock);
5769a747e4fSDavid du Colombier 	if(oldt->received == 0){	/* wake up receiver */
5779a747e4fSDavid du Colombier 		if(debug)
5789a747e4fSDavid du Colombier 			fprint(2, "wake up receiver\n");
5799a747e4fSDavid du Colombier 		oldt->received = 1;
580*74f16c81SDavid du Colombier 		rendezvous((void*)t->oldtag, 0);
5819a747e4fSDavid du Colombier 	}
5829a747e4fSDavid du Colombier 	freetag(oldt);
5839a747e4fSDavid du Colombier 	qunlock(&taglock);
5849a747e4fSDavid du Colombier 	return 0;
5859a747e4fSDavid du Colombier }
5869a747e4fSDavid du Colombier 
5879a747e4fSDavid du Colombier char*
rversion(Fcall * t,Fcall * r,char *)5889a747e4fSDavid du Colombier rversion(Fcall *t, Fcall *r, char*)
5899a747e4fSDavid du Colombier {
5909a747e4fSDavid du Colombier 	Fid *f;
5919a747e4fSDavid du Colombier 
5929a747e4fSDavid du Colombier 	/* just ack; this one doesn't go to old service */
5939a747e4fSDavid du Colombier 	if(t->msize > IOHDRSZ+Maxfdata)
5949a747e4fSDavid du Colombier 		r->msize = IOHDRSZ+Maxfdata;
5959a747e4fSDavid du Colombier 	else
5969a747e4fSDavid du Colombier 		r->msize = t->msize;
5979a747e4fSDavid du Colombier 	if(strncmp(t->version, "9P2000", 6) != 0)
5989a747e4fSDavid du Colombier 		return "unknown 9P version";
5999a747e4fSDavid du Colombier 	r->version = "9P2000";
6009a747e4fSDavid du Colombier 
6019a747e4fSDavid du Colombier 	qlock(&fidlock);
6029a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next){
6039a747e4fSDavid du Colombier 		f->busy = 0;
6049a747e4fSDavid du Colombier 		f->allocated = 0;
6059a747e4fSDavid du Colombier 	}
6069a747e4fSDavid du Colombier 	qunlock(&fidlock);
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier 	return 0;
6099a747e4fSDavid du Colombier }
6109a747e4fSDavid du Colombier 
6119a747e4fSDavid du Colombier char*
rauth(Fcall *,Fcall *,char *)6129a747e4fSDavid du Colombier rauth(Fcall *, Fcall *, char *)
6139a747e4fSDavid du Colombier {
6149a747e4fSDavid du Colombier 	return "srvold9p: authentication not supported";
6159a747e4fSDavid du Colombier }
6169a747e4fSDavid du Colombier 
6179a747e4fSDavid du Colombier #ifdef asdf
6189a747e4fSDavid du Colombier 
6199a747e4fSDavid du Colombier void
memrandom(void * p,int n)6209a747e4fSDavid du Colombier memrandom(void *p, int n)
6219a747e4fSDavid du Colombier {
6229a747e4fSDavid du Colombier 	ulong *lp;
6239a747e4fSDavid du Colombier 	uchar *cp;
6249a747e4fSDavid du Colombier 
6259a747e4fSDavid du Colombier 	for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong))
6269a747e4fSDavid du Colombier 		*lp++ = fastrand();
6279a747e4fSDavid du Colombier 	for(cp = (uchar*)lp; n > 0; n--)
6289a747e4fSDavid du Colombier 		*cp++ = fastrand();
6299a747e4fSDavid du Colombier }
6309a747e4fSDavid du Colombier 
6319a747e4fSDavid du Colombier char*
rsession(Fcall * t,Fcall * r,char * mdata9p1)6329a747e4fSDavid du Colombier rsession(Fcall *t, Fcall *r, char *mdata9p1)
6339a747e4fSDavid du Colombier {
6349a747e4fSDavid du Colombier 	char *err;
6359a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
6369a747e4fSDavid du Colombier 	Fid *f;
6379a747e4fSDavid du Colombier 
6389a747e4fSDavid du Colombier 	t9.type = Tsession9p1;
6399a747e4fSDavid du Colombier 	t9.tag = t->tag;
6409a747e4fSDavid du Colombier 	if(doauth)
6419a747e4fSDavid du Colombier 		memrandom(t9.chal, sizeof t9.chal);
6429a747e4fSDavid du Colombier 	else
6439a747e4fSDavid du Colombier 		memset(t9.chal, 0, sizeof t9.chal);
6449a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
6459a747e4fSDavid du Colombier 	if(err)
6469a747e4fSDavid du Colombier 		return err;
6479a747e4fSDavid du Colombier 
6489a747e4fSDavid du Colombier 	qlock(&fidlock);
6499a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next){
6509a747e4fSDavid du Colombier 		f->busy = 0;
6519a747e4fSDavid du Colombier 		f->allocated = 0;
6529a747e4fSDavid du Colombier 	}
6539a747e4fSDavid du Colombier 	qunlock(&fidlock);
6549a747e4fSDavid du Colombier 
6559a747e4fSDavid du Colombier 	if(doauth){
6569a747e4fSDavid du Colombier 		memmove(ai.authid, r9.authid, sizeof ai.authid);
6579a747e4fSDavid du Colombier 		memmove(ai.authdom, r9.authdom, sizeof ai.authid);
6589a747e4fSDavid du Colombier 		memmove(ai.rchal, r9.chal, sizeof ai.rchal);
6599a747e4fSDavid du Colombier 		memmove(ai.chal, t9.chal, sizeof ai.chal);
6609a747e4fSDavid du Colombier 		r->authid = ai.authid;
6619a747e4fSDavid du Colombier 		r->authdom = ai.authdom;
6629a747e4fSDavid du Colombier 		r->chal = (uchar*)ai.rchal;
6639a747e4fSDavid du Colombier 		r->nchal = CHALLEN;
6649a747e4fSDavid du Colombier 	} else {
6659a747e4fSDavid du Colombier 		r->authid = "";
6669a747e4fSDavid du Colombier 		r->authdom = "";
6679a747e4fSDavid du Colombier 		r->nchal = 0;
6689a747e4fSDavid du Colombier 		r->chal = nil;
6699a747e4fSDavid du Colombier 	}
6709a747e4fSDavid du Colombier 	return 0;
6719a747e4fSDavid du Colombier }
6729a747e4fSDavid du Colombier #endif
6739a747e4fSDavid du Colombier 
6749a747e4fSDavid du Colombier char*
rattach(Fcall * t,Fcall * r,char * mdata9p1)6759a747e4fSDavid du Colombier rattach(Fcall *t, Fcall *r, char *mdata9p1)
6769a747e4fSDavid du Colombier {
6779a747e4fSDavid du Colombier 	char *err;
6789a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
6799a747e4fSDavid du Colombier 	Fid *f;
6809a747e4fSDavid du Colombier 
6819a747e4fSDavid du Colombier 	f = newfid(t->fid);
6829a747e4fSDavid du Colombier 	if(f->busy)
6839a747e4fSDavid du Colombier 		return "attach: fid in use";
6849a747e4fSDavid du Colombier 	/* no authentication! */
6859a747e4fSDavid du Colombier 	t9.type = Tattach9p1;
6869a747e4fSDavid du Colombier 	t9.tag = t->tag;
6879a747e4fSDavid du Colombier 	t9.fid = t->fid;
6889a747e4fSDavid du Colombier 	strncpy(t9.uname, t->uname, NAMEREC);
6899a747e4fSDavid du Colombier 	if(strcmp(user, "none") == 0)
6909a747e4fSDavid du Colombier 		strncpy(t9.uname, user, NAMEREC);
6919a747e4fSDavid du Colombier 	strncpy(t9.aname, t->aname, NAMEREC);
6929a747e4fSDavid du Colombier 	memset(t9.ticket, 0, sizeof t9.ticket);
6939a747e4fSDavid du Colombier 	memset(t9.auth, 0, sizeof t9.auth);
6949a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
6959a747e4fSDavid du Colombier 	if(err)
6969a747e4fSDavid du Colombier 		return err;
6979a747e4fSDavid du Colombier 
6989a747e4fSDavid du Colombier 	r->qid.path = r9.qid.path & ~0x80000000;
6999a747e4fSDavid du Colombier 	r->qid.vers = r9.qid.version;
7009a747e4fSDavid du Colombier 	r->qid.type = QTDIR;
7019a747e4fSDavid du Colombier 	f->busy = 1;
7029a747e4fSDavid du Colombier 	f->qid = r->qid;
7039a747e4fSDavid du Colombier 	return 0;
7049a747e4fSDavid du Colombier }
7059a747e4fSDavid du Colombier 
7069a747e4fSDavid du Colombier char*
rwalk(Fcall * t,Fcall * r,char * mdata9p1)7079a747e4fSDavid du Colombier rwalk(Fcall *t, Fcall *r, char *mdata9p1)
7089a747e4fSDavid du Colombier {
7099a747e4fSDavid du Colombier 	char *err;
7109a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
7119a747e4fSDavid du Colombier 	int i, fid;
7129a747e4fSDavid du Colombier 	Qid *q;
7139a747e4fSDavid du Colombier 	Fid *f, *nf;
7149a747e4fSDavid du Colombier 
7159a747e4fSDavid du Colombier 	f = newfid(t->fid);
7169a747e4fSDavid du Colombier 	if(!f->busy)
7179a747e4fSDavid du Colombier 		return "walk: bad fid";
7189a747e4fSDavid du Colombier 
7199a747e4fSDavid du Colombier 	fid = t->fid;
7209a747e4fSDavid du Colombier 	nf = nil;
7219a747e4fSDavid du Colombier 	if(t->fid != t->newfid){
7229a747e4fSDavid du Colombier 		nf = newfid(t->newfid);
7239a747e4fSDavid du Colombier 		if(nf->busy)
7249a747e4fSDavid du Colombier 			return "walk: newfid in use";
7259a747e4fSDavid du Colombier 		t9.type = Tclone9p1;
7269a747e4fSDavid du Colombier 		t9.tag = t->tag;
7279a747e4fSDavid du Colombier 		t9.fid = t->fid;
7289a747e4fSDavid du Colombier 		t9.newfid = t->newfid;
7299a747e4fSDavid du Colombier 		err = transact9p1(&t9, &r9, mdata9p1);
7309a747e4fSDavid du Colombier 		if(err){
7319a747e4fSDavid du Colombier 			nf->busy = 0;
7329a747e4fSDavid du Colombier 			nf->allocated = 0;
7339a747e4fSDavid du Colombier 			return err;
7349a747e4fSDavid du Colombier 		}
7359a747e4fSDavid du Colombier 		fid = t->newfid;
7369a747e4fSDavid du Colombier 		nf->busy = 1;
7379a747e4fSDavid du Colombier 	}
7389a747e4fSDavid du Colombier 
7399a747e4fSDavid du Colombier 	err = nil;
7409a747e4fSDavid du Colombier 	r->nwqid = 0;
7419a747e4fSDavid du Colombier 	for(i=0; i<t->nwname && err==nil; i++){
7429a747e4fSDavid du Colombier 		if(i > MAXWELEM)
7439a747e4fSDavid du Colombier 			break;
7449a747e4fSDavid du Colombier 		t9.type = Twalk9p1;
7459a747e4fSDavid du Colombier 		t9.tag = t->tag;
7469a747e4fSDavid du Colombier 		t9.fid = fid;
7479a747e4fSDavid du Colombier 		strncpy(t9.name, t->wname[i], NAMEREC);
7489a747e4fSDavid du Colombier 		err = transact9p1(&t9, &r9, mdata9p1);
7499a747e4fSDavid du Colombier 		if(err == FLUSHED){
7509a747e4fSDavid du Colombier 			i = -1;	/* guarantee cleanup */
7519a747e4fSDavid du Colombier 			break;
7529a747e4fSDavid du Colombier 		}
7539a747e4fSDavid du Colombier 		if(err == nil){
7549a747e4fSDavid du Colombier 			q = &r->wqid[r->nwqid++];
7559a747e4fSDavid du Colombier 			q->type = QTFILE;
7569a747e4fSDavid du Colombier 			if(r9.qid.path & 0x80000000)
7579a747e4fSDavid du Colombier 				q->type = QTDIR;
7589a747e4fSDavid du Colombier 			q->vers = r9.qid.version;
7599a747e4fSDavid du Colombier 			q->path = r9.qid.path & ~0x80000000;
7609a747e4fSDavid du Colombier 		}
7619a747e4fSDavid du Colombier 	}
7629a747e4fSDavid du Colombier 
7639a747e4fSDavid du Colombier 	if(nf!=nil && (err!=nil || i<t->nwname)){
7649a747e4fSDavid du Colombier 		/* clunk the new fid */
7659a747e4fSDavid du Colombier 		t9.type = Tclunk9p1;
7669a747e4fSDavid du Colombier 		t9.tag = t->tag;
7679a747e4fSDavid du Colombier 		t9.fid = t->newfid;
7689a747e4fSDavid du Colombier 		transact9p1(&t9, &r9, mdata9p1);
7699a747e4fSDavid du Colombier 		/* ignore more errors */
7709a747e4fSDavid du Colombier 		nf->busy = 0;
7719a747e4fSDavid du Colombier 		nf->allocated = 0;
7729a747e4fSDavid du Colombier 	}
7739a747e4fSDavid du Colombier 
7749a747e4fSDavid du Colombier 	if(i>0 && i==t->nwname && err==nil)
7759a747e4fSDavid du Colombier 		f->qid = r->wqid[r->nwqid-1];
7769a747e4fSDavid du Colombier 	if(i > 0)
7779a747e4fSDavid du Colombier 		return 0;
7789a747e4fSDavid du Colombier 	return err;
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier 
7819a747e4fSDavid du Colombier char*
ropen(Fcall * t,Fcall * r,char * mdata9p1)7829a747e4fSDavid du Colombier ropen(Fcall *t, Fcall *r, char *mdata9p1)
7839a747e4fSDavid du Colombier {
7849a747e4fSDavid du Colombier 	char *err;
7859a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
7869a747e4fSDavid du Colombier 	Fid *f;
7879a747e4fSDavid du Colombier 
7889a747e4fSDavid du Colombier 	f = newfid(t->fid);
7899a747e4fSDavid du Colombier 	if(!f->busy)
7909a747e4fSDavid du Colombier 		return "open: bad fid";
7919a747e4fSDavid du Colombier 
7929a747e4fSDavid du Colombier 	t9.type = Topen9p1;
7939a747e4fSDavid du Colombier 	t9.tag = t->tag;
7949a747e4fSDavid du Colombier 	t9.fid = t->fid;
7959a747e4fSDavid du Colombier 	t9.mode = t->mode;
7969a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
7979a747e4fSDavid du Colombier 	if(err)
7989a747e4fSDavid du Colombier 		return err;
7999a747e4fSDavid du Colombier 
8009a747e4fSDavid du Colombier 	r->qid.path = r9.qid.path & ~0x80000000;
8019a747e4fSDavid du Colombier 	r->qid.vers = r9.qid.version;
8029a747e4fSDavid du Colombier 	r->qid.type = QTFILE;
8039a747e4fSDavid du Colombier 	if(r9.qid.path & 0x80000000)
8049a747e4fSDavid du Colombier 		r->qid.type = QTDIR;
8059a747e4fSDavid du Colombier 	f->qid = r->qid;
8069a747e4fSDavid du Colombier 	f->newoffset = 0;
8079a747e4fSDavid du Colombier 	f->oldoffset = 0;
8089a747e4fSDavid du Colombier 	r->iounit = 0;
8099a747e4fSDavid du Colombier 	return 0;
8109a747e4fSDavid du Colombier }
8119a747e4fSDavid du Colombier 
8129a747e4fSDavid du Colombier char*
rcreate(Fcall * t,Fcall * r,char * mdata9p1)8139a747e4fSDavid du Colombier rcreate(Fcall *t, Fcall *r, char *mdata9p1)
8149a747e4fSDavid du Colombier {
8159a747e4fSDavid du Colombier 	char *err;
8169a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
8179a747e4fSDavid du Colombier 	Fid *f;
8189a747e4fSDavid du Colombier 
8199a747e4fSDavid du Colombier 	f = newfid(t->fid);
8209a747e4fSDavid du Colombier 	if(!f->busy)
8219a747e4fSDavid du Colombier 		return "create: bad fid";
8229a747e4fSDavid du Colombier 
8239a747e4fSDavid du Colombier 	t9.type = Tcreate9p1;
8249a747e4fSDavid du Colombier 	t9.tag = t->tag;
8259a747e4fSDavid du Colombier 	t9.fid = t->fid;
8269a747e4fSDavid du Colombier 	if(strlen(t->name)+1 >= NAMEREC)
8279a747e4fSDavid du Colombier 		return "file name element too long";
8289a747e4fSDavid du Colombier 	strncpy(t9.name, t->name, NAMEREC);
8299a747e4fSDavid du Colombier 	t9.perm = t->perm;
8309a747e4fSDavid du Colombier 	t9.mode = t->mode;
8319a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
8329a747e4fSDavid du Colombier 	if(err)
8339a747e4fSDavid du Colombier 		return err;
8349a747e4fSDavid du Colombier 
8359a747e4fSDavid du Colombier 	r->qid.path = r9.qid.path & ~0x80000000;
8369a747e4fSDavid du Colombier 	r->qid.vers = r9.qid.version;
8379a747e4fSDavid du Colombier 	r->qid.type = QTFILE;
8389a747e4fSDavid du Colombier 	if(r9.qid.path & 0x80000000)
8399a747e4fSDavid du Colombier 		r->qid.type = QTDIR;
8409a747e4fSDavid du Colombier 	if(r9.qid.path & 0x40000000)
8419a747e4fSDavid du Colombier 		r->qid.type |= QTAPPEND;
8429a747e4fSDavid du Colombier 	if(r9.qid.path & 0x20000000)
8439a747e4fSDavid du Colombier 		r->qid.type |= QTEXCL;
8449a747e4fSDavid du Colombier 	f->qid = r->qid;
8459a747e4fSDavid du Colombier 	r->iounit = 0;
8469a747e4fSDavid du Colombier 	return 0;
8479a747e4fSDavid du Colombier }
8489a747e4fSDavid du Colombier 
8499a747e4fSDavid du Colombier char*
dirrread(Fcall * t,Fcall * r,char * mdata9p1)8509a747e4fSDavid du Colombier dirrread(Fcall *t, Fcall *r, char *mdata9p1)
8519a747e4fSDavid du Colombier {
8529a747e4fSDavid du Colombier 	char *err;
8539a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
8549a747e4fSDavid du Colombier 	Fid *f;
8559a747e4fSDavid du Colombier 	int i, ndir, n, count;
8569a747e4fSDavid du Colombier 	Dir d;
8579a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
8589a747e4fSDavid du Colombier 	char *old;
8599a747e4fSDavid du Colombier 
8609a747e4fSDavid du Colombier 	f = newfid(t->fid);
8619a747e4fSDavid du Colombier 	if(!f->busy)
8629a747e4fSDavid du Colombier 		return "dirread: bad fid";
8639a747e4fSDavid du Colombier 
8649a747e4fSDavid du Colombier 	if(f->newoffset != t->offset)
8659a747e4fSDavid du Colombier 		return "seek in directory disallowed";
8669a747e4fSDavid du Colombier 
8679a747e4fSDavid du Colombier 	t9.type = Tread9p1;
8689a747e4fSDavid du Colombier 	t9.tag = t->tag;
8699a747e4fSDavid du Colombier 	t9.fid = t->fid;
8709a747e4fSDavid du Colombier 	t9.offset = f->oldoffset;
8719a747e4fSDavid du Colombier 	t9.count = t->count;	/* new directories tend to be smaller, so this may overshoot */
8729a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
8739a747e4fSDavid du Colombier 	if(err)
8749a747e4fSDavid du Colombier 		return err;
8759a747e4fSDavid du Colombier 
8769a747e4fSDavid du Colombier 	ndir = r9.count/DIRREC;
8779a747e4fSDavid du Colombier 	old = r9.data;
8789a747e4fSDavid du Colombier 	count = 0;
8799a747e4fSDavid du Colombier 	for(i=0; i<ndir; i++){
8809a747e4fSDavid du Colombier 		if(convM2D9p1(old, &d) != DIRREC)
8819a747e4fSDavid du Colombier 			return "bad dir conversion in read";
8829a747e4fSDavid du Colombier 		n = convD2M(&d, buf+count, sizeof buf-count);
8839a747e4fSDavid du Colombier 		if(n<=BIT16SZ || count+n>t->count)
8849a747e4fSDavid du Colombier 			break;
8859a747e4fSDavid du Colombier 		old += DIRREC;
8869a747e4fSDavid du Colombier 		f->oldoffset += DIRREC;
8879a747e4fSDavid du Colombier 		f->newoffset += n;
8889a747e4fSDavid du Colombier 		count += n;
8899a747e4fSDavid du Colombier 	}
8909a747e4fSDavid du Colombier 	memmove(r9.data, buf, count);	/* put it back in stable storage */
8919a747e4fSDavid du Colombier 	r->data = r9.data;
8929a747e4fSDavid du Colombier 	r->count = count;
8939a747e4fSDavid du Colombier 	return 0;
8949a747e4fSDavid du Colombier }
8959a747e4fSDavid du Colombier 
8969a747e4fSDavid du Colombier char*
rread(Fcall * t,Fcall * r,char * mdata9p1)8979a747e4fSDavid du Colombier rread(Fcall *t, Fcall *r, char *mdata9p1)
8989a747e4fSDavid du Colombier {
8999a747e4fSDavid du Colombier 	char *err;
9009a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
9019a747e4fSDavid du Colombier 	Fid *f;
9029a747e4fSDavid du Colombier 
9039a747e4fSDavid du Colombier 	f = newfid(t->fid);
9049a747e4fSDavid du Colombier 	if(!f->busy)
9059a747e4fSDavid du Colombier 		return "read: bad fid";
9069a747e4fSDavid du Colombier 
9079a747e4fSDavid du Colombier 	if(f->qid.type & QTDIR)
9089a747e4fSDavid du Colombier 		return dirrread(t, r, mdata9p1);
9099a747e4fSDavid du Colombier 
9109a747e4fSDavid du Colombier 	t9.type = Tread9p1;
9119a747e4fSDavid du Colombier 	t9.tag = t->tag;
9129a747e4fSDavid du Colombier 	t9.fid = t->fid;
9139a747e4fSDavid du Colombier 	t9.offset = t->offset;
9149a747e4fSDavid du Colombier 	t9.count = t->count;
9159a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
9169a747e4fSDavid du Colombier 	if(err)
9179a747e4fSDavid du Colombier 		return err;
9189a747e4fSDavid du Colombier 
9199a747e4fSDavid du Colombier 	r->count = r9.count;
9209a747e4fSDavid du Colombier 	r->data = r9.data;	/* points to stable storage */
9219a747e4fSDavid du Colombier 	return 0;
9229a747e4fSDavid du Colombier }
9239a747e4fSDavid du Colombier 
9249a747e4fSDavid du Colombier char*
rwrite(Fcall * t,Fcall * r,char * mdata9p1)9259a747e4fSDavid du Colombier rwrite(Fcall *t, Fcall *r, char *mdata9p1)
9269a747e4fSDavid du Colombier {
9279a747e4fSDavid du Colombier 	char *err;
9289a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
9299a747e4fSDavid du Colombier 	Fid *f;
9309a747e4fSDavid du Colombier 
9319a747e4fSDavid du Colombier 	f = newfid(t->fid);
9329a747e4fSDavid du Colombier 	if(!f->busy)
9339a747e4fSDavid du Colombier 		return "write: bad fid";
9349a747e4fSDavid du Colombier 
9359a747e4fSDavid du Colombier 	t9.type = Twrite9p1;
9369a747e4fSDavid du Colombier 	t9.tag = t->tag;
9379a747e4fSDavid du Colombier 	t9.fid = t->fid;
9389a747e4fSDavid du Colombier 	t9.offset = t->offset;
9399a747e4fSDavid du Colombier 	t9.count = t->count;
9409a747e4fSDavid du Colombier 	t9.data = t->data;
9419a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
9429a747e4fSDavid du Colombier 	if(err)
9439a747e4fSDavid du Colombier 		return err;
9449a747e4fSDavid du Colombier 
9459a747e4fSDavid du Colombier 	r->count = r9.count;
9469a747e4fSDavid du Colombier 	return 0;
9479a747e4fSDavid du Colombier }
9489a747e4fSDavid du Colombier 
9499a747e4fSDavid du Colombier char*
rclunk(Fcall * t,Fcall *,char * mdata9p1)9509a747e4fSDavid du Colombier rclunk(Fcall *t, Fcall *, char *mdata9p1)
9519a747e4fSDavid du Colombier {
9529a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
9539a747e4fSDavid du Colombier 	Fid *f;
9549a747e4fSDavid du Colombier 
9559a747e4fSDavid du Colombier 	f = newfid(t->fid);
9569a747e4fSDavid du Colombier 	if(!f->busy)
9579a747e4fSDavid du Colombier 		return "clunk: bad fid";
9589a747e4fSDavid du Colombier 	t9.type = Tclunk9p1;
9599a747e4fSDavid du Colombier 	t9.tag = t->tag;
9609a747e4fSDavid du Colombier 	t9.fid = t->fid;
9619a747e4fSDavid du Colombier 	transact9p1(&t9, &r9, mdata9p1);
9629a747e4fSDavid du Colombier 	f->busy = 0;
9639a747e4fSDavid du Colombier 	f->allocated = 0;
9649a747e4fSDavid du Colombier 	/* disregard error */
9659a747e4fSDavid du Colombier 	return 0;
9669a747e4fSDavid du Colombier }
9679a747e4fSDavid du Colombier 
9689a747e4fSDavid du Colombier char*
rremove(Fcall * t,Fcall *,char * mdata9p1)9699a747e4fSDavid du Colombier rremove(Fcall *t, Fcall*, char *mdata9p1)
9709a747e4fSDavid du Colombier {
9719a747e4fSDavid du Colombier 	char *err;
9729a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
9739a747e4fSDavid du Colombier 	Fid *f;
9749a747e4fSDavid du Colombier 
9759a747e4fSDavid du Colombier 	f = newfid(t->fid);
9769a747e4fSDavid du Colombier 	if(!f->busy)
9779a747e4fSDavid du Colombier 		return "remove: bad fid";
9789a747e4fSDavid du Colombier 	t9.type = Tremove9p1;
9799a747e4fSDavid du Colombier 	t9.tag = t->tag;
9809a747e4fSDavid du Colombier 	t9.fid = t->fid;
9819a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
9829a747e4fSDavid du Colombier 	f->busy = 0;
9839a747e4fSDavid du Colombier 	f->allocated = 0;
9849a747e4fSDavid du Colombier 	return err;
9859a747e4fSDavid du Colombier }
9869a747e4fSDavid du Colombier 
9879a747e4fSDavid du Colombier char*
rstat(Fcall * t,Fcall * r,char * mdata9p1)9889a747e4fSDavid du Colombier rstat(Fcall *t, Fcall *r, char *mdata9p1)
9899a747e4fSDavid du Colombier {
9909a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
9919a747e4fSDavid du Colombier 	char *err;
9929a747e4fSDavid du Colombier 	Fid *f;
9939a747e4fSDavid du Colombier 	Dir d;
9949a747e4fSDavid du Colombier 	uchar buf[256];	/* big enough; there's no long names */
9959a747e4fSDavid du Colombier 
9969a747e4fSDavid du Colombier 	f = newfid(t->fid);
9979a747e4fSDavid du Colombier 	if(!f->busy)
9989a747e4fSDavid du Colombier 		return "stat: bad fid";
9999a747e4fSDavid du Colombier 
10009a747e4fSDavid du Colombier 	t9.type = Tstat9p1;
10019a747e4fSDavid du Colombier 	t9.tag = t->tag;
10029a747e4fSDavid du Colombier 	t9.fid = t->fid;
10039a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
10049a747e4fSDavid du Colombier 	if(err)
10059a747e4fSDavid du Colombier 		return err;
10069a747e4fSDavid du Colombier 
10079a747e4fSDavid du Colombier 	if(convM2D9p1(r9.stat, &d) != DIRREC)
10089a747e4fSDavid du Colombier 		return "bad conversion in stat";
10099a747e4fSDavid du Colombier 	r->stat = buf;
10109a747e4fSDavid du Colombier 	r->nstat = convD2M(&d, buf, sizeof buf);
10119a747e4fSDavid du Colombier 	return 0;
10129a747e4fSDavid du Colombier }
10139a747e4fSDavid du Colombier 
10149a747e4fSDavid du Colombier int
anydefault(Dir * d)10159a747e4fSDavid du Colombier anydefault(Dir *d)
10169a747e4fSDavid du Colombier {
10179a747e4fSDavid du Colombier 	if(d->name[0] == '\0')
10189a747e4fSDavid du Colombier 		return 1;
10199a747e4fSDavid du Colombier 	if(d->uid[0] == '\0')
10209a747e4fSDavid du Colombier 		return 1;
10219a747e4fSDavid du Colombier 	if(d->gid[0] == '\0')
10229a747e4fSDavid du Colombier 		return 1;
10239a747e4fSDavid du Colombier 	if(d->mode == ~0)
10249a747e4fSDavid du Colombier 		return 1;
10259a747e4fSDavid du Colombier 	if(d->mtime == ~0)
10269a747e4fSDavid du Colombier 		return 1;
10279a747e4fSDavid du Colombier 	return 0;
10289a747e4fSDavid du Colombier }
10299a747e4fSDavid du Colombier 
10309a747e4fSDavid du Colombier char*
rwstat(Fcall * t,Fcall *,char * mdata9p1)10319a747e4fSDavid du Colombier rwstat(Fcall *t, Fcall *, char *mdata9p1)
10329a747e4fSDavid du Colombier {
10339a747e4fSDavid du Colombier 	Fcall9p1 t9, r9;
10349a747e4fSDavid du Colombier 	char strs[DIRREC];
10359a747e4fSDavid du Colombier 	char *err;
10369a747e4fSDavid du Colombier 	Fid *f;
10379a747e4fSDavid du Colombier 	Dir d, cd;
10389a747e4fSDavid du Colombier 
10399a747e4fSDavid du Colombier 	f = newfid(t->fid);
10409a747e4fSDavid du Colombier 	if(!f->busy)
10419a747e4fSDavid du Colombier 		return "wstat: bad fid";
10429a747e4fSDavid du Colombier 
10439a747e4fSDavid du Colombier 	convM2D(t->stat, t->nstat, &d, strs);
10449a747e4fSDavid du Colombier 	cd = d;
10459a747e4fSDavid du Colombier 	if(anydefault(&d)){
10469a747e4fSDavid du Colombier 		/* must first stat file so we can copy current values */
10479a747e4fSDavid du Colombier 		t9.type = Tstat9p1;
10489a747e4fSDavid du Colombier 		t9.tag = t->tag;
10499a747e4fSDavid du Colombier 		t9.fid = t->fid;
10509a747e4fSDavid du Colombier 		err = transact9p1(&t9, &r9, mdata9p1);
10519a747e4fSDavid du Colombier 		if(err)
10529a747e4fSDavid du Colombier 			return err;
10539a747e4fSDavid du Colombier 		if(convM2D9p1(r9.stat, &cd) != DIRREC)
10549a747e4fSDavid du Colombier 			return "bad in conversion in wstat";
10559a747e4fSDavid du Colombier 
10569a747e4fSDavid du Colombier 		/* fill in default values */
10579a747e4fSDavid du Colombier 		if(d.name[0] != '\0'){
10589a747e4fSDavid du Colombier 			if(strlen(d.name) >= NAMEREC)
10599a747e4fSDavid du Colombier 				return Etoolong;
10609a747e4fSDavid du Colombier 			cd.name = d.name;
10619a747e4fSDavid du Colombier 		}
10629a747e4fSDavid du Colombier 		if(d.uid[0] != '\0'){
10639a747e4fSDavid du Colombier 			if(strlen(d.uid) >= NAMEREC)
10649a747e4fSDavid du Colombier 				return Etoolong;
10659a747e4fSDavid du Colombier 			cd.uid = d.uid;
10669a747e4fSDavid du Colombier 		}
10679a747e4fSDavid du Colombier 		if(d.gid[0] != '\0'){
10689a747e4fSDavid du Colombier 			if(strlen(d.gid) >= NAMEREC)
10699a747e4fSDavid du Colombier 				return Etoolong;
10709a747e4fSDavid du Colombier 			cd.gid = d.gid;
10719a747e4fSDavid du Colombier 		}
10729a747e4fSDavid du Colombier 		if(d.mode != ~0)
10739a747e4fSDavid du Colombier 			cd.mode = d.mode;
10749a747e4fSDavid du Colombier 		if(d.mtime != ~0)
10759a747e4fSDavid du Colombier 			cd.mtime = d.mtime;
10769a747e4fSDavid du Colombier 		if(d.length != ~0LL)
10779a747e4fSDavid du Colombier 			cd.length = d.length;
10789a747e4fSDavid du Colombier 	}
10799a747e4fSDavid du Colombier 
10809a747e4fSDavid du Colombier 	if(convD2M9p1(&cd, t9.stat) != DIRREC)
10819a747e4fSDavid du Colombier 		return "bad out conversion in wstat";
10829a747e4fSDavid du Colombier 
10839a747e4fSDavid du Colombier 	t9.type = Twstat9p1;
10849a747e4fSDavid du Colombier 	t9.tag = t->tag;
10859a747e4fSDavid du Colombier 	t9.fid = t->fid;
10869a747e4fSDavid du Colombier 	err = transact9p1(&t9, &r9, mdata9p1);
10879a747e4fSDavid du Colombier 	if(err)
10889a747e4fSDavid du Colombier 		return err;
10899a747e4fSDavid du Colombier 	return 0;
10909a747e4fSDavid du Colombier }
10919a747e4fSDavid du Colombier 
10929a747e4fSDavid du Colombier void *
emalloc(ulong n)10939a747e4fSDavid du Colombier emalloc(ulong n)
10949a747e4fSDavid du Colombier {
10959a747e4fSDavid du Colombier 	void *p;
10969a747e4fSDavid du Colombier 
10979a747e4fSDavid du Colombier 	p = malloc(n);
10989a747e4fSDavid du Colombier 	if(!p)
10999a747e4fSDavid du Colombier 		fatal("out of memory: %r");
11009a747e4fSDavid du Colombier 	memset(p, 0, n);
11019a747e4fSDavid du Colombier 	return p;
11029a747e4fSDavid du Colombier }
11039a747e4fSDavid du Colombier 
11049a747e4fSDavid du Colombier void
fatal(char * fmt,...)11059a747e4fSDavid du Colombier fatal(char *fmt, ...)
11069a747e4fSDavid du Colombier {
11079a747e4fSDavid du Colombier 	char buf[1024];
11089a747e4fSDavid du Colombier 	va_list arg;
11099a747e4fSDavid du Colombier 
11109a747e4fSDavid du Colombier 	if(fmt){
11119a747e4fSDavid du Colombier 		va_start(arg, fmt);
11129a747e4fSDavid du Colombier 		vseprint(buf, buf+sizeof(buf), fmt, arg);
11139a747e4fSDavid du Colombier 		va_end(arg);
11149a747e4fSDavid du Colombier 		fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf);
11159a747e4fSDavid du Colombier 	}else
11169a747e4fSDavid du Colombier 		buf[0] = '\0';
11179a747e4fSDavid du Colombier 	if(mainpid){
11189a747e4fSDavid du Colombier 		/* two hits are sometimes needed */
11199a747e4fSDavid du Colombier 		postnote(PNGROUP, mainpid, "die1 - from srvold9p");
11209a747e4fSDavid du Colombier 		postnote(PNGROUP, mainpid, "die2 - from srvold9p");
11219a747e4fSDavid du Colombier 	}
11229a747e4fSDavid du Colombier 	exits(buf);
11239a747e4fSDavid du Colombier }
1124