xref: /plan9/sys/src/cmd/unix/u9fs/u9fs.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include <sys/types.h>
33e12c5d1SDavid du Colombier #include <sys/stat.h>
43e12c5d1SDavid du Colombier #include "libc.h"
53e12c5d1SDavid du Colombier #include "9p.h"
63e12c5d1SDavid du Colombier #include "stdio.h"
73e12c5d1SDavid du Colombier #include "setjmp.h"
83e12c5d1SDavid du Colombier #include "pwd.h"
93e12c5d1SDavid du Colombier #include "grp.h"
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier #define	DBG(f)
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier struct group *getgrent(void);
143e12c5d1SDavid du Colombier struct passwd *getpwent(void);
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier #ifdef SYSV
173e12c5d1SDavid du Colombier #	include <dirent.h>
183e12c5d1SDavid du Colombier #	define	DTYPE	struct dirent
19219b2ee8SDavid du Colombier #	define SOCKETS
203e12c5d1SDavid du Colombier #endif
213e12c5d1SDavid du Colombier #ifdef V10
223e12c5d1SDavid du Colombier #	include <ndir.h>
233e12c5d1SDavid du Colombier #	define	DTYPE	struct direct
243e12c5d1SDavid du Colombier #endif
253e12c5d1SDavid du Colombier #ifdef BSD
263e12c5d1SDavid du Colombier #	include <sys/dir.h>
273e12c5d1SDavid du Colombier #	define	DTYPE	struct direct
28219b2ee8SDavid du Colombier #	define	SOCKETS
29219b2ee8SDavid du Colombier #endif
30219b2ee8SDavid du Colombier #ifdef SOCKETS
31219b2ee8SDavid du Colombier #	define sendmsg	__sendmsg
32219b2ee8SDavid du Colombier #	include <sys/socket.h>
33219b2ee8SDavid du Colombier #	include <netinet/in.h>
34219b2ee8SDavid du Colombier #	include <netdb.h>
35*7dd7cddfSDavid du Colombier #	include <arpa/inet.h>
36219b2ee8SDavid du Colombier #	undef sendmsg
37219b2ee8SDavid du Colombier 	char	bsdhost[256];
38219b2ee8SDavid du Colombier 	void	remotehostname(void);
39*7dd7cddfSDavid du Colombier 	char	ipaddr[20];
403e12c5d1SDavid du Colombier #endif
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier typedef struct File	File;
433e12c5d1SDavid du Colombier typedef struct Rfile	Rfile;
443e12c5d1SDavid du Colombier typedef struct Fd	Fd;
453e12c5d1SDavid du Colombier typedef struct Pass	Pass;
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier struct Fd{
483e12c5d1SDavid du Colombier 	int		ref;
493e12c5d1SDavid du Colombier 	Ulong		offset;
503e12c5d1SDavid du Colombier 	int		fd;
513e12c5d1SDavid du Colombier 	DIR		*dir;
523e12c5d1SDavid du Colombier };
533e12c5d1SDavid du Colombier 
543e12c5d1SDavid du Colombier struct Rfile{
553e12c5d1SDavid du Colombier 	int		busy;
563e12c5d1SDavid du Colombier 	int		uid;
57219b2ee8SDavid du Colombier 	int		rclose;
583e12c5d1SDavid du Colombier 	File		*file;
593e12c5d1SDavid du Colombier 	Fd		*fd;
603e12c5d1SDavid du Colombier };
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier struct File{
633e12c5d1SDavid du Colombier 	int		ref;
643e12c5d1SDavid du Colombier 	char		*path;
653e12c5d1SDavid du Colombier 	char		*name;
663e12c5d1SDavid du Colombier 	Qid		qid;
673e12c5d1SDavid du Colombier 	struct stat	stbuf;
683e12c5d1SDavid du Colombier };
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier struct Pass{
713e12c5d1SDavid du Colombier 	int		id;
723e12c5d1SDavid du Colombier 	int		gid;
733e12c5d1SDavid du Colombier 	char		*name;
743e12c5d1SDavid du Colombier 	Pass		*next;
75*7dd7cddfSDavid du Colombier 	Pass		*nnext;
76*7dd7cddfSDavid du Colombier 	int		nmem;
77*7dd7cddfSDavid du Colombier 	gid_t		*mem;
783e12c5d1SDavid du Colombier };
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier char	data[2][MAXMSG+MAXFDATA];
813e12c5d1SDavid du Colombier char	tdata[MAXMSG+MAXFDATA];
823e12c5d1SDavid du Colombier char	rdata[MAXFDATA];
833e12c5d1SDavid du Colombier Fcall	rhdr;
843e12c5d1SDavid du Colombier Fcall	thdr;
853e12c5d1SDavid du Colombier Rfile	*rfile;
863e12c5d1SDavid du Colombier File	*file0;
873e12c5d1SDavid du Colombier int	nrfilealloc;
883e12c5d1SDavid du Colombier jmp_buf	loopjmp;
893e12c5d1SDavid du Colombier Pass*	uid[256];
903e12c5d1SDavid du Colombier Pass*	gid[256];
91*7dd7cddfSDavid du Colombier Pass*	uidname[256];
92*7dd7cddfSDavid du Colombier Pass*	gidname[256];
93*7dd7cddfSDavid du Colombier int	curuid;
943e12c5d1SDavid du Colombier int	devallowed;
953e12c5d1SDavid du Colombier int	connected;
96*7dd7cddfSDavid du Colombier int	readonly;
97*7dd7cddfSDavid du Colombier int	myuid;
98*7dd7cddfSDavid du Colombier char	*onlyuser;
993e12c5d1SDavid du Colombier 
1003e12c5d1SDavid du Colombier void	io(void);
1013e12c5d1SDavid du Colombier void	error(char*);
1023e12c5d1SDavid du Colombier char	*mfmt(Fcall*);
103*7dd7cddfSDavid du Colombier void	sendmsg(const char*);
1043e12c5d1SDavid du Colombier int	okfid(int);
1053e12c5d1SDavid du Colombier Rfile*	rfilefid(void);
1063e12c5d1SDavid du Colombier File*	newfile(void);
1073e12c5d1SDavid du Colombier void*	erealloc(void*, unsigned);
1083e12c5d1SDavid du Colombier char*	estrdup(char*);
109*7dd7cddfSDavid du Colombier const char*	dostat(File*, char*);
1103e12c5d1SDavid du Colombier char*	bldpath(char*, char*, char*);
1113e12c5d1SDavid du Colombier Ulong	qid(struct stat*);
112219b2ee8SDavid du Colombier Ulong	vers(struct stat*);
113*7dd7cddfSDavid du Colombier void	errjmp(const char*);
1143e12c5d1SDavid du Colombier int	omode(int);
1153e12c5d1SDavid du Colombier char*	id2name(Pass**, int);
116*7dd7cddfSDavid du Colombier Pass*	id2pass(Pass**, int);
1173e12c5d1SDavid du Colombier Pass*	name2pass(Pass**, char*);
1183e12c5d1SDavid du Colombier void	getpwdf(void);
1193e12c5d1SDavid du Colombier void	getgrpf(void);
120*7dd7cddfSDavid du Colombier int	hash(char*);
121*7dd7cddfSDavid du Colombier void	setupuser(int);
1223e12c5d1SDavid du Colombier 
123219b2ee8SDavid du Colombier void	rsession(void);
1243e12c5d1SDavid du Colombier void	rattach(void);
1253e12c5d1SDavid du Colombier void	rflush(void);
1263e12c5d1SDavid du Colombier void	rclone(void);
1273e12c5d1SDavid du Colombier void	rwalk(void);
1283e12c5d1SDavid du Colombier void	ropen(void);
1293e12c5d1SDavid du Colombier void	rcreate(void);
1303e12c5d1SDavid du Colombier void	rread(void);
1313e12c5d1SDavid du Colombier void	rwrite(void);
1323e12c5d1SDavid du Colombier void	rclunk(int);
1333e12c5d1SDavid du Colombier void	rstat(void);
1343e12c5d1SDavid du Colombier void	rwstat(void);
1353e12c5d1SDavid du Colombier void	rclwalk(void);
1363e12c5d1SDavid du Colombier 
1373e12c5d1SDavid du Colombier char	Eauth[] =	"authentication failed";
1383e12c5d1SDavid du Colombier char	Eperm[] =	"permission denied";
1393e12c5d1SDavid du Colombier char	Ebadfid[] =	"fid unknown or out of range";
1403e12c5d1SDavid du Colombier char	Efidactive[] =	"fid already in use";
1413e12c5d1SDavid du Colombier char	Eopen[] =	"file is open";
1423e12c5d1SDavid du Colombier char	Emode[] =	"invalid open mode";
1433e12c5d1SDavid du Colombier char	Especial[] =	"no access to special file";
1443e12c5d1SDavid du Colombier char	Especial0[] =	"already attached without access to special files";
1453e12c5d1SDavid du Colombier char	Especial1[] =	"already attached with access to special files";
1463e12c5d1SDavid du Colombier char	Enotopen[] =	"file is not open";
1473e12c5d1SDavid du Colombier char	Etoolarge[] =	"i/o count too large";
1483e12c5d1SDavid du Colombier char	Ebaddir[] =	"i/o error on directory";
1493e12c5d1SDavid du Colombier char	Eunknown[] =	"unknown user or group";
1503e12c5d1SDavid du Colombier char	Euid[] =	"can't set uid";
1513e12c5d1SDavid du Colombier char	Egid[] =	"can't set gid";
1523e12c5d1SDavid du Colombier char	Eowner[] =	"not owner";
1533e12c5d1SDavid du Colombier 
154*7dd7cddfSDavid du Colombier void
155*7dd7cddfSDavid du Colombier usage(void)
156*7dd7cddfSDavid du Colombier {
157*7dd7cddfSDavid du Colombier 	fprintf(stderr, "u9fs [-r] [-u user uid]\n");
158*7dd7cddfSDavid du Colombier 	exit(1);
159*7dd7cddfSDavid du Colombier }
160*7dd7cddfSDavid du Colombier 
1613e12c5d1SDavid du Colombier int
1623e12c5d1SDavid du Colombier main(int argc, char *argv[])
1633e12c5d1SDavid du Colombier {
164*7dd7cddfSDavid du Colombier 	char *s;
165*7dd7cddfSDavid du Colombier 	int onlyuid;
166*7dd7cddfSDavid du Colombier 
167*7dd7cddfSDavid du Colombier #	ifdef LOG
1683e12c5d1SDavid du Colombier 	freopen(LOG, "a", stderr);
169*7dd7cddfSDavid du Colombier #	endif
170*7dd7cddfSDavid du Colombier 
1713e12c5d1SDavid du Colombier 	setbuf(stderr, (void*)0);
1723e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, "u9fs\nkill %d\n", getpid()));
173*7dd7cddfSDavid du Colombier 
174*7dd7cddfSDavid du Colombier 	onlyuid = -1;
175*7dd7cddfSDavid du Colombier 	ARGBEGIN{
176*7dd7cddfSDavid du Colombier 	case 'r':
177*7dd7cddfSDavid du Colombier 		readonly++;
178*7dd7cddfSDavid du Colombier 		break;
179*7dd7cddfSDavid du Colombier 	case 'u':
180*7dd7cddfSDavid du Colombier 		onlyuser = ARGF();
181*7dd7cddfSDavid du Colombier 		if(onlyuser == 0)
182*7dd7cddfSDavid du Colombier 			usage();
183*7dd7cddfSDavid du Colombier 		s = ARGF();
184*7dd7cddfSDavid du Colombier 		if(s == 0)
185*7dd7cddfSDavid du Colombier 			usage();
186*7dd7cddfSDavid du Colombier 		onlyuid = atoi(s);
187*7dd7cddfSDavid du Colombier 		break;
188*7dd7cddfSDavid du Colombier 	default:
189*7dd7cddfSDavid du Colombier 		usage();
190*7dd7cddfSDavid du Colombier 		break;
191*7dd7cddfSDavid du Colombier 	}ARGEND
192*7dd7cddfSDavid du Colombier 
193*7dd7cddfSDavid du Colombier 	if(argc)
194*7dd7cddfSDavid du Colombier 		usage();
195219b2ee8SDavid du Colombier 
196219b2ee8SDavid du Colombier #	ifdef SOCKETS
197*7dd7cddfSDavid du Colombier 	if(!onlyuser)
198219b2ee8SDavid du Colombier 		remotehostname();
199219b2ee8SDavid du Colombier #	endif
200219b2ee8SDavid du Colombier 
201*7dd7cddfSDavid du Colombier 	setreuid(0, 0);
202*7dd7cddfSDavid du Colombier 	myuid = geteuid();
203*7dd7cddfSDavid du Colombier 	if(onlyuser && myuid != onlyuid)
204*7dd7cddfSDavid du Colombier 		error("invalid uid");
205*7dd7cddfSDavid du Colombier 
2063e12c5d1SDavid du Colombier 	io();
2073e12c5d1SDavid du Colombier 	return 0;
2083e12c5d1SDavid du Colombier }
2093e12c5d1SDavid du Colombier 
2103e12c5d1SDavid du Colombier void
2113e12c5d1SDavid du Colombier io(void)
2123e12c5d1SDavid du Colombier {
2133e12c5d1SDavid du Colombier 	int m;
2143e12c5d1SDavid du Colombier 	static int toggle, ndata;
2153e12c5d1SDavid du Colombier 	char *datap;
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier 	/*
2183e12c5d1SDavid du Colombier 	 * TCP does not preserve record boundaries; this dance works around
2193e12c5d1SDavid du Colombier 	 * the problem.
2203e12c5d1SDavid du Colombier 	 */
2213e12c5d1SDavid du Colombier 	setjmp(loopjmp);
2223e12c5d1SDavid du Colombier 
2233e12c5d1SDavid du Colombier 	/*
2243e12c5d1SDavid du Colombier 	 * Invariant: data[toggle] has ndata bytes already
2253e12c5d1SDavid du Colombier 	 */
2263e12c5d1SDavid du Colombier     loop:
2273e12c5d1SDavid du Colombier 	datap = data[toggle];
2283e12c5d1SDavid du Colombier 	toggle ^= 1;
2293e12c5d1SDavid du Colombier 	for(;;){
2303e12c5d1SDavid du Colombier 		if(ndata){
2313e12c5d1SDavid du Colombier 			m = convM2S(datap, &rhdr, ndata);
2323e12c5d1SDavid du Colombier 			/* m is number of bytes more than a full message */
2333e12c5d1SDavid du Colombier 			if(m >= 0){
2343e12c5d1SDavid du Colombier 				memmove(data[toggle], datap+(ndata-m), m);
2353e12c5d1SDavid du Colombier 				ndata = m;
2363e12c5d1SDavid du Colombier 				break;
2373e12c5d1SDavid du Colombier 			}
2383e12c5d1SDavid du Colombier 		}
2393e12c5d1SDavid du Colombier 		m = read(0, datap+ndata, (MAXMSG+MAXFDATA)-ndata);
240*7dd7cddfSDavid du Colombier 		if(m == 0){
241*7dd7cddfSDavid du Colombier 			fprintf(stderr, "u9fs: eof\n");
242*7dd7cddfSDavid du Colombier 			exit(1);
243*7dd7cddfSDavid du Colombier 		}
244*7dd7cddfSDavid du Colombier 		if(m < 0)
2453e12c5d1SDavid du Colombier 			error("read");
2463e12c5d1SDavid du Colombier 		ndata += m;
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier 	thdr.type = rhdr.type+1;
2503e12c5d1SDavid du Colombier 	thdr.tag = rhdr.tag;
2513e12c5d1SDavid du Colombier 	thdr.fid = rhdr.fid;
2523e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, ">> %s\n", mfmt(&rhdr)));
2533e12c5d1SDavid du Colombier 	switch(rhdr.type){
2543e12c5d1SDavid du Colombier 	case Tnop:
2553e12c5d1SDavid du Colombier 	case Tflush:	/* this is a synchronous fs; easy */
2563e12c5d1SDavid du Colombier 		break;
257219b2ee8SDavid du Colombier 	case Tsession:
258219b2ee8SDavid du Colombier 		rsession();
2593e12c5d1SDavid du Colombier 		break;
2603e12c5d1SDavid du Colombier 	case Tattach:
2613e12c5d1SDavid du Colombier 		rattach();
2623e12c5d1SDavid du Colombier 		break;
2633e12c5d1SDavid du Colombier 	case Tclone:
2643e12c5d1SDavid du Colombier 		rclone();
2653e12c5d1SDavid du Colombier 		break;
2663e12c5d1SDavid du Colombier 	case Twalk:
2673e12c5d1SDavid du Colombier 		rwalk();
2683e12c5d1SDavid du Colombier 		break;
2693e12c5d1SDavid du Colombier 	case Tstat:
2703e12c5d1SDavid du Colombier 		rstat();
2713e12c5d1SDavid du Colombier 		break;
2723e12c5d1SDavid du Colombier 	case Twstat:
2733e12c5d1SDavid du Colombier 		rwstat();
2743e12c5d1SDavid du Colombier 		break;
2753e12c5d1SDavid du Colombier 	case Topen:
2763e12c5d1SDavid du Colombier 		ropen();
2773e12c5d1SDavid du Colombier 		break;
2783e12c5d1SDavid du Colombier 	case Tcreate:
2793e12c5d1SDavid du Colombier 		rcreate();
2803e12c5d1SDavid du Colombier 		break;
2813e12c5d1SDavid du Colombier 	case Tread:
2823e12c5d1SDavid du Colombier 		rread();
2833e12c5d1SDavid du Colombier 		break;
2843e12c5d1SDavid du Colombier 	case Twrite:
2853e12c5d1SDavid du Colombier 		rwrite();
2863e12c5d1SDavid du Colombier 		break;
2873e12c5d1SDavid du Colombier 	case Tclunk:
2883e12c5d1SDavid du Colombier 		rclunk(0);
2893e12c5d1SDavid du Colombier 		break;
2903e12c5d1SDavid du Colombier 	case Tremove:
2913e12c5d1SDavid du Colombier 		rclunk(1);
2923e12c5d1SDavid du Colombier 		break;
2933e12c5d1SDavid du Colombier 	default:
2943e12c5d1SDavid du Colombier 		fprintf(stderr, "unknown message %s\n", mfmt(&rhdr));
2953e12c5d1SDavid du Colombier 		error("bad message");
2963e12c5d1SDavid du Colombier 	}
2973e12c5d1SDavid du Colombier 	sendmsg(0);
2983e12c5d1SDavid du Colombier 	goto loop;
2993e12c5d1SDavid du Colombier }
3003e12c5d1SDavid du Colombier 
3013e12c5d1SDavid du Colombier void
302219b2ee8SDavid du Colombier rsession(void)
3033e12c5d1SDavid du Colombier {
304219b2ee8SDavid du Colombier 	memset(thdr.authid, 0, sizeof(thdr.authid));
305219b2ee8SDavid du Colombier 	memset(thdr.authdom, 0, sizeof(thdr.authdom));
306219b2ee8SDavid du Colombier 	memset(thdr.chal, 0, sizeof(thdr.chal));
3073e12c5d1SDavid du Colombier }
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier void
3103e12c5d1SDavid du Colombier rattach(void)
3113e12c5d1SDavid du Colombier {
3123e12c5d1SDavid du Colombier 	Rfile *rf;
3133e12c5d1SDavid du Colombier 	Pass *p;
3143e12c5d1SDavid du Colombier 
3153e12c5d1SDavid du Colombier 	if(file0 == 0){
3163e12c5d1SDavid du Colombier 		file0 = newfile();
3173e12c5d1SDavid du Colombier 		file0->ref++;		/* one extra to hold it up */
3183e12c5d1SDavid du Colombier 		file0->path = estrdup("/");
3193e12c5d1SDavid du Colombier 		file0->name = estrdup("/");
3203e12c5d1SDavid du Colombier 		errjmp(dostat(file0, 0));
3213e12c5d1SDavid du Colombier 	}
3223e12c5d1SDavid du Colombier 	if(!okfid(rhdr.fid))
3233e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
3243e12c5d1SDavid du Colombier 	if(strncmp(rhdr.aname, "device", 6) == 0){
3253e12c5d1SDavid du Colombier 		if(connected && !devallowed)
3263e12c5d1SDavid du Colombier 			errjmp(Especial0);
3273e12c5d1SDavid du Colombier 		devallowed = 1;
3283e12c5d1SDavid du Colombier 	}else{
3293e12c5d1SDavid du Colombier 		if(connected && devallowed)
3303e12c5d1SDavid du Colombier 			errjmp(Especial1);
3313e12c5d1SDavid du Colombier 	}
3323e12c5d1SDavid du Colombier 	getpwdf();
3333e12c5d1SDavid du Colombier 	getgrpf();
3343e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
3353e12c5d1SDavid du Colombier 	if(rf->busy)
3363e12c5d1SDavid du Colombier 		errjmp(Efidactive);
337*7dd7cddfSDavid du Colombier 	p = name2pass(uidname, rhdr.uname);
3383e12c5d1SDavid du Colombier 	if(p == 0)
3393e12c5d1SDavid du Colombier 		errjmp(Eunknown);
340*7dd7cddfSDavid du Colombier 	if(p->id == 0 || (uid_t)p->id == (uid_t)-1
341*7dd7cddfSDavid du Colombier 	|| myuid && p->id != myuid)
342219b2ee8SDavid du Colombier 		errjmp(Eperm);
343219b2ee8SDavid du Colombier #	ifdef SOCKETS
344*7dd7cddfSDavid du Colombier 	if(!myuid && ruserok(bsdhost, 0, rhdr.uname, rhdr.uname) < 0)
345219b2ee8SDavid du Colombier 		errjmp(Eperm);
346219b2ee8SDavid du Colombier #	endif
347219b2ee8SDavid du Colombier 	/* mark busy & inc ref cnt only after committed to succeed */
348219b2ee8SDavid du Colombier 	rf->busy = 1;
349219b2ee8SDavid du Colombier 	rf->file = file0;
350219b2ee8SDavid du Colombier 	file0->ref++;
351219b2ee8SDavid du Colombier 	rf->rclose = 0;
3523e12c5d1SDavid du Colombier 	rf->uid = p->id;
3533e12c5d1SDavid du Colombier 	thdr.qid = file0->qid;
3543e12c5d1SDavid du Colombier 	connected = 1;
3553e12c5d1SDavid du Colombier }
3563e12c5d1SDavid du Colombier 
3573e12c5d1SDavid du Colombier void
3583e12c5d1SDavid du Colombier rclone(void)
3593e12c5d1SDavid du Colombier {
3603e12c5d1SDavid du Colombier 	Rfile *rf, *nrf;
3613e12c5d1SDavid du Colombier 	File *f;
3623e12c5d1SDavid du Colombier 
3633e12c5d1SDavid du Colombier 	rfilefid();
3643e12c5d1SDavid du Colombier 	if(!okfid(rhdr.newfid))
3653e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
3663e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
3673e12c5d1SDavid du Colombier 	nrf = &rfile[rhdr.newfid];
3683e12c5d1SDavid du Colombier 	f = rf->file;
3693e12c5d1SDavid du Colombier 	if(nrf->busy)
3703e12c5d1SDavid du Colombier 		errjmp(Efidactive);
3713e12c5d1SDavid du Colombier 	nrf->busy = 1;
3723e12c5d1SDavid du Colombier 	nrf->file = f;
3733e12c5d1SDavid du Colombier 	f->ref++;
3743e12c5d1SDavid du Colombier 	nrf->fd = rf->fd;
3753e12c5d1SDavid du Colombier 	nrf->uid = rf->uid;
376219b2ee8SDavid du Colombier 	nrf->rclose = rf->rclose;
3773e12c5d1SDavid du Colombier 	if(nrf->fd){
3783e12c5d1SDavid du Colombier 		if(nrf->fd->ref == 0)
3793e12c5d1SDavid du Colombier 			error("clone fd count");
3803e12c5d1SDavid du Colombier 		nrf->fd->ref++;
3813e12c5d1SDavid du Colombier 	}
3823e12c5d1SDavid du Colombier }
3833e12c5d1SDavid du Colombier 
3843e12c5d1SDavid du Colombier void
3853e12c5d1SDavid du Colombier rwalk(void)
3863e12c5d1SDavid du Colombier {
387*7dd7cddfSDavid du Colombier 	const char *err;
3883e12c5d1SDavid du Colombier 	Rfile *rf;
3893e12c5d1SDavid du Colombier 	File *of, *f;
3903e12c5d1SDavid du Colombier 
3913e12c5d1SDavid du Colombier 	rf = rfilefid();
3923e12c5d1SDavid du Colombier 	if(rf->fd)
3933e12c5d1SDavid du Colombier 		errjmp(Eopen);
3943e12c5d1SDavid du Colombier 	of = rf->file;
3953e12c5d1SDavid du Colombier 	f = newfile();
3963e12c5d1SDavid du Colombier 	f->path = estrdup(of->path);
3973e12c5d1SDavid du Colombier 	err = dostat(f, rhdr.name);
3983e12c5d1SDavid du Colombier 	if(err){
3993e12c5d1SDavid du Colombier 		free(f->path);
400*7dd7cddfSDavid du Colombier 		free(f->name);
401*7dd7cddfSDavid du Colombier 		free(f);
4023e12c5d1SDavid du Colombier 		errjmp(err);
4033e12c5d1SDavid du Colombier 	}
4043e12c5d1SDavid du Colombier 	if(of->ref <= 0)
4053e12c5d1SDavid du Colombier 		error("walk ref count");
4063e12c5d1SDavid du Colombier 	if(--of->ref == 0){
4073e12c5d1SDavid du Colombier 		free(of->path);
4083e12c5d1SDavid du Colombier 		free(of->name);
4093e12c5d1SDavid du Colombier 		free(of);
4103e12c5d1SDavid du Colombier 	}
4113e12c5d1SDavid du Colombier 	rf->file = f;
4123e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
4133e12c5d1SDavid du Colombier }
4143e12c5d1SDavid du Colombier 
4153e12c5d1SDavid du Colombier void
4163e12c5d1SDavid du Colombier ropen(void)
4173e12c5d1SDavid du Colombier {
4183e12c5d1SDavid du Colombier 	Rfile *rf;
4193e12c5d1SDavid du Colombier 	File *f;
4203e12c5d1SDavid du Colombier 	int fd;
4213e12c5d1SDavid du Colombier 	DIR *dir;
4223e12c5d1SDavid du Colombier 	int m, trunc;
4233e12c5d1SDavid du Colombier 
4243e12c5d1SDavid du Colombier 	rf = rfilefid();
4253e12c5d1SDavid du Colombier 	f = rf->file;
4263e12c5d1SDavid du Colombier 	if(rf->fd)
4273e12c5d1SDavid du Colombier 		error("open already open");
4283e12c5d1SDavid du Colombier 	if(!devallowed && (f->stbuf.st_mode & S_IFCHR))
4293e12c5d1SDavid du Colombier 		errjmp(Especial);
4303e12c5d1SDavid du Colombier 	m = rhdr.mode & (16|3);
4313e12c5d1SDavid du Colombier 	trunc = m & 16;	/* OTRUNC */
4323e12c5d1SDavid du Colombier 	switch(m){
4333e12c5d1SDavid du Colombier 	case 0:
4343e12c5d1SDavid du Colombier 	case 1:
4353e12c5d1SDavid du Colombier 	case 1|16:
4363e12c5d1SDavid du Colombier 	case 2:
4373e12c5d1SDavid du Colombier 	case 0|16:
4383e12c5d1SDavid du Colombier 	case 2|16:
4393e12c5d1SDavid du Colombier 	case 3:
4403e12c5d1SDavid du Colombier 		break;
4413e12c5d1SDavid du Colombier 	default:
4423e12c5d1SDavid du Colombier 		errjmp(Emode);
4433e12c5d1SDavid du Colombier 	}
4443e12c5d1SDavid du Colombier 
445bd389b36SDavid du Colombier 	m = omode(m & 3);
4463e12c5d1SDavid du Colombier 	errno = 0;
4473e12c5d1SDavid du Colombier 	if(f->qid.path & CHDIR){
4483e12c5d1SDavid du Colombier 		if(rhdr.mode != 0)		/* OREAD */
4493e12c5d1SDavid du Colombier 			errjmp(Eperm);
4503e12c5d1SDavid du Colombier 		dir = opendir(f->path);
4513e12c5d1SDavid du Colombier 		if(dir == 0)
4523e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4533e12c5d1SDavid du Colombier 		fd = 0;
4543e12c5d1SDavid du Colombier 	}else{
4553e12c5d1SDavid du Colombier 		if(trunc){
456*7dd7cddfSDavid du Colombier 			if(readonly) errjmp("trunc disallowed");
4573e12c5d1SDavid du Colombier 			fd = creat(f->path, 0666);
4583e12c5d1SDavid du Colombier 			if(fd >= 0)
4593e12c5d1SDavid du Colombier 				if(m != 1){
4603e12c5d1SDavid du Colombier 					close(fd);
4613e12c5d1SDavid du Colombier 					fd = open(f->path, m);
4623e12c5d1SDavid du Colombier 				}
4633e12c5d1SDavid du Colombier 		}else
4643e12c5d1SDavid du Colombier 			fd = open(f->path, m);
4653e12c5d1SDavid du Colombier 		if(fd < 0)
4663e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4673e12c5d1SDavid du Colombier 		dir = 0;
4683e12c5d1SDavid du Colombier 	}
469219b2ee8SDavid du Colombier 	rf->rclose = rhdr.mode & 64;	/* ORCLOSE */
4703e12c5d1SDavid du Colombier 	rf->fd = erealloc(0, sizeof(Fd));
4713e12c5d1SDavid du Colombier 	rf->fd->ref = 1;
4723e12c5d1SDavid du Colombier 	rf->fd->fd = fd;
4733e12c5d1SDavid du Colombier 	rf->fd->dir = dir;
4743e12c5d1SDavid du Colombier 	rf->fd->offset = 0;
4753e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
4763e12c5d1SDavid du Colombier }
4773e12c5d1SDavid du Colombier 
4783e12c5d1SDavid du Colombier void
4793e12c5d1SDavid du Colombier rcreate(void)
4803e12c5d1SDavid du Colombier {
4813e12c5d1SDavid du Colombier 	Rfile *rf;
4823e12c5d1SDavid du Colombier 	File *f, *of;
483*7dd7cddfSDavid du Colombier 	char *path;
484*7dd7cddfSDavid du Colombier 	const char *err;
485*7dd7cddfSDavid du Colombier 	int fd, m;
4863e12c5d1SDavid du Colombier 	char name[NAMELEN];
4873e12c5d1SDavid du Colombier 
488*7dd7cddfSDavid du Colombier 	if(readonly) errjmp("write disallowed");
4893e12c5d1SDavid du Colombier 	rf = rfilefid();
4903e12c5d1SDavid du Colombier 	if(rf->fd)
4913e12c5d1SDavid du Colombier 		errjmp(Eopen);
4923e12c5d1SDavid du Colombier 	path = bldpath(rf->file->path, rhdr.name, name);
493bd389b36SDavid du Colombier 	m = omode(rhdr.mode&3);
4943e12c5d1SDavid du Colombier 	errno = 0;
495*7dd7cddfSDavid du Colombier 	/* plan 9 group sematics: always inherit from directory */
4963e12c5d1SDavid du Colombier 	if(rhdr.perm & CHDIR){
4973e12c5d1SDavid du Colombier 		if(m){
4983e12c5d1SDavid du Colombier 			free(path);
4993e12c5d1SDavid du Colombier 			errjmp(Eperm);
5003e12c5d1SDavid du Colombier 		}
5013e12c5d1SDavid du Colombier 		fd = mkdir(path, 0777);
5023e12c5d1SDavid du Colombier 		if(fd < 0){
5033e12c5d1SDavid du Colombier 			free(path);
5043e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
5053e12c5d1SDavid du Colombier 		}
5063e12c5d1SDavid du Colombier 		fd = open(path, 0);
5073e12c5d1SDavid du Colombier 		free(path);
508*7dd7cddfSDavid du Colombier 		if(fd >= 0)
509*7dd7cddfSDavid du Colombier 			fchmod(fd, S_ISGID|(rhdr.perm&rf->file->stbuf.st_mode&0777));
5103e12c5d1SDavid du Colombier 	}else{
5113e12c5d1SDavid du Colombier 		fd = creat(path, 0666);
5123e12c5d1SDavid du Colombier 		if(fd >= 0){
5133e12c5d1SDavid du Colombier 			if(m != 1){
5143e12c5d1SDavid du Colombier 				close(fd);
5153e12c5d1SDavid du Colombier 				fd = open(path, m);
5163e12c5d1SDavid du Colombier 			}
517*7dd7cddfSDavid du Colombier 			fchmod(fd, rhdr.perm&rf->file->stbuf.st_mode&0777);
5183e12c5d1SDavid du Colombier 		}
5193e12c5d1SDavid du Colombier 		free(path);
5203e12c5d1SDavid du Colombier 		if(fd < 0)
5213e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
5223e12c5d1SDavid du Colombier 	}
5233e12c5d1SDavid du Colombier 	f = newfile();
5243e12c5d1SDavid du Colombier 	of = rf->file;
5253e12c5d1SDavid du Colombier 	f->path = estrdup(of->path);
5263e12c5d1SDavid du Colombier 	err = dostat(f, rhdr.name);
5273e12c5d1SDavid du Colombier 	if(err){
5283e12c5d1SDavid du Colombier 		free(f->path);
5293e12c5d1SDavid du Colombier 		free(f->name);
5303e12c5d1SDavid du Colombier 		free(f);
5313e12c5d1SDavid du Colombier 		errjmp(err);
5323e12c5d1SDavid du Colombier 	}
5333e12c5d1SDavid du Colombier 	if(!devallowed && (f->stbuf.st_mode & S_IFCHR)){
5343e12c5d1SDavid du Colombier 		free(f->path);
5353e12c5d1SDavid du Colombier 		free(f->name);
5363e12c5d1SDavid du Colombier 		free(f);
5373e12c5d1SDavid du Colombier 		errjmp(Especial);
5383e12c5d1SDavid du Colombier 	}
5393e12c5d1SDavid du Colombier 	if(--of->ref == 0){
5403e12c5d1SDavid du Colombier 		free(of->path);
5413e12c5d1SDavid du Colombier 		free(of->name);
5423e12c5d1SDavid du Colombier 		free(of);
5433e12c5d1SDavid du Colombier 	}
5443e12c5d1SDavid du Colombier 	rf->file = f;
545219b2ee8SDavid du Colombier 	rf->rclose = rhdr.mode & 64;	/* ORCLOSE */
5463e12c5d1SDavid du Colombier 	rf->fd = erealloc(0, sizeof(Fd));
5473e12c5d1SDavid du Colombier 	rf->fd->ref = 1;
5483e12c5d1SDavid du Colombier 	rf->fd->fd = fd;
5493e12c5d1SDavid du Colombier 	rf->fd->dir = 0;
5503e12c5d1SDavid du Colombier 	rf->fd->offset = 0;
5513e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
5523e12c5d1SDavid du Colombier }
5533e12c5d1SDavid du Colombier 
5543e12c5d1SDavid du Colombier void
5553e12c5d1SDavid du Colombier rread(void)
5563e12c5d1SDavid du Colombier {
5573e12c5d1SDavid du Colombier 	Rfile *rf;
5583e12c5d1SDavid du Colombier 	File *f;
5593e12c5d1SDavid du Colombier 	long n;
5603e12c5d1SDavid du Colombier 	DTYPE *de;
5613e12c5d1SDavid du Colombier 	Dir d;
5623e12c5d1SDavid du Colombier 	struct stat stbuf;
5633e12c5d1SDavid du Colombier 	char *path;
5643e12c5d1SDavid du Colombier 
5653e12c5d1SDavid du Colombier 	rf = rfilefid();
5663e12c5d1SDavid du Colombier 	if(rf->fd == 0)
5673e12c5d1SDavid du Colombier 		errjmp(Enotopen);
5683e12c5d1SDavid du Colombier 	if(rhdr.count > sizeof rdata)
5693e12c5d1SDavid du Colombier 		errjmp(Etoolarge);
5703e12c5d1SDavid du Colombier 	f = rf->file;
5713e12c5d1SDavid du Colombier 	if(rf->fd->dir){
5723e12c5d1SDavid du Colombier 		errno = 0;
573219b2ee8SDavid du Colombier 		rhdr.count = (rhdr.count/DIRLEN)*DIRLEN;
5743e12c5d1SDavid du Colombier 		if(rf->fd->offset != rhdr.offset){
575219b2ee8SDavid du Colombier 			rf->fd->offset = rhdr.offset;  /* sync offset */
5763e12c5d1SDavid du Colombier 			seekdir(rf->fd->dir, 0);
5773e12c5d1SDavid du Colombier 			for(n=0; n<rhdr.offset; ){
5783e12c5d1SDavid du Colombier 				de = readdir(rf->fd->dir);
5793e12c5d1SDavid du Colombier 				if(de == 0)
5803e12c5d1SDavid du Colombier 					break;
5813e12c5d1SDavid du Colombier 				if(de->d_ino==0 || de->d_name[0]==0)
5823e12c5d1SDavid du Colombier 					continue;
5833e12c5d1SDavid du Colombier 				if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0)
5843e12c5d1SDavid du Colombier 					continue;
5853e12c5d1SDavid du Colombier 				n += DIRLEN;
5863e12c5d1SDavid du Colombier 			}
5873e12c5d1SDavid du Colombier 		}
5883e12c5d1SDavid du Colombier 		for(n=0; n<rhdr.count; ){
5893e12c5d1SDavid du Colombier 			de = readdir(rf->fd->dir);
5903e12c5d1SDavid du Colombier 			if(de == 0)
5913e12c5d1SDavid du Colombier 				break;
5923e12c5d1SDavid du Colombier 			if(de->d_ino==0 || de->d_name[0]==0)
5933e12c5d1SDavid du Colombier 				continue;
5943e12c5d1SDavid du Colombier 			if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0)
5953e12c5d1SDavid du Colombier 				continue;
5963e12c5d1SDavid du Colombier 			strncpy(d.name, de->d_name, NAMELEN-1);
5973e12c5d1SDavid du Colombier 			d.name[NAMELEN-1] = 0;
5983e12c5d1SDavid du Colombier 			path = erealloc(0, strlen(f->path)+1+strlen(de->d_name)+1);
5993e12c5d1SDavid du Colombier 			sprintf(path, "%s/%s", f->path, de->d_name);
6003e12c5d1SDavid du Colombier 			memset(&stbuf, 0, sizeof stbuf);
6013e12c5d1SDavid du Colombier 			if(stat(path, &stbuf) < 0){
6023e12c5d1SDavid du Colombier 				fprintf(stderr, "dir: bad path %s\n", path);
6033e12c5d1SDavid du Colombier 				/* but continue... probably a bad symlink */
6043e12c5d1SDavid du Colombier 			}
6053e12c5d1SDavid du Colombier 			free(path);
6063e12c5d1SDavid du Colombier 			strncpy(d.uid, id2name(uid, stbuf.st_uid), NAMELEN);
6073e12c5d1SDavid du Colombier 			strncpy(d.gid, id2name(gid, stbuf.st_gid), NAMELEN);
6083e12c5d1SDavid du Colombier 			d.qid.path = qid(&stbuf);
609219b2ee8SDavid du Colombier 			d.qid.vers = vers(&stbuf);
6103e12c5d1SDavid du Colombier 			d.mode = (d.qid.path&CHDIR)|(stbuf.st_mode&0777);
6113e12c5d1SDavid du Colombier 			d.atime = stbuf.st_atime;
6123e12c5d1SDavid du Colombier 			d.mtime = stbuf.st_mtime;
613*7dd7cddfSDavid du Colombier 			d.len.hlength = 0;
614*7dd7cddfSDavid du Colombier 			d.len.length = stbuf.st_size;
6153e12c5d1SDavid du Colombier 			convD2M(&d, rdata+n);
6163e12c5d1SDavid du Colombier 			n += DIRLEN;
6173e12c5d1SDavid du Colombier 		}
6183e12c5d1SDavid du Colombier 	}else{
6193e12c5d1SDavid du Colombier 		errno = 0;
620219b2ee8SDavid du Colombier 		if(rf->fd->offset != rhdr.offset){
621219b2ee8SDavid du Colombier 			rf->fd->offset = rhdr.offset;
6223e12c5d1SDavid du Colombier 			if(lseek(rf->fd->fd, rhdr.offset, 0) < 0)
6233e12c5d1SDavid du Colombier 				errjmp(sys_errlist[errno]);
624219b2ee8SDavid du Colombier 		}
6253e12c5d1SDavid du Colombier 		n = read(rf->fd->fd, rdata, rhdr.count);
6263e12c5d1SDavid du Colombier 		if(n < 0)
6273e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
6283e12c5d1SDavid du Colombier 	}
6293e12c5d1SDavid du Colombier 	rf->fd->offset += n;
6303e12c5d1SDavid du Colombier 	thdr.count = n;
6313e12c5d1SDavid du Colombier 	thdr.data = rdata;
6323e12c5d1SDavid du Colombier }
6333e12c5d1SDavid du Colombier 
6343e12c5d1SDavid du Colombier void
6353e12c5d1SDavid du Colombier rwrite(void)
6363e12c5d1SDavid du Colombier {
6373e12c5d1SDavid du Colombier 	Rfile *rf;
6383e12c5d1SDavid du Colombier 	int n;
6393e12c5d1SDavid du Colombier 
640*7dd7cddfSDavid du Colombier 	if(readonly) errjmp("write disallowed");
6413e12c5d1SDavid du Colombier 	rf = rfilefid();
6423e12c5d1SDavid du Colombier 	if(rf->fd == 0)
6433e12c5d1SDavid du Colombier 		errjmp(Enotopen);
6443e12c5d1SDavid du Colombier 	if(rhdr.count > sizeof rdata)
6453e12c5d1SDavid du Colombier 		errjmp(Etoolarge);
6463e12c5d1SDavid du Colombier 	errno = 0;
647219b2ee8SDavid du Colombier 	if(rf->fd->offset != rhdr.offset){
648219b2ee8SDavid du Colombier 		rf->fd->offset = rhdr.offset;
6493e12c5d1SDavid du Colombier 		if(lseek(rf->fd->fd, rhdr.offset, 0) < 0)
6503e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
651219b2ee8SDavid du Colombier 	}
6523e12c5d1SDavid du Colombier 	n = write(rf->fd->fd, rhdr.data, rhdr.count);
6533e12c5d1SDavid du Colombier 	if(n < 0)
6543e12c5d1SDavid du Colombier 		errjmp(sys_errlist[errno]);
6553e12c5d1SDavid du Colombier 	rf->fd->offset += n;
6563e12c5d1SDavid du Colombier 	thdr.count = n;
6573e12c5d1SDavid du Colombier }
6583e12c5d1SDavid du Colombier 
6593e12c5d1SDavid du Colombier void
6603e12c5d1SDavid du Colombier rstat(void)
6613e12c5d1SDavid du Colombier {
6623e12c5d1SDavid du Colombier 	Rfile *rf;
6633e12c5d1SDavid du Colombier 	File *f;
6643e12c5d1SDavid du Colombier 	Dir d;
6653e12c5d1SDavid du Colombier 
6663e12c5d1SDavid du Colombier 	rf = rfilefid();
6673e12c5d1SDavid du Colombier 	f = rf->file;
6683e12c5d1SDavid du Colombier 	errjmp(dostat(f, 0));
6693e12c5d1SDavid du Colombier 	strncpy(d.name, f->name, NAMELEN);
6703e12c5d1SDavid du Colombier 	strncpy(d.uid, id2name(uid, f->stbuf.st_uid), NAMELEN);
6713e12c5d1SDavid du Colombier 	strncpy(d.gid, id2name(gid, f->stbuf.st_gid), NAMELEN);
6723e12c5d1SDavid du Colombier 	d.qid = f->qid;
6733e12c5d1SDavid du Colombier 	d.mode = (f->qid.path&CHDIR)|(f->stbuf.st_mode&0777);
6743e12c5d1SDavid du Colombier 	d.atime = f->stbuf.st_atime;
6753e12c5d1SDavid du Colombier 	d.mtime = f->stbuf.st_mtime;
676*7dd7cddfSDavid du Colombier 	d.len.hlength = 0;
677*7dd7cddfSDavid du Colombier 	d.len.length = f->stbuf.st_size;
6783e12c5d1SDavid du Colombier 	convD2M(&d, thdr.stat);
6793e12c5d1SDavid du Colombier }
6803e12c5d1SDavid du Colombier 
6813e12c5d1SDavid du Colombier void
6823e12c5d1SDavid du Colombier rwstat(void)
6833e12c5d1SDavid du Colombier {
6843e12c5d1SDavid du Colombier 	Rfile *rf;
6853e12c5d1SDavid du Colombier 	File *f;
6863e12c5d1SDavid du Colombier 	Dir d;
6873e12c5d1SDavid du Colombier 	Pass *p;
688*7dd7cddfSDavid du Colombier 	char *path, *dir, name[NAMELEN], *e;
6893e12c5d1SDavid du Colombier 
690*7dd7cddfSDavid du Colombier 	if(readonly) errjmp("write disallowed");
6913e12c5d1SDavid du Colombier 	rf = rfilefid();
6923e12c5d1SDavid du Colombier 	f = rf->file;
6933e12c5d1SDavid du Colombier 	errjmp(dostat(f, 0));
6943e12c5d1SDavid du Colombier 	convM2D(rhdr.stat, &d);
6953e12c5d1SDavid du Colombier 	errno = 0;
6963e12c5d1SDavid du Colombier 	if(strcmp(d.name, f->name) != 0){
6973e12c5d1SDavid du Colombier 		dir = bldpath(f->path, "..", name);
6983e12c5d1SDavid du Colombier 		path = erealloc(0, strlen(dir)+1+strlen(d.name)+1);
6993e12c5d1SDavid du Colombier 		sprintf(path, "%s/%s", dir, d.name);
700*7dd7cddfSDavid du Colombier 		if(rename(f->path, path) < 0){
7013e12c5d1SDavid du Colombier 			free(path);
7023e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
7033e12c5d1SDavid du Colombier 		}
7043e12c5d1SDavid du Colombier 		free(f->path);
7053e12c5d1SDavid du Colombier 		free(f->name);
7063e12c5d1SDavid du Colombier 		f->path = path;
7073e12c5d1SDavid du Colombier 		f->name = estrdup(d.name);
7083e12c5d1SDavid du Colombier 	}
7093e12c5d1SDavid du Colombier 	if((d.mode&0777) != (f->stbuf.st_mode&0777)){
710*7dd7cddfSDavid du Colombier 		f->stbuf.st_mode = (f->stbuf.st_mode&~0777) | (d.mode&0777);
711*7dd7cddfSDavid du Colombier 		if(chmod(f->path, f->stbuf.st_mode) < 0)
7123e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
7133e12c5d1SDavid du Colombier 	}
714*7dd7cddfSDavid du Colombier 	p = name2pass(gidname, d.gid);
715*7dd7cddfSDavid du Colombier 	if(p == 0){
716*7dd7cddfSDavid du Colombier 		if(strtol(d.gid, &e, 10) == f->stbuf.st_gid && *e == 0)
717*7dd7cddfSDavid du Colombier 			return;
7183e12c5d1SDavid du Colombier 		errjmp(Eunknown);
719*7dd7cddfSDavid du Colombier 	}
7203e12c5d1SDavid du Colombier 	if(p->id != f->stbuf.st_gid){
7213e12c5d1SDavid du Colombier 		if(chown(f->path, f->stbuf.st_uid, p->id) < 0)
7223e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
7233e12c5d1SDavid du Colombier 		f->stbuf.st_gid = p->id;
7243e12c5d1SDavid du Colombier 	}
7253e12c5d1SDavid du Colombier }
7263e12c5d1SDavid du Colombier 
7273e12c5d1SDavid du Colombier void
7283e12c5d1SDavid du Colombier rclunk(int rm)
7293e12c5d1SDavid du Colombier {
7303e12c5d1SDavid du Colombier 	int ret;
731*7dd7cddfSDavid du Colombier 	const char *err;
7323e12c5d1SDavid du Colombier 	Rfile *rf;
7333e12c5d1SDavid du Colombier 	File *f;
7343e12c5d1SDavid du Colombier 	Fd *fd;
7353e12c5d1SDavid du Colombier 
7363e12c5d1SDavid du Colombier 	err = 0;
7373e12c5d1SDavid du Colombier 	rf = rfilefid();
7383e12c5d1SDavid du Colombier 	f = rf->file;
7393e12c5d1SDavid du Colombier 	if(rm){
7403e12c5d1SDavid du Colombier 		if(f->qid.path & CHDIR)
7413e12c5d1SDavid du Colombier 			ret = rmdir(f->path);
7423e12c5d1SDavid du Colombier 		else
7433e12c5d1SDavid du Colombier 			ret = unlink(f->path);
7443e12c5d1SDavid du Colombier 		if(ret)
7453e12c5d1SDavid du Colombier 			err = sys_errlist[errno];
746219b2ee8SDavid du Colombier 	}else if(rf->rclose){	/* ignore errors */
747219b2ee8SDavid du Colombier 		if(f->qid.path & CHDIR)
748219b2ee8SDavid du Colombier 			rmdir(f->path);
749219b2ee8SDavid du Colombier 		else
750219b2ee8SDavid du Colombier 			unlink(f->path);
7513e12c5d1SDavid du Colombier 	}
752219b2ee8SDavid du Colombier 
7533e12c5d1SDavid du Colombier 	rf->busy = 0;
7543e12c5d1SDavid du Colombier 	if(--f->ref == 0){
7553e12c5d1SDavid du Colombier 		free(f->path);
7563e12c5d1SDavid du Colombier 		free(f->name);
7573e12c5d1SDavid du Colombier 		free(f);
7583e12c5d1SDavid du Colombier 	}
7593e12c5d1SDavid du Colombier 	fd = rf->fd;
7603e12c5d1SDavid du Colombier 	if(fd){
7613e12c5d1SDavid du Colombier 		if(fd->ref <= 0)
7623e12c5d1SDavid du Colombier 			error("clunk fd count");
7633e12c5d1SDavid du Colombier 		if(--fd->ref == 0){
7643e12c5d1SDavid du Colombier 			if(fd->fd)
7653e12c5d1SDavid du Colombier 				close(fd->fd);
7663e12c5d1SDavid du Colombier 			if(fd->dir)
7673e12c5d1SDavid du Colombier 				closedir(fd->dir);
7683e12c5d1SDavid du Colombier 			free(fd);
7693e12c5d1SDavid du Colombier 		}
7703e12c5d1SDavid du Colombier 		rf->fd = 0;
7713e12c5d1SDavid du Colombier 	}
7723e12c5d1SDavid du Colombier 	if(err)
7733e12c5d1SDavid du Colombier 		errjmp(err);
7743e12c5d1SDavid du Colombier }
7753e12c5d1SDavid du Colombier 
7763e12c5d1SDavid du Colombier char*
7773e12c5d1SDavid du Colombier bldpath(char *a, char *elem, char *name)
7783e12c5d1SDavid du Colombier {
7793e12c5d1SDavid du Colombier 	char *path, *p;
7803e12c5d1SDavid du Colombier 
7813e12c5d1SDavid du Colombier 	if(strcmp(elem, "..") == 0){
7823e12c5d1SDavid du Colombier 		if(strcmp(a, "/") == 0){
7833e12c5d1SDavid du Colombier 			path = estrdup(a);
7843e12c5d1SDavid du Colombier 			strcpy(name, a);
7853e12c5d1SDavid du Colombier 		}else{
7863e12c5d1SDavid du Colombier 			p = strrchr(a, '/');
7873e12c5d1SDavid du Colombier 			if(p == 0){
7883e12c5d1SDavid du Colombier 				fprintf(stderr, "path: '%s'\n", path);
7893e12c5d1SDavid du Colombier 				error("malformed path 1");
7903e12c5d1SDavid du Colombier 			}
7913e12c5d1SDavid du Colombier 			if(p == a)	/* reduced to "/" */
7923e12c5d1SDavid du Colombier 				p++;
7933e12c5d1SDavid du Colombier 			path = erealloc(0, (p-a)+1);
7943e12c5d1SDavid du Colombier 			memmove(path, a, (p-a));
7953e12c5d1SDavid du Colombier 			path[(p-a)] = 0;
7963e12c5d1SDavid du Colombier 			if(strcmp(path, "/") == 0)
7973e12c5d1SDavid du Colombier 				p = path;
7983e12c5d1SDavid du Colombier 			else{
7993e12c5d1SDavid du Colombier 				p = strrchr(path, '/');
8003e12c5d1SDavid du Colombier 				if(p == 0){
8013e12c5d1SDavid du Colombier 					fprintf(stderr, "path: '%s'\n", path);
8023e12c5d1SDavid du Colombier 					error("malformed path 2");
8033e12c5d1SDavid du Colombier 				}
8043e12c5d1SDavid du Colombier 				p++;
8053e12c5d1SDavid du Colombier 			}
806*7dd7cddfSDavid du Colombier 			if(strlen(p) >= NAMELEN)
807*7dd7cddfSDavid du Colombier 				error("bldpath: name too long");
8083e12c5d1SDavid du Colombier 			strcpy(name, p);
8093e12c5d1SDavid du Colombier 		}
8103e12c5d1SDavid du Colombier 	}else{
8113e12c5d1SDavid du Colombier 		if(strcmp(a, "/") == 0)
8123e12c5d1SDavid du Colombier 			a = "";
8133e12c5d1SDavid du Colombier 		path = erealloc(0, strlen(a)+1+strlen(elem)+1);
8143e12c5d1SDavid du Colombier 		sprintf(path, "%s/%s", a, elem);
815*7dd7cddfSDavid du Colombier 		if(strlen(elem) >= NAMELEN)
816*7dd7cddfSDavid du Colombier 			error("bldpath: name too long");
8173e12c5d1SDavid du Colombier 		strcpy(name, elem);
8183e12c5d1SDavid du Colombier 	}
8193e12c5d1SDavid du Colombier 	return path;
8203e12c5d1SDavid du Colombier }
8213e12c5d1SDavid du Colombier 
822*7dd7cddfSDavid du Colombier const char*
8233e12c5d1SDavid du Colombier dostat(File *f, char *elem)
8243e12c5d1SDavid du Colombier {
8253e12c5d1SDavid du Colombier 	char *path;
8263e12c5d1SDavid du Colombier 	struct stat stbuf;
8273e12c5d1SDavid du Colombier 	char name[NAMELEN];
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier 	if(elem)
8303e12c5d1SDavid du Colombier 		path = bldpath(f->path, elem, name);
8313e12c5d1SDavid du Colombier 	else
8323e12c5d1SDavid du Colombier 		path = f->path;
8333e12c5d1SDavid du Colombier 	errno = 0;
8343e12c5d1SDavid du Colombier 	if(stat(path, &stbuf) < 0)
8353e12c5d1SDavid du Colombier 		return sys_errlist[errno];
8363e12c5d1SDavid du Colombier 	if(elem){
8373e12c5d1SDavid du Colombier 		free(f->path);
8383e12c5d1SDavid du Colombier 		f->path = path;
8393e12c5d1SDavid du Colombier 		f->name = estrdup(name);
8403e12c5d1SDavid du Colombier 	}
8413e12c5d1SDavid du Colombier 	f->qid.path = qid(&stbuf);
842219b2ee8SDavid du Colombier 	f->qid.vers = vers(&stbuf);
8433e12c5d1SDavid du Colombier 	f->stbuf = stbuf;
8443e12c5d1SDavid du Colombier 	return 0;
8453e12c5d1SDavid du Colombier }
8463e12c5d1SDavid du Colombier 
8473e12c5d1SDavid du Colombier int
8483e12c5d1SDavid du Colombier omode(int m)
8493e12c5d1SDavid du Colombier {
8503e12c5d1SDavid du Colombier 	switch(m){
8513e12c5d1SDavid du Colombier 	case 0:		/* OREAD */
8523e12c5d1SDavid du Colombier 	case 3:		/* OEXEC */
8533e12c5d1SDavid du Colombier 		return 0;
8543e12c5d1SDavid du Colombier 	case 1:		/* OWRITE */
8553e12c5d1SDavid du Colombier 		return 1;
8563e12c5d1SDavid du Colombier 	case 2:		/* ORDWR */
8573e12c5d1SDavid du Colombier 		return 2;
8583e12c5d1SDavid du Colombier 	}
8593e12c5d1SDavid du Colombier 	errjmp(Emode);
8603e12c5d1SDavid du Colombier 	return 0;
8613e12c5d1SDavid du Colombier }
8623e12c5d1SDavid du Colombier 
8633e12c5d1SDavid du Colombier void
864*7dd7cddfSDavid du Colombier sendmsg(const char *err)
8653e12c5d1SDavid du Colombier {
8663e12c5d1SDavid du Colombier 	int n;
8673e12c5d1SDavid du Colombier 
8683e12c5d1SDavid du Colombier 	if(err){
8693e12c5d1SDavid du Colombier 		thdr.type = Rerror;
8703e12c5d1SDavid du Colombier 		strncpy(thdr.ename, err, ERRLEN);
8713e12c5d1SDavid du Colombier 	}
8723e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, "<< %s\n", mfmt(&thdr)));
8733e12c5d1SDavid du Colombier 	n = convS2M(&thdr, tdata);
8743e12c5d1SDavid du Colombier 	if(n == 0)
8753e12c5d1SDavid du Colombier 		error("bad sendmsg format");
8763e12c5d1SDavid du Colombier 	if(write(1, tdata, n) != n)
8773e12c5d1SDavid du Colombier 		error("write error");
8783e12c5d1SDavid du Colombier }
8793e12c5d1SDavid du Colombier 
8803e12c5d1SDavid du Colombier int
8813e12c5d1SDavid du Colombier okfid(int fid)
8823e12c5d1SDavid du Colombier {
8833e12c5d1SDavid du Colombier 	enum{ Delta=10 };
8843e12c5d1SDavid du Colombier 
8853e12c5d1SDavid du Colombier 	if(fid < 0){
8863e12c5d1SDavid du Colombier 		fprintf(stderr, "u9fs: negative fid %d\n", fid);
8873e12c5d1SDavid du Colombier 		return 0;
8883e12c5d1SDavid du Colombier 	}
8893e12c5d1SDavid du Colombier 	if(fid >= nrfilealloc){
8903e12c5d1SDavid du Colombier 		fid += Delta;
8913e12c5d1SDavid du Colombier 		rfile = erealloc(rfile, fid*sizeof(Rfile));
8923e12c5d1SDavid du Colombier 		memset(rfile+nrfilealloc, 0, (fid-nrfilealloc)*sizeof(Rfile));
8933e12c5d1SDavid du Colombier 		nrfilealloc = fid;
8943e12c5d1SDavid du Colombier 	}
8953e12c5d1SDavid du Colombier 	return 1;
8963e12c5d1SDavid du Colombier }
8973e12c5d1SDavid du Colombier 
8983e12c5d1SDavid du Colombier Rfile*
8993e12c5d1SDavid du Colombier rfilefid(void)
9003e12c5d1SDavid du Colombier {
9013e12c5d1SDavid du Colombier 	Rfile *rf;
9023e12c5d1SDavid du Colombier 
9033e12c5d1SDavid du Colombier 	if(!okfid(rhdr.fid))
9043e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
9053e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
9063e12c5d1SDavid du Colombier 	if(rf->busy == 0)
9073e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
9083e12c5d1SDavid du Colombier 	if(rf->file->ref <= 0)
9093e12c5d1SDavid du Colombier 		error("ref count");
910*7dd7cddfSDavid du Colombier 	setupuser(rf->uid);
9113e12c5d1SDavid du Colombier 	return rf;
9123e12c5d1SDavid du Colombier }
9133e12c5d1SDavid du Colombier 
9143e12c5d1SDavid du Colombier File*
9153e12c5d1SDavid du Colombier newfile(void)
9163e12c5d1SDavid du Colombier {
9173e12c5d1SDavid du Colombier 	File *f;
9183e12c5d1SDavid du Colombier 
9193e12c5d1SDavid du Colombier 	f = erealloc(0, sizeof(File));
9203e12c5d1SDavid du Colombier 	memset(f, 0, sizeof(File));
9213e12c5d1SDavid du Colombier 	f->ref = 1;
9223e12c5d1SDavid du Colombier 	return f;
9233e12c5d1SDavid du Colombier }
9243e12c5d1SDavid du Colombier 
9253e12c5d1SDavid du Colombier /*
9263e12c5d1SDavid du Colombier  * qids: directory bit, seven bits of device, 24 bits of inode
9273e12c5d1SDavid du Colombier  */
9283e12c5d1SDavid du Colombier Ulong
929219b2ee8SDavid du Colombier vers(struct stat *st)
930219b2ee8SDavid du Colombier {
931*7dd7cddfSDavid du Colombier 	return st->st_mtime ^ (st->st_size<<8);
932219b2ee8SDavid du Colombier }
933219b2ee8SDavid du Colombier 
934219b2ee8SDavid du Colombier Ulong
9353e12c5d1SDavid du Colombier qid(struct stat *st)
9363e12c5d1SDavid du Colombier {
9373e12c5d1SDavid du Colombier 	static int nqdev;
9383e12c5d1SDavid du Colombier 	static Uchar *qdev;
9393e12c5d1SDavid du Colombier 	Ulong q;
9403e12c5d1SDavid du Colombier 	int dev;
9413e12c5d1SDavid du Colombier 
942219b2ee8SDavid du Colombier 	if(qdev == 0){
9433e12c5d1SDavid du Colombier 		qdev = erealloc(0, 65536U);
944219b2ee8SDavid du Colombier 		memset(qdev, 0, 65536U);
945219b2ee8SDavid du Colombier 	}
9463e12c5d1SDavid du Colombier 	q = 0;
947219b2ee8SDavid du Colombier 	if((st->st_mode&S_IFMT) ==  S_IFDIR)
9483e12c5d1SDavid du Colombier 		q = CHDIR;
9493e12c5d1SDavid du Colombier 	dev = st->st_dev & 0xFFFFUL;
9503e12c5d1SDavid du Colombier 	if(qdev[dev] == 0){
9513e12c5d1SDavid du Colombier 		if(++nqdev >= 128)
9523e12c5d1SDavid du Colombier 			error("too many devices");
9533e12c5d1SDavid du Colombier 		qdev[dev] = nqdev;
9543e12c5d1SDavid du Colombier 	}
9553e12c5d1SDavid du Colombier 	q |= qdev[dev]<<24;
9563e12c5d1SDavid du Colombier 	q |= st->st_ino & 0x00FFFFFFUL;
9573e12c5d1SDavid du Colombier 	return q;
9583e12c5d1SDavid du Colombier }
9593e12c5d1SDavid du Colombier 
9603e12c5d1SDavid du Colombier Pass*
9613e12c5d1SDavid du Colombier name2pass(Pass **pw, char *name)
9623e12c5d1SDavid du Colombier {
9633e12c5d1SDavid du Colombier 	Pass *p;
9643e12c5d1SDavid du Colombier 
965*7dd7cddfSDavid du Colombier 	for(p = pw[hash(name)]; p; p = p->nnext)
9663e12c5d1SDavid du Colombier 		if(strcmp(name, p->name) == 0)
9673e12c5d1SDavid du Colombier 			return p;
9683e12c5d1SDavid du Colombier 	return 0;
9693e12c5d1SDavid du Colombier }
9703e12c5d1SDavid du Colombier 
971*7dd7cddfSDavid du Colombier Pass*
972*7dd7cddfSDavid du Colombier id2pass(Pass **pw, int id)
973*7dd7cddfSDavid du Colombier {
974*7dd7cddfSDavid du Colombier 	int i;
975*7dd7cddfSDavid du Colombier 	Pass *p, *pp;
976*7dd7cddfSDavid du Colombier 
977*7dd7cddfSDavid du Colombier 	pp = 0;
978*7dd7cddfSDavid du Colombier 	/* use last on list == first in file */
979*7dd7cddfSDavid du Colombier 	i = (id&0xFF) ^ ((id>>8)&0xFF);
980*7dd7cddfSDavid du Colombier 	for(p = pw[i]; p; p = p->next)
981*7dd7cddfSDavid du Colombier 		if(p->id == id)
982*7dd7cddfSDavid du Colombier 			pp = p;
983*7dd7cddfSDavid du Colombier 	return pp;
984*7dd7cddfSDavid du Colombier }
985*7dd7cddfSDavid du Colombier 
9863e12c5d1SDavid du Colombier char*
9873e12c5d1SDavid du Colombier id2name(Pass **pw, int id)
9883e12c5d1SDavid du Colombier {
9893e12c5d1SDavid du Colombier 	int i;
9903e12c5d1SDavid du Colombier 	Pass *p;
9913e12c5d1SDavid du Colombier 	char *s;
992*7dd7cddfSDavid du Colombier 	static char buf[40];
9933e12c5d1SDavid du Colombier 
9943e12c5d1SDavid du Colombier 	s = 0;
9953e12c5d1SDavid du Colombier 	/* use last on list == first in file */
9963e12c5d1SDavid du Colombier 	i = (id&0xFF) ^ ((id>>8)&0xFF);
9973e12c5d1SDavid du Colombier 	for(p = pw[i]; p; p = p->next)
9983e12c5d1SDavid du Colombier 		if(p->id == id)
9993e12c5d1SDavid du Colombier 			s = p->name;
10003e12c5d1SDavid du Colombier 	if(s)
10013e12c5d1SDavid du Colombier 		return s;
10023e12c5d1SDavid du Colombier 	sprintf(buf, "%d", id);
10033e12c5d1SDavid du Colombier 	return buf;
10043e12c5d1SDavid du Colombier }
10053e12c5d1SDavid du Colombier 
10063e12c5d1SDavid du Colombier void
10073e12c5d1SDavid du Colombier freepass(Pass **pass)
10083e12c5d1SDavid du Colombier {
10093e12c5d1SDavid du Colombier 	int i;
10103e12c5d1SDavid du Colombier 	Pass *p, *np;
10113e12c5d1SDavid du Colombier 
10123e12c5d1SDavid du Colombier 	for(i=0; i<256; i++){
10133e12c5d1SDavid du Colombier 		for(p = pass[i]; p; p = np){
10143e12c5d1SDavid du Colombier 			np = p->next;
1015*7dd7cddfSDavid du Colombier 			free(p->mem);
10163e12c5d1SDavid du Colombier 			free(p);
10173e12c5d1SDavid du Colombier 		}
10183e12c5d1SDavid du Colombier 		pass[i] = 0;
10193e12c5d1SDavid du Colombier 	}
10203e12c5d1SDavid du Colombier }
10213e12c5d1SDavid du Colombier 
10223e12c5d1SDavid du Colombier void
1023*7dd7cddfSDavid du Colombier setupuser(int u)
1024*7dd7cddfSDavid du Colombier {
1025*7dd7cddfSDavid du Colombier 	Pass *p;
1026*7dd7cddfSDavid du Colombier 
1027*7dd7cddfSDavid du Colombier 	if(curuid == u || myuid != 0)
1028*7dd7cddfSDavid du Colombier 		return;
1029*7dd7cddfSDavid du Colombier 
1030*7dd7cddfSDavid du Colombier 	p = id2pass(uid, u);
1031*7dd7cddfSDavid du Colombier 	if(p == 0 || p->id == 0 || (uid_t)p->id == (uid_t)-1)
1032*7dd7cddfSDavid du Colombier 		errjmp(Eunknown);
1033*7dd7cddfSDavid du Colombier 
1034*7dd7cddfSDavid du Colombier 	if(setreuid(0, 0) < 0)
1035*7dd7cddfSDavid du Colombier 		error("can't revert to root");
1036*7dd7cddfSDavid du Colombier 
1037*7dd7cddfSDavid du Colombier 	/*
1038*7dd7cddfSDavid du Colombier 	 * this error message is just a likely guess
1039*7dd7cddfSDavid du Colombier 	 */
1040*7dd7cddfSDavid du Colombier 	if(setgroups(p->nmem, p->mem) < 0)
1041*7dd7cddfSDavid du Colombier 		errjmp("member of too many groups");
1042*7dd7cddfSDavid du Colombier 
1043*7dd7cddfSDavid du Colombier 	if(setgid(p->gid) < 0
1044*7dd7cddfSDavid du Colombier 	|| setreuid(0, p->id) < 0)
1045*7dd7cddfSDavid du Colombier 		errjmp(Eunknown);
1046*7dd7cddfSDavid du Colombier }
1047*7dd7cddfSDavid du Colombier 
1048*7dd7cddfSDavid du Colombier void
10493e12c5d1SDavid du Colombier getpwdf(void)
10503e12c5d1SDavid du Colombier {
1051*7dd7cddfSDavid du Colombier 	static int mtime;
10523e12c5d1SDavid du Colombier 	struct stat stbuf;
10533e12c5d1SDavid du Colombier 	struct passwd *pw;
10543e12c5d1SDavid du Colombier 	int i;
10553e12c5d1SDavid du Colombier 	Pass *p;
10563e12c5d1SDavid du Colombier 
1057*7dd7cddfSDavid du Colombier 	if(onlyuser){
1058*7dd7cddfSDavid du Colombier 		i = (myuid&0xFF) ^ ((myuid>>8)&0xFF);
1059*7dd7cddfSDavid du Colombier 		if(uid[i])
1060*7dd7cddfSDavid du Colombier 			return;
1061*7dd7cddfSDavid du Colombier 		p = erealloc(0, sizeof(Pass));
1062*7dd7cddfSDavid du Colombier 		uid[i] = p;
1063*7dd7cddfSDavid du Colombier 		p->name = strdup(onlyuser);
1064*7dd7cddfSDavid du Colombier 		uidname[hash(p->name)] = p;
1065*7dd7cddfSDavid du Colombier 		p->id = myuid;
1066*7dd7cddfSDavid du Colombier 		p->gid = 60001;
1067*7dd7cddfSDavid du Colombier 		p->next = 0;
1068*7dd7cddfSDavid du Colombier 		p->nnext = 0;
1069*7dd7cddfSDavid du Colombier 		p->nmem = 0;
1070*7dd7cddfSDavid du Colombier 		p->mem = 0;
1071*7dd7cddfSDavid du Colombier 		curuid = p->id;
1072*7dd7cddfSDavid du Colombier 		return;
1073*7dd7cddfSDavid du Colombier 	}
1074*7dd7cddfSDavid du Colombier 
1075*7dd7cddfSDavid du Colombier 	curuid = -1;
1076*7dd7cddfSDavid du Colombier 	if(myuid == 0 && setreuid(0, 0) < 0)
1077*7dd7cddfSDavid du Colombier 		error("can't revert to root");
1078*7dd7cddfSDavid du Colombier 
10793e12c5d1SDavid du Colombier 	if(stat("/etc/passwd", &stbuf) < 0)
10803e12c5d1SDavid du Colombier 		error("can't read /etc/passwd");
10813e12c5d1SDavid du Colombier 	if(stbuf.st_mtime <= mtime)
10823e12c5d1SDavid du Colombier 		return;
10833e12c5d1SDavid du Colombier 	freepass(uid);
1084*7dd7cddfSDavid du Colombier 	for(i=0; i<256; i++)
1085*7dd7cddfSDavid du Colombier 		uidname[i] = 0;
1086*7dd7cddfSDavid du Colombier 	for(;;) {
1087*7dd7cddfSDavid du Colombier 		pw = getpwent();
1088*7dd7cddfSDavid du Colombier 		if(!pw)
1089*7dd7cddfSDavid du Colombier 			break;
10903e12c5d1SDavid du Colombier 		i = pw->pw_uid;
10913e12c5d1SDavid du Colombier 		i = (i&0xFF) ^ ((i>>8)&0xFF);
10923e12c5d1SDavid du Colombier 		p = erealloc(0, sizeof(Pass));
10933e12c5d1SDavid du Colombier 		p->next = uid[i];
10943e12c5d1SDavid du Colombier 		uid[i] = p;
10953e12c5d1SDavid du Colombier 		p->id = pw->pw_uid;
10963e12c5d1SDavid du Colombier 		p->gid = pw->pw_gid;
10973e12c5d1SDavid du Colombier 		p->name = estrdup(pw->pw_name);
1098*7dd7cddfSDavid du Colombier 		p->nmem = 1;
1099*7dd7cddfSDavid du Colombier 		p->mem = erealloc(0, sizeof(p->mem[0]));
1100*7dd7cddfSDavid du Colombier 		p->mem[0] = p->gid;
1101*7dd7cddfSDavid du Colombier 		i = hash(p->name);
1102*7dd7cddfSDavid du Colombier 		p->nnext = uidname[i];
1103*7dd7cddfSDavid du Colombier 		uidname[i] = p;
11043e12c5d1SDavid du Colombier 	}
11053e12c5d1SDavid du Colombier 	setpwent();
11063e12c5d1SDavid du Colombier 	endpwent();
11073e12c5d1SDavid du Colombier }
11083e12c5d1SDavid du Colombier 
1109*7dd7cddfSDavid du Colombier int
1110*7dd7cddfSDavid du Colombier ismem(Pass *u, int gid)
1111*7dd7cddfSDavid du Colombier {
1112*7dd7cddfSDavid du Colombier 	int i;
1113*7dd7cddfSDavid du Colombier 
1114*7dd7cddfSDavid du Colombier 	if(u->gid == gid)
1115*7dd7cddfSDavid du Colombier 		return 1;
1116*7dd7cddfSDavid du Colombier 	for(i = 0; i < u->nmem; i++)
1117*7dd7cddfSDavid du Colombier 		if(u->mem[i] == gid)
1118*7dd7cddfSDavid du Colombier 			return 1;
1119*7dd7cddfSDavid du Colombier 	return 0;
1120*7dd7cddfSDavid du Colombier }
1121*7dd7cddfSDavid du Colombier 
11223e12c5d1SDavid du Colombier void
11233e12c5d1SDavid du Colombier getgrpf(void)
11243e12c5d1SDavid du Colombier {
1125*7dd7cddfSDavid du Colombier 	static int mtime;
11263e12c5d1SDavid du Colombier 	struct stat stbuf;
11273e12c5d1SDavid du Colombier 	struct group *pw;
1128*7dd7cddfSDavid du Colombier 	int i, m;
1129*7dd7cddfSDavid du Colombier 	Pass *p, *u;
11303e12c5d1SDavid du Colombier 
1131*7dd7cddfSDavid du Colombier 	if(onlyuser)
1132*7dd7cddfSDavid du Colombier 		return;
1133*7dd7cddfSDavid du Colombier 
1134*7dd7cddfSDavid du Colombier 	if(stat("/etc/group", &stbuf) < 0
1135*7dd7cddfSDavid du Colombier 	|| stbuf.st_mtime <= mtime)
11363e12c5d1SDavid du Colombier 		return;
11373e12c5d1SDavid du Colombier 	freepass(gid);
1138*7dd7cddfSDavid du Colombier 	for(i=0; i<256; i++)
1139*7dd7cddfSDavid du Colombier 		gidname[i] = 0;
1140*7dd7cddfSDavid du Colombier 	for(;;) {
1141*7dd7cddfSDavid du Colombier 		pw = getgrent();
1142*7dd7cddfSDavid du Colombier 		if(!pw)
1143*7dd7cddfSDavid du Colombier 			break;
11443e12c5d1SDavid du Colombier 		i = pw->gr_gid;
11453e12c5d1SDavid du Colombier 		i = (i&0xFF) ^ ((i>>8)&0xFF);
11463e12c5d1SDavid du Colombier 		p = erealloc(0, sizeof(Pass));
11473e12c5d1SDavid du Colombier 		p->next = gid[i];
11483e12c5d1SDavid du Colombier 		gid[i] = p;
11493e12c5d1SDavid du Colombier 		p->id = pw->gr_gid;
11503e12c5d1SDavid du Colombier 		p->gid = 0;
11513e12c5d1SDavid du Colombier 		p->name = estrdup(pw->gr_name);
1152*7dd7cddfSDavid du Colombier 		i = hash(p->name);
1153*7dd7cddfSDavid du Colombier 		p->nnext = gidname[i];
1154*7dd7cddfSDavid du Colombier 		gidname[i] = p;
1155*7dd7cddfSDavid du Colombier 
1156*7dd7cddfSDavid du Colombier 		for(m=0; pw->gr_mem[m]; m++)
1157*7dd7cddfSDavid du Colombier 			;
1158*7dd7cddfSDavid du Colombier 		p->nmem = m;
1159*7dd7cddfSDavid du Colombier 		p->mem = 0;
1160*7dd7cddfSDavid du Colombier 		if(m != 0)
1161*7dd7cddfSDavid du Colombier 			p->mem = erealloc(0, m*sizeof(p->mem[0]));
1162*7dd7cddfSDavid du Colombier 		for(m = 0; m<p->nmem; m++){
1163*7dd7cddfSDavid du Colombier 			u = name2pass(uidname, pw->gr_mem[m]);
1164*7dd7cddfSDavid du Colombier 			p->mem[m] = -1;
1165*7dd7cddfSDavid du Colombier 			if(u){
1166*7dd7cddfSDavid du Colombier 				p->mem[m] = u->id;
1167*7dd7cddfSDavid du Colombier 				if(!ismem(u, p->id)){
1168*7dd7cddfSDavid du Colombier 					u->mem = erealloc(u->mem, (u->nmem+1)*sizeof(u->mem[0]));
1169*7dd7cddfSDavid du Colombier 					u->mem[u->nmem++] = p->id;
1170*7dd7cddfSDavid du Colombier 				}
1171*7dd7cddfSDavid du Colombier 			}
1172*7dd7cddfSDavid du Colombier 		}
11733e12c5d1SDavid du Colombier 	}
11743e12c5d1SDavid du Colombier 	setgrent();
11753e12c5d1SDavid du Colombier 	endgrent();
11763e12c5d1SDavid du Colombier }
11773e12c5d1SDavid du Colombier 
1178*7dd7cddfSDavid du Colombier int
1179*7dd7cddfSDavid du Colombier hash(char *s)
1180*7dd7cddfSDavid du Colombier {
1181*7dd7cddfSDavid du Colombier 	int h;
1182*7dd7cddfSDavid du Colombier 
1183*7dd7cddfSDavid du Colombier 	h = 0;
1184*7dd7cddfSDavid du Colombier 	for(; *s; s++)
1185*7dd7cddfSDavid du Colombier 		h = (h << 1) ^ *s;
1186*7dd7cddfSDavid du Colombier 	return h & 255;
1187*7dd7cddfSDavid du Colombier }
1188*7dd7cddfSDavid du Colombier 
11893e12c5d1SDavid du Colombier void
11903e12c5d1SDavid du Colombier error(char *s)
11913e12c5d1SDavid du Colombier {
11923e12c5d1SDavid du Colombier 	fprintf(stderr, "u9fs: %s\n", s);
11933e12c5d1SDavid du Colombier 	perror("unix error");
11943e12c5d1SDavid du Colombier 	exit(1);
11953e12c5d1SDavid du Colombier }
11963e12c5d1SDavid du Colombier 
11973e12c5d1SDavid du Colombier void
1198*7dd7cddfSDavid du Colombier errjmp(const char *s)
11993e12c5d1SDavid du Colombier {
12003e12c5d1SDavid du Colombier 	if(s == 0)
12013e12c5d1SDavid du Colombier 		return;
12023e12c5d1SDavid du Colombier 	sendmsg(s);
12033e12c5d1SDavid du Colombier 	longjmp(loopjmp, 1);
12043e12c5d1SDavid du Colombier }
12053e12c5d1SDavid du Colombier 
12063e12c5d1SDavid du Colombier void*
12073e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
12083e12c5d1SDavid du Colombier {
12093e12c5d1SDavid du Colombier 	if(p == 0)
12103e12c5d1SDavid du Colombier 		p = malloc(n);
12113e12c5d1SDavid du Colombier 	else
12123e12c5d1SDavid du Colombier 		p = realloc(p, n);
12133e12c5d1SDavid du Colombier 	if(p == 0)
12143e12c5d1SDavid du Colombier 		error("realloc fail");
12153e12c5d1SDavid du Colombier 	return p;
12163e12c5d1SDavid du Colombier }
12173e12c5d1SDavid du Colombier 
12183e12c5d1SDavid du Colombier char*
12193e12c5d1SDavid du Colombier estrdup(char *p)
12203e12c5d1SDavid du Colombier {
12213e12c5d1SDavid du Colombier 	p = strdup(p);
12223e12c5d1SDavid du Colombier 	if(p == 0)
12233e12c5d1SDavid du Colombier 		error("strdup fail");
12243e12c5d1SDavid du Colombier 	return p;
12253e12c5d1SDavid du Colombier }
1226219b2ee8SDavid du Colombier 
1227219b2ee8SDavid du Colombier #ifdef SOCKETS
1228219b2ee8SDavid du Colombier void
1229219b2ee8SDavid du Colombier remotehostname(void)
1230219b2ee8SDavid du Colombier {
1231219b2ee8SDavid du Colombier 	struct sockaddr_in sock;
1232219b2ee8SDavid du Colombier 	struct hostent *hp;
1233219b2ee8SDavid du Colombier 	int len;
1234219b2ee8SDavid du Colombier 	int on = 1;
1235219b2ee8SDavid du Colombier 
1236219b2ee8SDavid du Colombier 	len = sizeof sock;
1237*7dd7cddfSDavid du Colombier 	if(getpeername(0, (struct sockaddr*)&sock, &len) < 0)
1238219b2ee8SDavid du Colombier 		error("getpeername");
1239219b2ee8SDavid du Colombier 	hp = gethostbyaddr((char *)&sock.sin_addr, sizeof (struct in_addr),
1240219b2ee8SDavid du Colombier 		sock.sin_family);
1241219b2ee8SDavid du Colombier 	if(hp == 0)
1242219b2ee8SDavid du Colombier 		error("gethostbyaddr");
1243*7dd7cddfSDavid du Colombier 	strncpy(bsdhost, hp->h_name, sizeof(bsdhost)-1);
1244*7dd7cddfSDavid du Colombier 	bsdhost[sizeof(bsdhost)-1] = '\0';
1245219b2ee8SDavid du Colombier 	fprintf(stderr, "bsdhost %s on %d\n", bsdhost, getpid());
1246*7dd7cddfSDavid du Colombier 	strcpy(ipaddr, inet_ntoa(sock.sin_addr));
1247219b2ee8SDavid du Colombier 
1248*7dd7cddfSDavid du Colombier 	setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
1249219b2ee8SDavid du Colombier }
1250219b2ee8SDavid du Colombier #endif
1251