xref: /plan9/sys/src/cmd/unix/u9fs/u9fs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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
19*219b2ee8SDavid 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
28*219b2ee8SDavid du Colombier #	define	SOCKETS
29*219b2ee8SDavid du Colombier #endif
30*219b2ee8SDavid du Colombier #ifdef SOCKETS
31*219b2ee8SDavid du Colombier #	define sendmsg	__sendmsg
32*219b2ee8SDavid du Colombier #	include <sys/socket.h>
33*219b2ee8SDavid du Colombier #	include <netinet/in.h>
34*219b2ee8SDavid du Colombier #	include <netdb.h>
35*219b2ee8SDavid du Colombier #	undef sendmsg
36*219b2ee8SDavid du Colombier 	char	bsdhost[256];
37*219b2ee8SDavid du Colombier 	void	remotehostname(void);
383e12c5d1SDavid du Colombier #endif
393e12c5d1SDavid du Colombier 
403e12c5d1SDavid du Colombier typedef struct File	File;
413e12c5d1SDavid du Colombier typedef struct Rfile	Rfile;
423e12c5d1SDavid du Colombier typedef struct Fd	Fd;
433e12c5d1SDavid du Colombier typedef struct Pass	Pass;
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier struct Fd{
463e12c5d1SDavid du Colombier 	int		ref;
473e12c5d1SDavid du Colombier 	Ulong		offset;
483e12c5d1SDavid du Colombier 	int		fd;
493e12c5d1SDavid du Colombier 	DIR		*dir;
503e12c5d1SDavid du Colombier };
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier struct Rfile{
533e12c5d1SDavid du Colombier 	int		busy;
543e12c5d1SDavid du Colombier 	int		uid;
553e12c5d1SDavid du Colombier 	int		gid;
56*219b2ee8SDavid du Colombier 	int		rclose;
573e12c5d1SDavid du Colombier 	File		*file;
583e12c5d1SDavid du Colombier 	Fd		*fd;
593e12c5d1SDavid du Colombier };
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier struct File{
623e12c5d1SDavid du Colombier 	int		ref;
633e12c5d1SDavid du Colombier 	char		*path;
643e12c5d1SDavid du Colombier 	char		*name;
653e12c5d1SDavid du Colombier 	Qid		qid;
663e12c5d1SDavid du Colombier 	struct stat	stbuf;
673e12c5d1SDavid du Colombier };
683e12c5d1SDavid du Colombier 
693e12c5d1SDavid du Colombier struct Pass{
703e12c5d1SDavid du Colombier 	int		id;
713e12c5d1SDavid du Colombier 	int		gid;
723e12c5d1SDavid du Colombier 	char		*name;
733e12c5d1SDavid du Colombier 	Pass		*next;
743e12c5d1SDavid du Colombier };
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier char	data[2][MAXMSG+MAXFDATA];
773e12c5d1SDavid du Colombier char	tdata[MAXMSG+MAXFDATA];
783e12c5d1SDavid du Colombier char	rdata[MAXFDATA];
793e12c5d1SDavid du Colombier Fcall	rhdr;
803e12c5d1SDavid du Colombier Fcall	thdr;
813e12c5d1SDavid du Colombier Rfile	*rfile;
823e12c5d1SDavid du Colombier File	*file0;
833e12c5d1SDavid du Colombier int	nrfilealloc;
843e12c5d1SDavid du Colombier jmp_buf	loopjmp;
853e12c5d1SDavid du Colombier Pass*	uid[256];
863e12c5d1SDavid du Colombier Pass*	gid[256];
873e12c5d1SDavid du Colombier int	devallowed;
883e12c5d1SDavid du Colombier int	connected;
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier void	io(void);
913e12c5d1SDavid du Colombier void	error(char*);
923e12c5d1SDavid du Colombier char	*mfmt(Fcall*);
933e12c5d1SDavid du Colombier void	sendmsg(char*);
943e12c5d1SDavid du Colombier int	okfid(int);
953e12c5d1SDavid du Colombier Rfile*	rfilefid(void);
963e12c5d1SDavid du Colombier File*	newfile(void);
973e12c5d1SDavid du Colombier void*	erealloc(void*, unsigned);
983e12c5d1SDavid du Colombier char*	estrdup(char*);
993e12c5d1SDavid du Colombier char*	dostat(File*, char*);
1003e12c5d1SDavid du Colombier char*	bldpath(char*, char*, char*);
1013e12c5d1SDavid du Colombier Ulong	qid(struct stat*);
102*219b2ee8SDavid du Colombier Ulong	vers(struct stat*);
1033e12c5d1SDavid du Colombier void	errjmp(char*);
1043e12c5d1SDavid du Colombier int	omode(int);
1053e12c5d1SDavid du Colombier char*	id2name(Pass**, int);
1063e12c5d1SDavid du Colombier Pass*	name2pass(Pass**, char*);
1073e12c5d1SDavid du Colombier void	getpwdf(void);
1083e12c5d1SDavid du Colombier void	getgrpf(void);
1093e12c5d1SDavid du Colombier void	perm(Rfile*, int, struct stat*);
1103e12c5d1SDavid du Colombier void	parentwrperm(Rfile*);
1113e12c5d1SDavid du Colombier 
112*219b2ee8SDavid du Colombier void	rsession(void);
1133e12c5d1SDavid du Colombier void	rattach(void);
1143e12c5d1SDavid du Colombier void	rflush(void);
1153e12c5d1SDavid du Colombier void	rclone(void);
1163e12c5d1SDavid du Colombier void	rwalk(void);
1173e12c5d1SDavid du Colombier void	ropen(void);
1183e12c5d1SDavid du Colombier void	rcreate(void);
1193e12c5d1SDavid du Colombier void	rread(void);
1203e12c5d1SDavid du Colombier void	rwrite(void);
1213e12c5d1SDavid du Colombier void	rclunk(int);
1223e12c5d1SDavid du Colombier void	rstat(void);
1233e12c5d1SDavid du Colombier void	rwstat(void);
1243e12c5d1SDavid du Colombier void	rclwalk(void);
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier char	Eauth[] =	"authentication failed";
1273e12c5d1SDavid du Colombier char	Eperm[] =	"permission denied";
1283e12c5d1SDavid du Colombier char	Ebadfid[] =	"fid unknown or out of range";
1293e12c5d1SDavid du Colombier char	Efidactive[] =	"fid already in use";
1303e12c5d1SDavid du Colombier char	Eopen[] =	"file is open";
1313e12c5d1SDavid du Colombier char	Emode[] =	"invalid open mode";
1323e12c5d1SDavid du Colombier char	Especial[] =	"no access to special file";
1333e12c5d1SDavid du Colombier char	Especial0[] =	"already attached without access to special files";
1343e12c5d1SDavid du Colombier char	Especial1[] =	"already attached with access to special files";
1353e12c5d1SDavid du Colombier char	Enotopen[] =	"file is not open";
1363e12c5d1SDavid du Colombier char	Etoolarge[] =	"i/o count too large";
1373e12c5d1SDavid du Colombier char	Ebaddir[] =	"i/o error on directory";
1383e12c5d1SDavid du Colombier char	Eunknown[] =	"unknown user or group";
1393e12c5d1SDavid du Colombier char	Euid[] =	"can't set uid";
1403e12c5d1SDavid du Colombier char	Egid[] =	"can't set gid";
1413e12c5d1SDavid du Colombier char	Eowner[] =	"not owner";
1423e12c5d1SDavid du Colombier 
1433e12c5d1SDavid du Colombier int
1443e12c5d1SDavid du Colombier main(int argc, char *argv[])
1453e12c5d1SDavid du Colombier {
1463e12c5d1SDavid du Colombier 	freopen(LOG, "a", stderr);
1473e12c5d1SDavid du Colombier 	setbuf(stderr, (void*)0);
1483e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, "u9fs\nkill %d\n", getpid()));
1493e12c5d1SDavid du Colombier 	if(argc > 1)
1503e12c5d1SDavid du Colombier 		if(chroot(argv[1]) == -1)
1513e12c5d1SDavid du Colombier 			error("chroot failed");
152*219b2ee8SDavid du Colombier 
153*219b2ee8SDavid du Colombier #	ifdef SOCKETS
154*219b2ee8SDavid du Colombier 	remotehostname();
155*219b2ee8SDavid du Colombier #	endif
156*219b2ee8SDavid du Colombier 
1573e12c5d1SDavid du Colombier 	io();
1583e12c5d1SDavid du Colombier 	return 0;
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier 
1613e12c5d1SDavid du Colombier void
1623e12c5d1SDavid du Colombier io(void)
1633e12c5d1SDavid du Colombier {
1643e12c5d1SDavid du Colombier 	int m;
1653e12c5d1SDavid du Colombier 	static int toggle, ndata;
1663e12c5d1SDavid du Colombier 	char *datap;
1673e12c5d1SDavid du Colombier 
1683e12c5d1SDavid du Colombier 	/*
1693e12c5d1SDavid du Colombier 	 * TCP does not preserve record boundaries; this dance works around
1703e12c5d1SDavid du Colombier 	 * the problem.
1713e12c5d1SDavid du Colombier 	 */
1723e12c5d1SDavid du Colombier 	setjmp(loopjmp);
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	/*
1753e12c5d1SDavid du Colombier 	 * Invariant: data[toggle] has ndata bytes already
1763e12c5d1SDavid du Colombier 	 */
1773e12c5d1SDavid du Colombier     loop:
1783e12c5d1SDavid du Colombier 	datap = data[toggle];
1793e12c5d1SDavid du Colombier 	toggle ^= 1;
1803e12c5d1SDavid du Colombier 	for(;;){
1813e12c5d1SDavid du Colombier 		if(ndata){
1823e12c5d1SDavid du Colombier 			m = convM2S(datap, &rhdr, ndata);
1833e12c5d1SDavid du Colombier 			/* m is number of bytes more than a full message */
1843e12c5d1SDavid du Colombier 			if(m >= 0){
1853e12c5d1SDavid du Colombier 				memmove(data[toggle], datap+(ndata-m), m);
1863e12c5d1SDavid du Colombier 				ndata = m;
1873e12c5d1SDavid du Colombier 				break;
1883e12c5d1SDavid du Colombier 			}
1893e12c5d1SDavid du Colombier 		}
1903e12c5d1SDavid du Colombier 		m = read(0, datap+ndata, (MAXMSG+MAXFDATA)-ndata);
1913e12c5d1SDavid du Colombier 		if(m <= 0)
1923e12c5d1SDavid du Colombier 			error("read");
1933e12c5d1SDavid du Colombier 		ndata += m;
1943e12c5d1SDavid du Colombier 	}
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier 	thdr.type = rhdr.type+1;
1973e12c5d1SDavid du Colombier 	thdr.tag = rhdr.tag;
1983e12c5d1SDavid du Colombier 	thdr.fid = rhdr.fid;
1993e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, ">> %s\n", mfmt(&rhdr)));
2003e12c5d1SDavid du Colombier 	switch(rhdr.type){
2013e12c5d1SDavid du Colombier 	case Tnop:
2023e12c5d1SDavid du Colombier 	case Tflush:	/* this is a synchronous fs; easy */
2033e12c5d1SDavid du Colombier 		break;
204*219b2ee8SDavid du Colombier 	case Tsession:
205*219b2ee8SDavid du Colombier 		rsession();
2063e12c5d1SDavid du Colombier 		break;
2073e12c5d1SDavid du Colombier 	case Tattach:
2083e12c5d1SDavid du Colombier 		rattach();
2093e12c5d1SDavid du Colombier 		break;
2103e12c5d1SDavid du Colombier 	case Tclone:
2113e12c5d1SDavid du Colombier 		rclone();
2123e12c5d1SDavid du Colombier 		break;
2133e12c5d1SDavid du Colombier 	case Twalk:
2143e12c5d1SDavid du Colombier 		rwalk();
2153e12c5d1SDavid du Colombier 		break;
2163e12c5d1SDavid du Colombier 	case Tstat:
2173e12c5d1SDavid du Colombier 		rstat();
2183e12c5d1SDavid du Colombier 		break;
2193e12c5d1SDavid du Colombier 	case Twstat:
2203e12c5d1SDavid du Colombier 		rwstat();
2213e12c5d1SDavid du Colombier 		break;
2223e12c5d1SDavid du Colombier 	case Topen:
2233e12c5d1SDavid du Colombier 		ropen();
2243e12c5d1SDavid du Colombier 		break;
2253e12c5d1SDavid du Colombier 	case Tcreate:
2263e12c5d1SDavid du Colombier 		rcreate();
2273e12c5d1SDavid du Colombier 		break;
2283e12c5d1SDavid du Colombier 	case Tread:
2293e12c5d1SDavid du Colombier 		rread();
2303e12c5d1SDavid du Colombier 		break;
2313e12c5d1SDavid du Colombier 	case Twrite:
2323e12c5d1SDavid du Colombier 		rwrite();
2333e12c5d1SDavid du Colombier 		break;
2343e12c5d1SDavid du Colombier 	case Tclunk:
2353e12c5d1SDavid du Colombier 		rclunk(0);
2363e12c5d1SDavid du Colombier 		break;
2373e12c5d1SDavid du Colombier 	case Tremove:
2383e12c5d1SDavid du Colombier 		rclunk(1);
2393e12c5d1SDavid du Colombier 		break;
2403e12c5d1SDavid du Colombier 	default:
2413e12c5d1SDavid du Colombier 		fprintf(stderr, "unknown message %s\n", mfmt(&rhdr));
2423e12c5d1SDavid du Colombier 		error("bad message");
2433e12c5d1SDavid du Colombier 	}
2443e12c5d1SDavid du Colombier 	sendmsg(0);
2453e12c5d1SDavid du Colombier 	goto loop;
2463e12c5d1SDavid du Colombier }
2473e12c5d1SDavid du Colombier 
2483e12c5d1SDavid du Colombier void
249*219b2ee8SDavid du Colombier rsession(void)
2503e12c5d1SDavid du Colombier {
251*219b2ee8SDavid du Colombier 	memset(thdr.authid, 0, sizeof(thdr.authid));
252*219b2ee8SDavid du Colombier 	memset(thdr.authdom, 0, sizeof(thdr.authdom));
253*219b2ee8SDavid du Colombier 	memset(thdr.chal, 0, sizeof(thdr.chal));
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier void
2573e12c5d1SDavid du Colombier rattach(void)
2583e12c5d1SDavid du Colombier {
2593e12c5d1SDavid du Colombier 	Rfile *rf;
2603e12c5d1SDavid du Colombier 	char *err;
2613e12c5d1SDavid du Colombier 	Pass *p;
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 	err = 0;
2643e12c5d1SDavid du Colombier 	if(file0 == 0){
2653e12c5d1SDavid du Colombier 		file0 = newfile();
2663e12c5d1SDavid du Colombier 		file0->ref++;		/* one extra to hold it up */
2673e12c5d1SDavid du Colombier 		file0->path = estrdup("/");
2683e12c5d1SDavid du Colombier 		file0->name = estrdup("/");
2693e12c5d1SDavid du Colombier 		errjmp(dostat(file0, 0));
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier 	if(!okfid(rhdr.fid))
2723e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
2733e12c5d1SDavid du Colombier 	if(strncmp(rhdr.aname, "device", 6) == 0){
2743e12c5d1SDavid du Colombier 		if(connected && !devallowed)
2753e12c5d1SDavid du Colombier 			errjmp(Especial0);
2763e12c5d1SDavid du Colombier 		devallowed = 1;
2773e12c5d1SDavid du Colombier 	}else{
2783e12c5d1SDavid du Colombier 		if(connected && devallowed)
2793e12c5d1SDavid du Colombier 			errjmp(Especial1);
2803e12c5d1SDavid du Colombier 	}
2813e12c5d1SDavid du Colombier 	getpwdf();
2823e12c5d1SDavid du Colombier 	getgrpf();
2833e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
2843e12c5d1SDavid du Colombier 	if(rf->busy)
2853e12c5d1SDavid du Colombier 		errjmp(Efidactive);
2863e12c5d1SDavid du Colombier 	p = name2pass(uid, rhdr.uname);
2873e12c5d1SDavid du Colombier 	if(p == 0)
2883e12c5d1SDavid du Colombier 		errjmp(Eunknown);
289*219b2ee8SDavid du Colombier 	if(p->id == 0)
290*219b2ee8SDavid du Colombier 		errjmp(Eperm);
291*219b2ee8SDavid du Colombier #	ifdef SOCKETS
292*219b2ee8SDavid du Colombier 	if(ruserok(bsdhost, 0, rhdr.uname, rhdr.uname) < 0)
293*219b2ee8SDavid du Colombier 		errjmp(Eperm);
294*219b2ee8SDavid du Colombier #	endif
295*219b2ee8SDavid du Colombier 	/* mark busy & inc ref cnt only after committed to succeed */
296*219b2ee8SDavid du Colombier 	rf->busy = 1;
297*219b2ee8SDavid du Colombier 	rf->file = file0;
298*219b2ee8SDavid du Colombier 	file0->ref++;
299*219b2ee8SDavid du Colombier 	rf->rclose = 0;
3003e12c5d1SDavid du Colombier 	rf->uid = p->id;
3013e12c5d1SDavid du Colombier 	rf->gid = p->gid;
3023e12c5d1SDavid du Colombier 	thdr.qid = file0->qid;
3033e12c5d1SDavid du Colombier 	connected = 1;
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier void
3073e12c5d1SDavid du Colombier rclone(void)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	Rfile *rf, *nrf;
3103e12c5d1SDavid du Colombier 	File *f;
3113e12c5d1SDavid du Colombier 
3123e12c5d1SDavid du Colombier 	rfilefid();
3133e12c5d1SDavid du Colombier 	if(!okfid(rhdr.newfid))
3143e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
3153e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
3163e12c5d1SDavid du Colombier 	nrf = &rfile[rhdr.newfid];
3173e12c5d1SDavid du Colombier 	f = rf->file;
3183e12c5d1SDavid du Colombier 	if(nrf->busy)
3193e12c5d1SDavid du Colombier 		errjmp(Efidactive);
3203e12c5d1SDavid du Colombier 	nrf->busy = 1;
3213e12c5d1SDavid du Colombier 	nrf->file = f;
3223e12c5d1SDavid du Colombier 	f->ref++;
3233e12c5d1SDavid du Colombier 	nrf->fd = rf->fd;
3243e12c5d1SDavid du Colombier 	nrf->uid = rf->uid;
3253e12c5d1SDavid du Colombier 	nrf->gid = rf->gid;
326*219b2ee8SDavid du Colombier 	nrf->rclose = rf->rclose;
3273e12c5d1SDavid du Colombier 	if(nrf->fd){
3283e12c5d1SDavid du Colombier 		if(nrf->fd->ref == 0)
3293e12c5d1SDavid du Colombier 			error("clone fd count");
3303e12c5d1SDavid du Colombier 		nrf->fd->ref++;
3313e12c5d1SDavid du Colombier 	}
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier void
3353e12c5d1SDavid du Colombier rwalk(void)
3363e12c5d1SDavid du Colombier {
3373e12c5d1SDavid du Colombier 	char *err;
3383e12c5d1SDavid du Colombier 	Rfile *rf;
3393e12c5d1SDavid du Colombier 	File *of, *f;
3403e12c5d1SDavid du Colombier 
3413e12c5d1SDavid du Colombier 	rf = rfilefid();
3423e12c5d1SDavid du Colombier 	if(rf->fd)
3433e12c5d1SDavid du Colombier 		errjmp(Eopen);
3443e12c5d1SDavid du Colombier 	of = rf->file;
3453e12c5d1SDavid du Colombier 	perm(rf, 1, 0);
3463e12c5d1SDavid du Colombier 	f = newfile();
3473e12c5d1SDavid du Colombier 	f->path = estrdup(of->path);
3483e12c5d1SDavid du Colombier 	err = dostat(f, rhdr.name);
3493e12c5d1SDavid du Colombier 	if(err){
3503e12c5d1SDavid du Colombier 		f->ref = 0;
3513e12c5d1SDavid du Colombier 		free(f->path);
3523e12c5d1SDavid du Colombier 		errjmp(err);
3533e12c5d1SDavid du Colombier 	}
3543e12c5d1SDavid du Colombier 	if(of->ref <= 0)
3553e12c5d1SDavid du Colombier 		error("walk ref count");
3563e12c5d1SDavid du Colombier 	if(--of->ref == 0){
3573e12c5d1SDavid du Colombier 		free(of->path);
3583e12c5d1SDavid du Colombier 		free(of->name);
3593e12c5d1SDavid du Colombier 		free(of);
3603e12c5d1SDavid du Colombier 	}
3613e12c5d1SDavid du Colombier 	rf->file = f;
3623e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier 
3653e12c5d1SDavid du Colombier void
3663e12c5d1SDavid du Colombier ropen(void)
3673e12c5d1SDavid du Colombier {
3683e12c5d1SDavid du Colombier 	Rfile *rf;
3693e12c5d1SDavid du Colombier 	File *f;
3703e12c5d1SDavid du Colombier 	int fd;
3713e12c5d1SDavid du Colombier 	DIR *dir;
3723e12c5d1SDavid du Colombier 	int m, trunc;
3733e12c5d1SDavid du Colombier 
3743e12c5d1SDavid du Colombier 	rf = rfilefid();
3753e12c5d1SDavid du Colombier 	f = rf->file;
3763e12c5d1SDavid du Colombier 	if(rf->fd)
3773e12c5d1SDavid du Colombier 		error("open already open");
3783e12c5d1SDavid du Colombier 	if(!devallowed && (f->stbuf.st_mode & S_IFCHR))
3793e12c5d1SDavid du Colombier 		errjmp(Especial);
3803e12c5d1SDavid du Colombier 	m = rhdr.mode & (16|3);
3813e12c5d1SDavid du Colombier 	trunc = m & 16;	/* OTRUNC */
3823e12c5d1SDavid du Colombier 	switch(m){
3833e12c5d1SDavid du Colombier 	case 0:
3843e12c5d1SDavid du Colombier 		perm(rf, 4, 0);
3853e12c5d1SDavid du Colombier 		break;
3863e12c5d1SDavid du Colombier 	case 1:
3873e12c5d1SDavid du Colombier 	case 1|16:
3883e12c5d1SDavid du Colombier 		perm(rf, 2, 0);
3893e12c5d1SDavid du Colombier 		break;
3903e12c5d1SDavid du Colombier 	case 2:
3913e12c5d1SDavid du Colombier 	case 0|16:
3923e12c5d1SDavid du Colombier 	case 2|16:
3933e12c5d1SDavid du Colombier 		perm(rf, 4, 0);
3943e12c5d1SDavid du Colombier 		perm(rf, 2, 0);
3953e12c5d1SDavid du Colombier 		break;
3963e12c5d1SDavid du Colombier 	case 3:
3973e12c5d1SDavid du Colombier 		perm(rf, 1, 0);
3983e12c5d1SDavid du Colombier 		break;
3993e12c5d1SDavid du Colombier 	default:
4003e12c5d1SDavid du Colombier 		errjmp(Emode);
4013e12c5d1SDavid du Colombier 	}
4023e12c5d1SDavid du Colombier 
403bd389b36SDavid du Colombier 	m = omode(m & 3);
4043e12c5d1SDavid du Colombier 	errno = 0;
4053e12c5d1SDavid du Colombier 	if(f->qid.path & CHDIR){
4063e12c5d1SDavid du Colombier 		if(rhdr.mode != 0)		/* OREAD */
4073e12c5d1SDavid du Colombier 			errjmp(Eperm);
4083e12c5d1SDavid du Colombier 		dir = opendir(f->path);
4093e12c5d1SDavid du Colombier 		if(dir == 0)
4103e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4113e12c5d1SDavid du Colombier 		fd = 0;
4123e12c5d1SDavid du Colombier 	}else{
4133e12c5d1SDavid du Colombier 		if(trunc){
4143e12c5d1SDavid du Colombier 			fd = creat(f->path, 0666);
4153e12c5d1SDavid du Colombier 			if(fd >= 0)
4163e12c5d1SDavid du Colombier 				if(m != 1){
4173e12c5d1SDavid du Colombier 					close(fd);
4183e12c5d1SDavid du Colombier 					fd = open(f->path, m);
4193e12c5d1SDavid du Colombier 				}
4203e12c5d1SDavid du Colombier 		}else
4213e12c5d1SDavid du Colombier 			fd = open(f->path, m);
4223e12c5d1SDavid du Colombier 		if(fd < 0)
4233e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4243e12c5d1SDavid du Colombier 		dir = 0;
4253e12c5d1SDavid du Colombier 	}
426*219b2ee8SDavid du Colombier 	rf->rclose = rhdr.mode & 64;	/* ORCLOSE */
4273e12c5d1SDavid du Colombier 	rf->fd = erealloc(0, sizeof(Fd));
4283e12c5d1SDavid du Colombier 	rf->fd->ref = 1;
4293e12c5d1SDavid du Colombier 	rf->fd->fd = fd;
4303e12c5d1SDavid du Colombier 	rf->fd->dir = dir;
4313e12c5d1SDavid du Colombier 	rf->fd->offset = 0;
4323e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
4333e12c5d1SDavid du Colombier }
4343e12c5d1SDavid du Colombier 
4353e12c5d1SDavid du Colombier void
4363e12c5d1SDavid du Colombier rcreate(void)
4373e12c5d1SDavid du Colombier {
4383e12c5d1SDavid du Colombier 	Rfile *rf;
4393e12c5d1SDavid du Colombier 	File *f, *of;
4403e12c5d1SDavid du Colombier 	char *path, *err;
4413e12c5d1SDavid du Colombier 	int fd;
4423e12c5d1SDavid du Colombier 	int m;
4433e12c5d1SDavid du Colombier 	char name[NAMELEN];
4443e12c5d1SDavid du Colombier 
4453e12c5d1SDavid du Colombier 	rf = rfilefid();
4463e12c5d1SDavid du Colombier 	if(rf->fd)
4473e12c5d1SDavid du Colombier 		errjmp(Eopen);
4483e12c5d1SDavid du Colombier 	perm(rf, 2, 0);
4493e12c5d1SDavid du Colombier 	path = bldpath(rf->file->path, rhdr.name, name);
450bd389b36SDavid du Colombier 	m = omode(rhdr.mode&3);
4513e12c5d1SDavid du Colombier 	errno = 0;
4523e12c5d1SDavid du Colombier 	if(rhdr.perm & CHDIR){
4533e12c5d1SDavid du Colombier 		if(m){
4543e12c5d1SDavid du Colombier 			free(path);
4553e12c5d1SDavid du Colombier 			errjmp(Eperm);
4563e12c5d1SDavid du Colombier 		}
4573e12c5d1SDavid du Colombier 		fd = mkdir(path, 0777);
4583e12c5d1SDavid du Colombier 		if(fd < 0){
4593e12c5d1SDavid du Colombier 			free(path);
4603e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4613e12c5d1SDavid du Colombier 		}
4623e12c5d1SDavid du Colombier 		fd = open(path, 0);
4633e12c5d1SDavid du Colombier 		free(path);
4643e12c5d1SDavid du Colombier 		if(fd >= 0){
4653e12c5d1SDavid du Colombier 			fchmod(fd, rhdr.perm&0777);
4663e12c5d1SDavid du Colombier 			fchown(fd, rf->uid, rf->gid);
4673e12c5d1SDavid du Colombier 		}
4683e12c5d1SDavid du Colombier 	}else{
4693e12c5d1SDavid du Colombier 		fd = creat(path, 0666);
4703e12c5d1SDavid du Colombier 		if(fd >= 0){
4713e12c5d1SDavid du Colombier 			if(m != 1){
4723e12c5d1SDavid du Colombier 				close(fd);
4733e12c5d1SDavid du Colombier 				fd = open(path, m);
4743e12c5d1SDavid du Colombier 			}
4753e12c5d1SDavid du Colombier 			fchmod(fd, rhdr.perm&0777);
4763e12c5d1SDavid du Colombier 			fchown(fd, rf->uid, rf->gid);
4773e12c5d1SDavid du Colombier 		}
4783e12c5d1SDavid du Colombier 		free(path);
4793e12c5d1SDavid du Colombier 		if(fd < 0)
4803e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
4813e12c5d1SDavid du Colombier 	}
4823e12c5d1SDavid du Colombier 	f = newfile();
4833e12c5d1SDavid du Colombier 	of = rf->file;
4843e12c5d1SDavid du Colombier 	f->path = estrdup(of->path);
4853e12c5d1SDavid du Colombier 	err = dostat(f, rhdr.name);
4863e12c5d1SDavid du Colombier 	if(err){
4873e12c5d1SDavid du Colombier 		free(f->path);
4883e12c5d1SDavid du Colombier 		free(f->name);
4893e12c5d1SDavid du Colombier 		free(f);
4903e12c5d1SDavid du Colombier 		errjmp(err);
4913e12c5d1SDavid du Colombier 	}
4923e12c5d1SDavid du Colombier 	if(!devallowed && (f->stbuf.st_mode & S_IFCHR)){
4933e12c5d1SDavid du Colombier 		free(f->path);
4943e12c5d1SDavid du Colombier 		free(f->name);
4953e12c5d1SDavid du Colombier 		free(f);
4963e12c5d1SDavid du Colombier 		errjmp(Especial);
4973e12c5d1SDavid du Colombier 	}
4983e12c5d1SDavid du Colombier 	if(--of->ref == 0){
4993e12c5d1SDavid du Colombier 		free(of->path);
5003e12c5d1SDavid du Colombier 		free(of->name);
5013e12c5d1SDavid du Colombier 		free(of);
5023e12c5d1SDavid du Colombier 	}
5033e12c5d1SDavid du Colombier 	rf->file = f;
504*219b2ee8SDavid du Colombier 	rf->rclose = rhdr.mode & 64;	/* ORCLOSE */
5053e12c5d1SDavid du Colombier 	rf->fd = erealloc(0, sizeof(Fd));
5063e12c5d1SDavid du Colombier 	rf->fd->ref = 1;
5073e12c5d1SDavid du Colombier 	rf->fd->fd = fd;
5083e12c5d1SDavid du Colombier 	rf->fd->dir = 0;
5093e12c5d1SDavid du Colombier 	rf->fd->offset = 0;
5103e12c5d1SDavid du Colombier 	thdr.qid = f->qid;
5113e12c5d1SDavid du Colombier }
5123e12c5d1SDavid du Colombier 
5133e12c5d1SDavid du Colombier void
5143e12c5d1SDavid du Colombier rread(void)
5153e12c5d1SDavid du Colombier {
5163e12c5d1SDavid du Colombier 	Rfile *rf;
5173e12c5d1SDavid du Colombier 	File *f;
5183e12c5d1SDavid du Colombier 	long n;
5193e12c5d1SDavid du Colombier 	DTYPE *de;
5203e12c5d1SDavid du Colombier 	Dir d;
5213e12c5d1SDavid du Colombier 	struct stat stbuf;
5223e12c5d1SDavid du Colombier 	char *path;
5233e12c5d1SDavid du Colombier 
5243e12c5d1SDavid du Colombier 	rf = rfilefid();
5253e12c5d1SDavid du Colombier 	if(rf->fd == 0)
5263e12c5d1SDavid du Colombier 		errjmp(Enotopen);
5273e12c5d1SDavid du Colombier 	if(rhdr.count > sizeof rdata)
5283e12c5d1SDavid du Colombier 		errjmp(Etoolarge);
5293e12c5d1SDavid du Colombier 	f = rf->file;
5303e12c5d1SDavid du Colombier 	if(rf->fd->dir){
5313e12c5d1SDavid du Colombier 		errno = 0;
532*219b2ee8SDavid du Colombier 		rhdr.count = (rhdr.count/DIRLEN)*DIRLEN;
5333e12c5d1SDavid du Colombier 		if(rf->fd->offset != rhdr.offset){
534*219b2ee8SDavid du Colombier 			rf->fd->offset = rhdr.offset;  /* sync offset */
5353e12c5d1SDavid du Colombier 			seekdir(rf->fd->dir, 0);
5363e12c5d1SDavid du Colombier 			for(n=0; n<rhdr.offset; ){
5373e12c5d1SDavid du Colombier 				de = readdir(rf->fd->dir);
5383e12c5d1SDavid du Colombier 				if(de == 0)
5393e12c5d1SDavid du Colombier 					break;
5403e12c5d1SDavid du Colombier 				if(de->d_ino==0 || de->d_name[0]==0)
5413e12c5d1SDavid du Colombier 					continue;
5423e12c5d1SDavid du Colombier 				if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0)
5433e12c5d1SDavid du Colombier 					continue;
5443e12c5d1SDavid du Colombier 				n += DIRLEN;
5453e12c5d1SDavid du Colombier 			}
5463e12c5d1SDavid du Colombier 		}
5473e12c5d1SDavid du Colombier 		for(n=0; n<rhdr.count; ){
5483e12c5d1SDavid du Colombier 			de = readdir(rf->fd->dir);
5493e12c5d1SDavid du Colombier 			if(de == 0)
5503e12c5d1SDavid du Colombier 				break;
5513e12c5d1SDavid du Colombier 			if(de->d_ino==0 || de->d_name[0]==0)
5523e12c5d1SDavid du Colombier 				continue;
5533e12c5d1SDavid du Colombier 			if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0)
5543e12c5d1SDavid du Colombier 				continue;
5553e12c5d1SDavid du Colombier 			strncpy(d.name, de->d_name, NAMELEN-1);
5563e12c5d1SDavid du Colombier 			d.name[NAMELEN-1] = 0;
5573e12c5d1SDavid du Colombier 			path = erealloc(0, strlen(f->path)+1+strlen(de->d_name)+1);
5583e12c5d1SDavid du Colombier 			sprintf(path, "%s/%s", f->path, de->d_name);
5593e12c5d1SDavid du Colombier 			memset(&stbuf, 0, sizeof stbuf);
5603e12c5d1SDavid du Colombier 			if(stat(path, &stbuf) < 0){
5613e12c5d1SDavid du Colombier 				fprintf(stderr, "dir: bad path %s\n", path);
5623e12c5d1SDavid du Colombier 				/* but continue... probably a bad symlink */
5633e12c5d1SDavid du Colombier 			}
5643e12c5d1SDavid du Colombier 			free(path);
5653e12c5d1SDavid du Colombier 			strncpy(d.uid, id2name(uid, stbuf.st_uid), NAMELEN);
5663e12c5d1SDavid du Colombier 			strncpy(d.gid, id2name(gid, stbuf.st_gid), NAMELEN);
5673e12c5d1SDavid du Colombier 			d.qid.path = qid(&stbuf);
568*219b2ee8SDavid du Colombier 			d.qid.vers = vers(&stbuf);
5693e12c5d1SDavid du Colombier 			d.mode = (d.qid.path&CHDIR)|(stbuf.st_mode&0777);
5703e12c5d1SDavid du Colombier 			d.atime = stbuf.st_atime;
5713e12c5d1SDavid du Colombier 			d.mtime = stbuf.st_mtime;
5723e12c5d1SDavid du Colombier 			d.len.l.hlength = 0;
5733e12c5d1SDavid du Colombier 			d.len.l.length = stbuf.st_size;
5743e12c5d1SDavid du Colombier 			convD2M(&d, rdata+n);
5753e12c5d1SDavid du Colombier 			n += DIRLEN;
5763e12c5d1SDavid du Colombier 		}
5773e12c5d1SDavid du Colombier 	}else{
5783e12c5d1SDavid du Colombier 		errno = 0;
579*219b2ee8SDavid du Colombier 		if(rf->fd->offset != rhdr.offset){
580*219b2ee8SDavid du Colombier 			rf->fd->offset = rhdr.offset;
5813e12c5d1SDavid du Colombier 			if(lseek(rf->fd->fd, rhdr.offset, 0) < 0)
5823e12c5d1SDavid du Colombier 				errjmp(sys_errlist[errno]);
583*219b2ee8SDavid du Colombier 		}
5843e12c5d1SDavid du Colombier 		n = read(rf->fd->fd, rdata, rhdr.count);
5853e12c5d1SDavid du Colombier 		if(n < 0)
5863e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
5873e12c5d1SDavid du Colombier 	}
5883e12c5d1SDavid du Colombier 	rf->fd->offset += n;
5893e12c5d1SDavid du Colombier 	thdr.count = n;
5903e12c5d1SDavid du Colombier 	thdr.data = rdata;
5913e12c5d1SDavid du Colombier }
5923e12c5d1SDavid du Colombier 
5933e12c5d1SDavid du Colombier void
5943e12c5d1SDavid du Colombier rwrite(void)
5953e12c5d1SDavid du Colombier {
5963e12c5d1SDavid du Colombier 	Rfile *rf;
5973e12c5d1SDavid du Colombier 	int n;
5983e12c5d1SDavid du Colombier 
5993e12c5d1SDavid du Colombier 	rf = rfilefid();
6003e12c5d1SDavid du Colombier 	if(rf->fd == 0)
6013e12c5d1SDavid du Colombier 		errjmp(Enotopen);
6023e12c5d1SDavid du Colombier 	if(rhdr.count > sizeof rdata)
6033e12c5d1SDavid du Colombier 		errjmp(Etoolarge);
6043e12c5d1SDavid du Colombier 	errno = 0;
605*219b2ee8SDavid du Colombier 	if(rf->fd->offset != rhdr.offset){
606*219b2ee8SDavid du Colombier 		rf->fd->offset = rhdr.offset;
6073e12c5d1SDavid du Colombier 		if(lseek(rf->fd->fd, rhdr.offset, 0) < 0)
6083e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
609*219b2ee8SDavid du Colombier 	}
6103e12c5d1SDavid du Colombier 	n = write(rf->fd->fd, rhdr.data, rhdr.count);
6113e12c5d1SDavid du Colombier 	if(n < 0)
6123e12c5d1SDavid du Colombier 		errjmp(sys_errlist[errno]);
6133e12c5d1SDavid du Colombier 	rf->fd->offset += n;
6143e12c5d1SDavid du Colombier 	thdr.count = n;
6153e12c5d1SDavid du Colombier }
6163e12c5d1SDavid du Colombier 
6173e12c5d1SDavid du Colombier void
6183e12c5d1SDavid du Colombier rstat(void)
6193e12c5d1SDavid du Colombier {
6203e12c5d1SDavid du Colombier 	Rfile *rf;
6213e12c5d1SDavid du Colombier 	File *f;
6223e12c5d1SDavid du Colombier 	Dir d;
6233e12c5d1SDavid du Colombier 
6243e12c5d1SDavid du Colombier 	rf = rfilefid();
6253e12c5d1SDavid du Colombier 	f = rf->file;
6263e12c5d1SDavid du Colombier 	errjmp(dostat(f, 0));
6273e12c5d1SDavid du Colombier 	strncpy(d.name, f->name, NAMELEN);
6283e12c5d1SDavid du Colombier 	strncpy(d.uid, id2name(uid, f->stbuf.st_uid), NAMELEN);
6293e12c5d1SDavid du Colombier 	strncpy(d.gid, id2name(gid, f->stbuf.st_gid), NAMELEN);
6303e12c5d1SDavid du Colombier 	d.qid = f->qid;
6313e12c5d1SDavid du Colombier 	d.mode = (f->qid.path&CHDIR)|(f->stbuf.st_mode&0777);
6323e12c5d1SDavid du Colombier 	d.atime = f->stbuf.st_atime;
6333e12c5d1SDavid du Colombier 	d.mtime = f->stbuf.st_mtime;
6343e12c5d1SDavid du Colombier 	d.len.l.hlength = 0;
6353e12c5d1SDavid du Colombier 	d.len.l.length = f->stbuf.st_size;
6363e12c5d1SDavid du Colombier 	convD2M(&d, thdr.stat);
6373e12c5d1SDavid du Colombier }
6383e12c5d1SDavid du Colombier 
6393e12c5d1SDavid du Colombier void
6403e12c5d1SDavid du Colombier rwstat(void)
6413e12c5d1SDavid du Colombier {
6423e12c5d1SDavid du Colombier 	Rfile *rf;
6433e12c5d1SDavid du Colombier 	File *f;
6443e12c5d1SDavid du Colombier 	Dir d;
6453e12c5d1SDavid du Colombier 	Pass *p;
6463e12c5d1SDavid du Colombier 	char *path, *dir, name[NAMELEN];
6473e12c5d1SDavid du Colombier 
6483e12c5d1SDavid du Colombier 	rf = rfilefid();
6493e12c5d1SDavid du Colombier 	f = rf->file;
6503e12c5d1SDavid du Colombier 	errjmp(dostat(f, 0));
6513e12c5d1SDavid du Colombier 	convM2D(rhdr.stat, &d);
6523e12c5d1SDavid du Colombier 	errno = 0;
6533e12c5d1SDavid du Colombier 	if(rf->uid != f->stbuf.st_uid)
6543e12c5d1SDavid du Colombier 		errjmp(Eowner);
6553e12c5d1SDavid du Colombier 	if(strcmp(d.name, f->name) != 0){
6563e12c5d1SDavid du Colombier 		parentwrperm(rf);
6573e12c5d1SDavid du Colombier 		dir = bldpath(f->path, "..", name);
6583e12c5d1SDavid du Colombier 		path = erealloc(0, strlen(dir)+1+strlen(d.name)+1);
6593e12c5d1SDavid du Colombier 		sprintf(path, "%s/%s", dir, d.name);
6603e12c5d1SDavid du Colombier 		if(link(f->path, path) < 0){
6613e12c5d1SDavid du Colombier 			free(path);
6623e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
6633e12c5d1SDavid du Colombier 		}
6643e12c5d1SDavid du Colombier 		if(unlink(f->path) < 0){
6653e12c5d1SDavid du Colombier 			free(path);
6663e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
6673e12c5d1SDavid du Colombier 		}
6683e12c5d1SDavid du Colombier 		free(f->path);
6693e12c5d1SDavid du Colombier 		free(f->name);
6703e12c5d1SDavid du Colombier 		f->path = path;
6713e12c5d1SDavid du Colombier 		f->name = estrdup(d.name);
6723e12c5d1SDavid du Colombier 	}
6733e12c5d1SDavid du Colombier 	if((d.mode&0777) != (f->stbuf.st_mode&0777)){
6743e12c5d1SDavid du Colombier 		if(chmod(f->path, d.mode&0777) < 0)
6753e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
6763e12c5d1SDavid du Colombier 		f->stbuf.st_mode &= ~0777;
6773e12c5d1SDavid du Colombier 		f->stbuf.st_mode |= d.mode&0777;
6783e12c5d1SDavid du Colombier 	}
6793e12c5d1SDavid du Colombier 	p = name2pass(gid, d.gid);
6803e12c5d1SDavid du Colombier 	if(p == 0)
6813e12c5d1SDavid du Colombier 		errjmp(Eunknown);
6823e12c5d1SDavid du Colombier 	if(p->id != f->stbuf.st_gid){
6833e12c5d1SDavid du Colombier 		if(chown(f->path, f->stbuf.st_uid, p->id) < 0)
6843e12c5d1SDavid du Colombier 			errjmp(sys_errlist[errno]);
6853e12c5d1SDavid du Colombier 		f->stbuf.st_gid = p->id;
6863e12c5d1SDavid du Colombier 	}
6873e12c5d1SDavid du Colombier }
6883e12c5d1SDavid du Colombier 
6893e12c5d1SDavid du Colombier void
6903e12c5d1SDavid du Colombier rclunk(int rm)
6913e12c5d1SDavid du Colombier {
6923e12c5d1SDavid du Colombier 	int ret;
6933e12c5d1SDavid du Colombier 	char *err;
6943e12c5d1SDavid du Colombier 	Rfile *rf;
6953e12c5d1SDavid du Colombier 	File *f;
6963e12c5d1SDavid du Colombier 	Fd *fd;
6973e12c5d1SDavid du Colombier 
6983e12c5d1SDavid du Colombier 	err = 0;
6993e12c5d1SDavid du Colombier 	rf = rfilefid();
7003e12c5d1SDavid du Colombier 	f = rf->file;
7013e12c5d1SDavid du Colombier 	if(rm){
7023e12c5d1SDavid du Colombier 		parentwrperm(rf);
7033e12c5d1SDavid du Colombier 		if(f->qid.path & CHDIR)
7043e12c5d1SDavid du Colombier 			ret = rmdir(f->path);
7053e12c5d1SDavid du Colombier 		else
7063e12c5d1SDavid du Colombier 			ret = unlink(f->path);
7073e12c5d1SDavid du Colombier 		if(ret)
7083e12c5d1SDavid du Colombier 			err = sys_errlist[errno];
709*219b2ee8SDavid du Colombier 	}else if(rf->rclose){	/* ignore errors */
710*219b2ee8SDavid du Colombier 		if(f->qid.path & CHDIR)
711*219b2ee8SDavid du Colombier 			rmdir(f->path);
712*219b2ee8SDavid du Colombier 		else
713*219b2ee8SDavid du Colombier 			unlink(f->path);
7143e12c5d1SDavid du Colombier 	}
715*219b2ee8SDavid du Colombier 
7163e12c5d1SDavid du Colombier 	rf->busy = 0;
7173e12c5d1SDavid du Colombier 	if(--f->ref == 0){
7183e12c5d1SDavid du Colombier 		free(f->path);
7193e12c5d1SDavid du Colombier 		free(f->name);
7203e12c5d1SDavid du Colombier 		free(f);
7213e12c5d1SDavid du Colombier 	}
7223e12c5d1SDavid du Colombier 	fd = rf->fd;
7233e12c5d1SDavid du Colombier 	if(fd){
7243e12c5d1SDavid du Colombier 		if(fd->ref <= 0)
7253e12c5d1SDavid du Colombier 			error("clunk fd count");
7263e12c5d1SDavid du Colombier 		if(--fd->ref == 0){
7273e12c5d1SDavid du Colombier 			if(fd->fd)
7283e12c5d1SDavid du Colombier 				close(fd->fd);
7293e12c5d1SDavid du Colombier 			if(fd->dir)
7303e12c5d1SDavid du Colombier 				closedir(fd->dir);
7313e12c5d1SDavid du Colombier 			free(fd);
7323e12c5d1SDavid du Colombier 		}
7333e12c5d1SDavid du Colombier 		rf->fd = 0;
7343e12c5d1SDavid du Colombier 	}
7353e12c5d1SDavid du Colombier 	if(err)
7363e12c5d1SDavid du Colombier 		errjmp(err);
7373e12c5d1SDavid du Colombier }
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier char*
7403e12c5d1SDavid du Colombier bldpath(char *a, char *elem, char *name)
7413e12c5d1SDavid du Colombier {
7423e12c5d1SDavid du Colombier 	char *path, *p;
7433e12c5d1SDavid du Colombier 
7443e12c5d1SDavid du Colombier 	if(strcmp(elem, "..") == 0){
7453e12c5d1SDavid du Colombier 		if(strcmp(a, "/") == 0){
7463e12c5d1SDavid du Colombier 			path = estrdup(a);
7473e12c5d1SDavid du Colombier 			strcpy(name, a);
7483e12c5d1SDavid du Colombier 		}else{
7493e12c5d1SDavid du Colombier 			p = strrchr(a, '/');
7503e12c5d1SDavid du Colombier 			if(p == 0){
7513e12c5d1SDavid du Colombier 				fprintf(stderr, "path: '%s'\n", path);
7523e12c5d1SDavid du Colombier 				error("malformed path 1");
7533e12c5d1SDavid du Colombier 			}
7543e12c5d1SDavid du Colombier 			if(p == a)	/* reduced to "/" */
7553e12c5d1SDavid du Colombier 				p++;
7563e12c5d1SDavid du Colombier 			path = erealloc(0, (p-a)+1);
7573e12c5d1SDavid du Colombier 			memmove(path, a, (p-a));
7583e12c5d1SDavid du Colombier 			path[(p-a)] = 0;
7593e12c5d1SDavid du Colombier 			if(strcmp(path, "/") == 0)
7603e12c5d1SDavid du Colombier 				p = path;
7613e12c5d1SDavid du Colombier 			else{
7623e12c5d1SDavid du Colombier 				p = strrchr(path, '/');
7633e12c5d1SDavid du Colombier 				if(p == 0){
7643e12c5d1SDavid du Colombier 					fprintf(stderr, "path: '%s'\n", path);
7653e12c5d1SDavid du Colombier 					error("malformed path 2");
7663e12c5d1SDavid du Colombier 				}
7673e12c5d1SDavid du Colombier 				p++;
7683e12c5d1SDavid du Colombier 			}
7693e12c5d1SDavid du Colombier 			strcpy(name, p);
7703e12c5d1SDavid du Colombier 		}
7713e12c5d1SDavid du Colombier 	}else{
7723e12c5d1SDavid du Colombier 		if(strcmp(a, "/") == 0)
7733e12c5d1SDavid du Colombier 			a = "";
7743e12c5d1SDavid du Colombier 		path = erealloc(0, strlen(a)+1+strlen(elem)+1);
7753e12c5d1SDavid du Colombier 		sprintf(path, "%s/%s", a, elem);
7763e12c5d1SDavid du Colombier 		strcpy(name, elem);
7773e12c5d1SDavid du Colombier 	}
7783e12c5d1SDavid du Colombier 	if(strlen(name) >= NAMELEN)
7793e12c5d1SDavid du Colombier 		error("bldpath: name too long");
7803e12c5d1SDavid du Colombier 	return path;
7813e12c5d1SDavid du Colombier }
7823e12c5d1SDavid du Colombier 
7833e12c5d1SDavid du Colombier char*
7843e12c5d1SDavid du Colombier dostat(File *f, char *elem)
7853e12c5d1SDavid du Colombier {
7863e12c5d1SDavid du Colombier 	char *path;
7873e12c5d1SDavid du Colombier 	struct stat stbuf;
7883e12c5d1SDavid du Colombier 	char name[NAMELEN];
7893e12c5d1SDavid du Colombier 
7903e12c5d1SDavid du Colombier 	if(elem)
7913e12c5d1SDavid du Colombier 		path = bldpath(f->path, elem, name);
7923e12c5d1SDavid du Colombier 	else
7933e12c5d1SDavid du Colombier 		path = f->path;
7943e12c5d1SDavid du Colombier 	errno = 0;
7953e12c5d1SDavid du Colombier 	if(stat(path, &stbuf) < 0)
7963e12c5d1SDavid du Colombier 		return sys_errlist[errno];
7973e12c5d1SDavid du Colombier 	if(elem){
7983e12c5d1SDavid du Colombier 		free(f->path);
7993e12c5d1SDavid du Colombier 		f->path = path;
8003e12c5d1SDavid du Colombier 		f->name = estrdup(name);
8013e12c5d1SDavid du Colombier 	}
8023e12c5d1SDavid du Colombier 	f->qid.path = qid(&stbuf);
803*219b2ee8SDavid du Colombier 	f->qid.vers = vers(&stbuf);
8043e12c5d1SDavid du Colombier 	f->stbuf = stbuf;
8053e12c5d1SDavid du Colombier 	return 0;
8063e12c5d1SDavid du Colombier }
8073e12c5d1SDavid du Colombier 
8083e12c5d1SDavid du Colombier int
8093e12c5d1SDavid du Colombier omode(int m)
8103e12c5d1SDavid du Colombier {
8113e12c5d1SDavid du Colombier 	switch(m){
8123e12c5d1SDavid du Colombier 	case 0:		/* OREAD */
8133e12c5d1SDavid du Colombier 	case 3:		/* OEXEC */
8143e12c5d1SDavid du Colombier 		return 0;
8153e12c5d1SDavid du Colombier 	case 1:		/* OWRITE */
8163e12c5d1SDavid du Colombier 		return 1;
8173e12c5d1SDavid du Colombier 	case 2:		/* ORDWR */
8183e12c5d1SDavid du Colombier 		return 2;
8193e12c5d1SDavid du Colombier 	}
8203e12c5d1SDavid du Colombier 	errjmp(Emode);
8213e12c5d1SDavid du Colombier 	return 0;
8223e12c5d1SDavid du Colombier }
8233e12c5d1SDavid du Colombier 
8243e12c5d1SDavid du Colombier void
8253e12c5d1SDavid du Colombier sendmsg(char *err)
8263e12c5d1SDavid du Colombier {
8273e12c5d1SDavid du Colombier 	int n;
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier 	if(err){
8303e12c5d1SDavid du Colombier 		thdr.type = Rerror;
8313e12c5d1SDavid du Colombier 		strncpy(thdr.ename, err, ERRLEN);
8323e12c5d1SDavid du Colombier 	}
8333e12c5d1SDavid du Colombier 	DBG(fprintf(stderr, "<< %s\n", mfmt(&thdr)));
8343e12c5d1SDavid du Colombier 	n = convS2M(&thdr, tdata);
8353e12c5d1SDavid du Colombier 	if(n == 0)
8363e12c5d1SDavid du Colombier 		error("bad sendmsg format");
8373e12c5d1SDavid du Colombier 	if(write(1, tdata, n) != n)
8383e12c5d1SDavid du Colombier 		error("write error");
8393e12c5d1SDavid du Colombier }
8403e12c5d1SDavid du Colombier 
8413e12c5d1SDavid du Colombier 
8423e12c5d1SDavid du Colombier int
8433e12c5d1SDavid du Colombier okfid(int fid)
8443e12c5d1SDavid du Colombier {
8453e12c5d1SDavid du Colombier 	enum{ Delta=10 };
8463e12c5d1SDavid du Colombier 
8473e12c5d1SDavid du Colombier 	if(fid < 0){
8483e12c5d1SDavid du Colombier 		fprintf(stderr, "u9fs: negative fid %d\n", fid);
8493e12c5d1SDavid du Colombier 		return 0;
8503e12c5d1SDavid du Colombier 	}
8513e12c5d1SDavid du Colombier 	if(fid >= nrfilealloc){
8523e12c5d1SDavid du Colombier 		fid += Delta;
8533e12c5d1SDavid du Colombier 		rfile = erealloc(rfile, fid*sizeof(Rfile));
8543e12c5d1SDavid du Colombier 		memset(rfile+nrfilealloc, 0, (fid-nrfilealloc)*sizeof(Rfile));
8553e12c5d1SDavid du Colombier 		nrfilealloc = fid;
8563e12c5d1SDavid du Colombier 	}
8573e12c5d1SDavid du Colombier 	return 1;
8583e12c5d1SDavid du Colombier }
8593e12c5d1SDavid du Colombier 
8603e12c5d1SDavid du Colombier Rfile*
8613e12c5d1SDavid du Colombier rfilefid(void)
8623e12c5d1SDavid du Colombier {
8633e12c5d1SDavid du Colombier 	Rfile *rf;
8643e12c5d1SDavid du Colombier 
8653e12c5d1SDavid du Colombier 	if(!okfid(rhdr.fid))
8663e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
8673e12c5d1SDavid du Colombier 	rf = &rfile[rhdr.fid];
8683e12c5d1SDavid du Colombier 	if(rf->busy == 0)
8693e12c5d1SDavid du Colombier 		errjmp(Ebadfid);
8703e12c5d1SDavid du Colombier 	if(rf->file->ref <= 0)
8713e12c5d1SDavid du Colombier 		error("ref count");
8723e12c5d1SDavid du Colombier 	return rf;
8733e12c5d1SDavid du Colombier }
8743e12c5d1SDavid du Colombier 
8753e12c5d1SDavid du Colombier void
8763e12c5d1SDavid du Colombier perm(Rfile *rf, int mask, struct stat *st)
8773e12c5d1SDavid du Colombier {
8783e12c5d1SDavid du Colombier 	if(st == 0)
8793e12c5d1SDavid du Colombier 		st = &rf->file->stbuf;
8803e12c5d1SDavid du Colombier 	/* plan 9 access semantics; simpler and more sensible */
8813e12c5d1SDavid du Colombier 	if(rf->uid == st->st_uid)
8823e12c5d1SDavid du Colombier 		if((st->st_mode>>6) & mask)
8833e12c5d1SDavid du Colombier 			return;
8843e12c5d1SDavid du Colombier 	if(rf->gid == st->st_gid)
8853e12c5d1SDavid du Colombier 		if((st->st_mode>>3) & mask)
8863e12c5d1SDavid du Colombier 			return;
8873e12c5d1SDavid du Colombier 	if((st->st_mode>>0) & mask)
8883e12c5d1SDavid du Colombier 		return;
8893e12c5d1SDavid du Colombier 	errjmp(Eperm);
8903e12c5d1SDavid du Colombier }
8913e12c5d1SDavid du Colombier 
8923e12c5d1SDavid du Colombier void
8933e12c5d1SDavid du Colombier parentwrperm(Rfile *rf)
8943e12c5d1SDavid du Colombier {
8953e12c5d1SDavid du Colombier 	Rfile trf;
8963e12c5d1SDavid du Colombier 	struct stat st;
8973e12c5d1SDavid du Colombier 	char *dirp, dir[512];
8983e12c5d1SDavid du Colombier 
8993e12c5d1SDavid du Colombier 	dirp = bldpath(rf->file->path, "..", dir);
9003e12c5d1SDavid du Colombier 	if(strlen(dirp) < sizeof dir){	/* ugly: avoid leaving dirp allocated */
9013e12c5d1SDavid du Colombier 		strcpy(dir, dirp);
9023e12c5d1SDavid du Colombier 		free(dirp);
9033e12c5d1SDavid du Colombier 		dirp = dir;
9043e12c5d1SDavid du Colombier 	}
9053e12c5d1SDavid du Colombier 	if(stat(dirp, &st) < 0)
9063e12c5d1SDavid du Colombier 		errjmp(Eperm);
9073e12c5d1SDavid du Colombier 	trf.uid = rf->uid;
9083e12c5d1SDavid du Colombier 	trf.gid = rf->gid;
9093e12c5d1SDavid du Colombier 	perm(&trf, 2, &st);
9103e12c5d1SDavid du Colombier }
9113e12c5d1SDavid du Colombier 
9123e12c5d1SDavid du Colombier File*
9133e12c5d1SDavid du Colombier newfile(void)
9143e12c5d1SDavid du Colombier {
9153e12c5d1SDavid du Colombier 	File *f;
9163e12c5d1SDavid du Colombier 
9173e12c5d1SDavid du Colombier 	f = erealloc(0, sizeof(File));
9183e12c5d1SDavid du Colombier 	memset(f, 0, sizeof(File));
9193e12c5d1SDavid du Colombier 	f->ref = 1;
9203e12c5d1SDavid du Colombier 	return f;
9213e12c5d1SDavid du Colombier }
9223e12c5d1SDavid du Colombier 
9233e12c5d1SDavid du Colombier /*
9243e12c5d1SDavid du Colombier  * qids: directory bit, seven bits of device, 24 bits of inode
9253e12c5d1SDavid du Colombier  */
9263e12c5d1SDavid du Colombier Ulong
927*219b2ee8SDavid du Colombier vers(struct stat *st)
928*219b2ee8SDavid du Colombier {
929*219b2ee8SDavid du Colombier 	return st->st_mtime;
930*219b2ee8SDavid du Colombier }
931*219b2ee8SDavid du Colombier 
932*219b2ee8SDavid du Colombier Ulong
9333e12c5d1SDavid du Colombier qid(struct stat *st)
9343e12c5d1SDavid du Colombier {
9353e12c5d1SDavid du Colombier 	static int nqdev;
9363e12c5d1SDavid du Colombier 	static Uchar *qdev;
9373e12c5d1SDavid du Colombier 	Ulong q;
9383e12c5d1SDavid du Colombier 	int dev;
9393e12c5d1SDavid du Colombier 
940*219b2ee8SDavid du Colombier 	if(qdev == 0){
9413e12c5d1SDavid du Colombier 		qdev = erealloc(0, 65536U);
942*219b2ee8SDavid du Colombier 		memset(qdev, 0, 65536U);
943*219b2ee8SDavid du Colombier 	}
9443e12c5d1SDavid du Colombier 	q = 0;
945*219b2ee8SDavid du Colombier 	if((st->st_mode&S_IFMT) ==  S_IFDIR)
9463e12c5d1SDavid du Colombier 		q = CHDIR;
9473e12c5d1SDavid du Colombier 	dev = st->st_dev & 0xFFFFUL;
9483e12c5d1SDavid du Colombier 	if(qdev[dev] == 0){
9493e12c5d1SDavid du Colombier 		if(++nqdev >= 128)
9503e12c5d1SDavid du Colombier 			error("too many devices");
9513e12c5d1SDavid du Colombier 		qdev[dev] = nqdev;
9523e12c5d1SDavid du Colombier 	}
9533e12c5d1SDavid du Colombier 	q |= qdev[dev]<<24;
9543e12c5d1SDavid du Colombier 	q |= st->st_ino & 0x00FFFFFFUL;
9553e12c5d1SDavid du Colombier 	return q;
9563e12c5d1SDavid du Colombier }
9573e12c5d1SDavid du Colombier 
9583e12c5d1SDavid du Colombier Pass*
9593e12c5d1SDavid du Colombier name2pass(Pass **pw, char *name)
9603e12c5d1SDavid du Colombier {
9613e12c5d1SDavid du Colombier 	int i;
9623e12c5d1SDavid du Colombier 	Pass *p;
9633e12c5d1SDavid du Colombier 
9643e12c5d1SDavid du Colombier 	for(i=0; i<256; i++)
9653e12c5d1SDavid du Colombier 		for(p = pw[i]; p; p = p->next)
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 
9713e12c5d1SDavid du Colombier char*
9723e12c5d1SDavid du Colombier id2name(Pass **pw, int id)
9733e12c5d1SDavid du Colombier {
9743e12c5d1SDavid du Colombier 	int i;
9753e12c5d1SDavid du Colombier 	Pass *p;
9763e12c5d1SDavid du Colombier 	char *s;
9773e12c5d1SDavid du Colombier 	static char buf[8];
9783e12c5d1SDavid du Colombier 
9793e12c5d1SDavid du Colombier 	s = 0;
9803e12c5d1SDavid du Colombier 	/* use last on list == first in file */
9813e12c5d1SDavid du Colombier 	i = (id&0xFF) ^ ((id>>8)&0xFF);
9823e12c5d1SDavid du Colombier 	for(p = pw[i]; p; p = p->next)
9833e12c5d1SDavid du Colombier 		if(p->id == id)
9843e12c5d1SDavid du Colombier 			s = p->name;
9853e12c5d1SDavid du Colombier 	if(s)
9863e12c5d1SDavid du Colombier 		return s;
9873e12c5d1SDavid du Colombier 	sprintf(buf, "%d", id);
9883e12c5d1SDavid du Colombier 	return buf;
9893e12c5d1SDavid du Colombier }
9903e12c5d1SDavid du Colombier 
9913e12c5d1SDavid du Colombier void
9923e12c5d1SDavid du Colombier freepass(Pass **pass)
9933e12c5d1SDavid du Colombier {
9943e12c5d1SDavid du Colombier 	int i;
9953e12c5d1SDavid du Colombier 	Pass *p, *np;
9963e12c5d1SDavid du Colombier 
9973e12c5d1SDavid du Colombier 	for(i=0; i<256; i++){
9983e12c5d1SDavid du Colombier 		for(p = pass[i]; p; p = np){
9993e12c5d1SDavid du Colombier 			np = p->next;
10003e12c5d1SDavid du Colombier 			free(p);
10013e12c5d1SDavid du Colombier 		}
10023e12c5d1SDavid du Colombier 		pass[i] = 0;
10033e12c5d1SDavid du Colombier 	}
10043e12c5d1SDavid du Colombier }
10053e12c5d1SDavid du Colombier 
10063e12c5d1SDavid du Colombier void
10073e12c5d1SDavid du Colombier getpwdf(void)
10083e12c5d1SDavid du Colombier {
10093e12c5d1SDavid du Colombier 	static mtime;
10103e12c5d1SDavid du Colombier 	struct stat stbuf;
10113e12c5d1SDavid du Colombier 	struct passwd *pw;
10123e12c5d1SDavid du Colombier 	int i;
10133e12c5d1SDavid du Colombier 	Pass *p;
10143e12c5d1SDavid du Colombier 
10153e12c5d1SDavid du Colombier 	if(stat("/etc/passwd", &stbuf) < 0)
10163e12c5d1SDavid du Colombier 		error("can't read /etc/passwd");
10173e12c5d1SDavid du Colombier 	if(stbuf.st_mtime <= mtime)
10183e12c5d1SDavid du Colombier 		return;
10193e12c5d1SDavid du Colombier 	freepass(uid);
10203e12c5d1SDavid du Colombier 	while(pw = getpwent()){
10213e12c5d1SDavid du Colombier 		i = pw->pw_uid;
10223e12c5d1SDavid du Colombier 		i = (i&0xFF) ^ ((i>>8)&0xFF);
10233e12c5d1SDavid du Colombier 		p = erealloc(0, sizeof(Pass));
10243e12c5d1SDavid du Colombier 		p->next = uid[i];
10253e12c5d1SDavid du Colombier 		uid[i] = p;
10263e12c5d1SDavid du Colombier 		p->id = pw->pw_uid;
10273e12c5d1SDavid du Colombier 		p->gid = pw->pw_gid;
10283e12c5d1SDavid du Colombier 		p->name = estrdup(pw->pw_name);
10293e12c5d1SDavid du Colombier 	}
10303e12c5d1SDavid du Colombier 	setpwent();
10313e12c5d1SDavid du Colombier 	endpwent();
10323e12c5d1SDavid du Colombier }
10333e12c5d1SDavid du Colombier 
10343e12c5d1SDavid du Colombier void
10353e12c5d1SDavid du Colombier getgrpf(void)
10363e12c5d1SDavid du Colombier {
10373e12c5d1SDavid du Colombier 	static mtime;
10383e12c5d1SDavid du Colombier 	struct stat stbuf;
10393e12c5d1SDavid du Colombier 	struct group *pw;
10403e12c5d1SDavid du Colombier 	int i;
10413e12c5d1SDavid du Colombier 	Pass *p;
10423e12c5d1SDavid du Colombier 
10433e12c5d1SDavid du Colombier 	if(stat("/etc/group", &stbuf) < 0)
10443e12c5d1SDavid du Colombier 		error("can't read /etc/group");
10453e12c5d1SDavid du Colombier 	if(stbuf.st_mtime <= mtime)
10463e12c5d1SDavid du Colombier 		return;
10473e12c5d1SDavid du Colombier 	freepass(gid);
10483e12c5d1SDavid du Colombier 	while(pw = getgrent()){
10493e12c5d1SDavid du Colombier 		i = pw->gr_gid;
10503e12c5d1SDavid du Colombier 		i = (i&0xFF) ^ ((i>>8)&0xFF);
10513e12c5d1SDavid du Colombier 		p = erealloc(0, sizeof(Pass));
10523e12c5d1SDavid du Colombier 		p->next = gid[i];
10533e12c5d1SDavid du Colombier 		gid[i] = p;
10543e12c5d1SDavid du Colombier 		p->id = pw->gr_gid;
10553e12c5d1SDavid du Colombier 		p->gid = 0;
10563e12c5d1SDavid du Colombier 		p->name = estrdup(pw->gr_name);
10573e12c5d1SDavid du Colombier 	}
10583e12c5d1SDavid du Colombier 	setgrent();
10593e12c5d1SDavid du Colombier 	endgrent();
10603e12c5d1SDavid du Colombier }
10613e12c5d1SDavid du Colombier 
10623e12c5d1SDavid du Colombier void
10633e12c5d1SDavid du Colombier error(char *s)
10643e12c5d1SDavid du Colombier {
10653e12c5d1SDavid du Colombier 	fprintf(stderr, "u9fs: %s\n", s);
10663e12c5d1SDavid du Colombier 	perror("unix error");
10673e12c5d1SDavid du Colombier 	exit(1);
10683e12c5d1SDavid du Colombier }
10693e12c5d1SDavid du Colombier 
10703e12c5d1SDavid du Colombier void
10713e12c5d1SDavid du Colombier errjmp(char *s)
10723e12c5d1SDavid du Colombier {
10733e12c5d1SDavid du Colombier 	if(s == 0)
10743e12c5d1SDavid du Colombier 		return;
10753e12c5d1SDavid du Colombier 	sendmsg(s);
10763e12c5d1SDavid du Colombier 	longjmp(loopjmp, 1);
10773e12c5d1SDavid du Colombier }
10783e12c5d1SDavid du Colombier 
10793e12c5d1SDavid du Colombier void*
10803e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
10813e12c5d1SDavid du Colombier {
10823e12c5d1SDavid du Colombier 	if(p == 0)
10833e12c5d1SDavid du Colombier 		p = malloc(n);
10843e12c5d1SDavid du Colombier 	else
10853e12c5d1SDavid du Colombier 		p = realloc(p, n);
10863e12c5d1SDavid du Colombier 	if(p == 0)
10873e12c5d1SDavid du Colombier 		error("realloc fail");
10883e12c5d1SDavid du Colombier 	return p;
10893e12c5d1SDavid du Colombier }
10903e12c5d1SDavid du Colombier 
10913e12c5d1SDavid du Colombier char*
10923e12c5d1SDavid du Colombier estrdup(char *p)
10933e12c5d1SDavid du Colombier {
10943e12c5d1SDavid du Colombier 	p = strdup(p);
10953e12c5d1SDavid du Colombier 	if(p == 0)
10963e12c5d1SDavid du Colombier 		error("strdup fail");
10973e12c5d1SDavid du Colombier 	return p;
10983e12c5d1SDavid du Colombier }
1099*219b2ee8SDavid du Colombier 
1100*219b2ee8SDavid du Colombier #ifdef SOCKETS
1101*219b2ee8SDavid du Colombier void
1102*219b2ee8SDavid du Colombier remotehostname(void)
1103*219b2ee8SDavid du Colombier {
1104*219b2ee8SDavid du Colombier 	struct sockaddr_in sock;
1105*219b2ee8SDavid du Colombier 	struct hostent *hp;
1106*219b2ee8SDavid du Colombier 	int len;
1107*219b2ee8SDavid du Colombier 	int on = 1;
1108*219b2ee8SDavid du Colombier 
1109*219b2ee8SDavid du Colombier 	len = sizeof sock;
1110*219b2ee8SDavid du Colombier 	if(getpeername(0, &sock, &len) < 0)
1111*219b2ee8SDavid du Colombier 		error("getpeername");
1112*219b2ee8SDavid du Colombier 	hp = gethostbyaddr((char *)&sock.sin_addr, sizeof (struct in_addr),
1113*219b2ee8SDavid du Colombier 		sock.sin_family);
1114*219b2ee8SDavid du Colombier 	if(hp == 0)
1115*219b2ee8SDavid du Colombier 		error("gethostbyaddr");
1116*219b2ee8SDavid du Colombier 	strcpy(bsdhost, hp->h_name);
1117*219b2ee8SDavid du Colombier 	fprintf(stderr, "bsdhost %s on %d\n", bsdhost, getpid());
1118*219b2ee8SDavid du Colombier 
1119*219b2ee8SDavid du Colombier 	setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
1120*219b2ee8SDavid du Colombier }
1121*219b2ee8SDavid du Colombier #endif
1122