xref: /plan9/sys/src/cmd/lnfs.c (revision f6269f58ad15527f31cd4480aa79b67e93423b0f)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
59a747e4fSDavid du Colombier #include <fcall.h>
69a747e4fSDavid du Colombier #include <String.h>
79a747e4fSDavid du Colombier #include <libsec.h>
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier enum
109a747e4fSDavid du Colombier {
119a747e4fSDavid du Colombier 	OPERM	= 0x3,		/* mask of all permission types in open mode */
129a747e4fSDavid du Colombier 	Maxsize	= 512*1024*1024,
139a747e4fSDavid du Colombier 	Maxfdata	= 8192,
149a747e4fSDavid du Colombier 	NAMELEN = 28,
159a747e4fSDavid du Colombier };
169a747e4fSDavid du Colombier 
179a747e4fSDavid du Colombier typedef struct Fid Fid;
189a747e4fSDavid du Colombier struct Fid
199a747e4fSDavid du Colombier {
209a747e4fSDavid du Colombier 	short	busy;
219a747e4fSDavid du Colombier 	int	fid;
229a747e4fSDavid du Colombier 	Fid	*next;
239a747e4fSDavid du Colombier 	char	*user;
249a747e4fSDavid du Colombier 	String	*path;		/* complete path */
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier 	int	fd;		/* set on open or create */
279a747e4fSDavid du Colombier 	Qid	qid;		/* set on open or create */
289a747e4fSDavid du Colombier 	int	attach;		/* this is an attach fd */
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier 	ulong	diroff;		/* directory offset */
319a747e4fSDavid du Colombier 	Dir	*dir;		/* directory entries */
329a747e4fSDavid du Colombier 	int	ndir;		/* number of directory entries */
339a747e4fSDavid du Colombier };
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier Fid	*fids;
369a747e4fSDavid du Colombier int	mfd[2];
379a747e4fSDavid du Colombier char	*user;
389a747e4fSDavid du Colombier uchar	mdata[IOHDRSZ+Maxfdata];
399a747e4fSDavid du Colombier uchar	rdata[Maxfdata];	/* buffer for data in reply */
409a747e4fSDavid du Colombier uchar	statbuf[STATMAX];
419a747e4fSDavid du Colombier Fcall	thdr;
429a747e4fSDavid du Colombier Fcall	rhdr;
439a747e4fSDavid du Colombier int	messagesize = sizeof mdata;
449a747e4fSDavid du Colombier int	readonly;
459a747e4fSDavid du Colombier char	*srvname;
469a747e4fSDavid du Colombier int	debug;
479a747e4fSDavid du Colombier 
489a747e4fSDavid du Colombier Fid *	newfid(int);
499a747e4fSDavid du Colombier void	io(void);
509a747e4fSDavid du Colombier void	*erealloc(void*, ulong);
519a747e4fSDavid du Colombier void	*emalloc(ulong);
529a747e4fSDavid du Colombier char	*estrdup(char*);
539a747e4fSDavid du Colombier void	usage(void);
549a747e4fSDavid du Colombier void	fidqid(Fid*, Qid*);
559a747e4fSDavid du Colombier char*	short2long(char*);
569a747e4fSDavid du Colombier char*	long2short(char*, int);
579a747e4fSDavid du Colombier void	readnames(void);
589a747e4fSDavid du Colombier void	post(char*, int);
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
619a747e4fSDavid du Colombier 	*rattach(Fid*), *rwalk(Fid*),
629a747e4fSDavid du Colombier 	*ropen(Fid*), *rcreate(Fid*),
639a747e4fSDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
649a747e4fSDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier char 	*(*fcalls[])(Fid*) = {
679a747e4fSDavid du Colombier 	[Tversion]	rversion,
689a747e4fSDavid du Colombier 	[Tflush]	rflush,
699a747e4fSDavid du Colombier 	[Tauth]	rauth,
709a747e4fSDavid du Colombier 	[Tattach]	rattach,
719a747e4fSDavid du Colombier 	[Twalk]		rwalk,
729a747e4fSDavid du Colombier 	[Topen]		ropen,
739a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
749a747e4fSDavid du Colombier 	[Tread]		rread,
759a747e4fSDavid du Colombier 	[Twrite]	rwrite,
769a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
779a747e4fSDavid du Colombier 	[Tremove]	rremove,
789a747e4fSDavid du Colombier 	[Tstat]		rstat,
799a747e4fSDavid du Colombier 	[Twstat]	rwstat,
809a747e4fSDavid du Colombier };
819a747e4fSDavid du Colombier 
829a747e4fSDavid du Colombier char	Eperm[] =	"permission denied";
839a747e4fSDavid du Colombier char	Enotdir[] =	"not a directory";
843ff48bf5SDavid du Colombier char	Enoauth[] =	"lnfs: authentication not required";
859a747e4fSDavid du Colombier char	Enotexist[] =	"file does not exist";
869a747e4fSDavid du Colombier char	Einuse[] =	"file in use";
879a747e4fSDavid du Colombier char	Eexist[] =	"file exists";
889a747e4fSDavid du Colombier char	Eisdir[] =	"file is a directory";
899a747e4fSDavid du Colombier char	Enotowner[] =	"not owner";
909a747e4fSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
919a747e4fSDavid du Colombier char	Excl[] = 	"exclusive use file already open";
929a747e4fSDavid du Colombier char	Ename[] = 	"illegal name";
939a747e4fSDavid du Colombier char	Eversion[] =	"unknown 9P version";
949a747e4fSDavid du Colombier 
959a747e4fSDavid du Colombier void
usage(void)969a747e4fSDavid du Colombier usage(void)
979a747e4fSDavid du Colombier {
989a747e4fSDavid du Colombier 	fprint(2, "usage: %s [-r] [-s srvname] mountpoint\n", argv0);
999a747e4fSDavid du Colombier 	exits("usage");
1009a747e4fSDavid du Colombier }
1019a747e4fSDavid du Colombier 
1029a747e4fSDavid du Colombier void
notifyf(void * a,char * s)1039a747e4fSDavid du Colombier notifyf(void *a, char *s)
1049a747e4fSDavid du Colombier {
1059a747e4fSDavid du Colombier 	USED(a);
1069a747e4fSDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
1079a747e4fSDavid du Colombier 		noted(NCONT);
1089a747e4fSDavid du Colombier 	noted(NDFLT);
1099a747e4fSDavid du Colombier }
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier void
main(int argc,char * argv[])1129a747e4fSDavid du Colombier main(int argc, char *argv[])
1139a747e4fSDavid du Colombier {
1149a747e4fSDavid du Colombier 	char *defmnt;
1159a747e4fSDavid du Colombier 	int p[2];
1169a747e4fSDavid du Colombier 	Dir *d;
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	ARGBEGIN{
1199a747e4fSDavid du Colombier 	case 'r':
1209a747e4fSDavid du Colombier 		readonly = 1;
1219a747e4fSDavid du Colombier 		break;
1229a747e4fSDavid du Colombier 	case 'd':
1239a747e4fSDavid du Colombier 		debug = 1;
1249a747e4fSDavid du Colombier 		break;
1259a747e4fSDavid du Colombier 	case 's':
1269a747e4fSDavid du Colombier 		srvname = ARGF();
1279a747e4fSDavid du Colombier 		if(srvname == nil)
1289a747e4fSDavid du Colombier 			usage();
1299a747e4fSDavid du Colombier 		break;
1309a747e4fSDavid du Colombier 	default:
1319a747e4fSDavid du Colombier 		usage();
1329a747e4fSDavid du Colombier 	}ARGEND
1339a747e4fSDavid du Colombier 
1349a747e4fSDavid du Colombier 	if(argc < 1)
1359a747e4fSDavid du Colombier 		usage();
1369a747e4fSDavid du Colombier 	defmnt = argv[0];
1379a747e4fSDavid du Colombier 	d = dirstat(defmnt);
138*f6269f58SDavid du Colombier 	if(d == nil || !(d->qid.type & QTDIR))
1399a747e4fSDavid du Colombier 		sysfatal("mountpoint must be an accessible directory");
1409a747e4fSDavid du Colombier 	free(d);
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier 	if(pipe(p) < 0)
1439a747e4fSDavid du Colombier 		sysfatal("pipe failed");
1449a747e4fSDavid du Colombier 	mfd[0] = p[0];
1459a747e4fSDavid du Colombier 	mfd[1] = p[0];
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	user = getuser();
1489a747e4fSDavid du Colombier 	notify(notifyf);
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier 	if(srvname != nil)
1519a747e4fSDavid du Colombier 		post(srvname, p[1]);
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	if(debug)
1549a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
1559a747e4fSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
1569a747e4fSDavid du Colombier 	case -1:
1579a747e4fSDavid du Colombier 		sysfatal("fork: %r");
1589a747e4fSDavid du Colombier 	case 0:
1599a747e4fSDavid du Colombier 		close(p[1]);
1609a747e4fSDavid du Colombier 		chdir(defmnt);
1619a747e4fSDavid du Colombier 		io();
1629a747e4fSDavid du Colombier 		break;
1639a747e4fSDavid du Colombier 	default:
1649a747e4fSDavid du Colombier 		close(p[0]);	/* don't deadlock if child fails */
1659a747e4fSDavid du Colombier 		if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
1669a747e4fSDavid du Colombier 			sysfatal("mount failed: %r");
1679a747e4fSDavid du Colombier 	}
1689a747e4fSDavid du Colombier 	exits(0);
1699a747e4fSDavid du Colombier }
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier void
post(char * srvname,int pfd)1729a747e4fSDavid du Colombier post(char *srvname, int pfd)
1739a747e4fSDavid du Colombier {
1749a747e4fSDavid du Colombier 	char name[128];
1759a747e4fSDavid du Colombier 	int fd;
1769a747e4fSDavid du Colombier 
1779a747e4fSDavid du Colombier 	snprint(name, sizeof name, "#s/%s", srvname);
1789a747e4fSDavid du Colombier 	fd = create(name, OWRITE, 0666);
1799a747e4fSDavid du Colombier 	if(fd < 0)
1809a747e4fSDavid du Colombier 		sysfatal("create of %s failed: %r", srvname);
1819a747e4fSDavid du Colombier 	sprint(name, "%d", pfd);
1829a747e4fSDavid du Colombier 	if(write(fd, name, strlen(name)) < 0)
1839a747e4fSDavid du Colombier 		sysfatal("writing %s: %r", srvname);
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier char*
rversion(Fid *)1869a747e4fSDavid du Colombier rversion(Fid*)
1879a747e4fSDavid du Colombier {
1889a747e4fSDavid du Colombier 	Fid *f;
1899a747e4fSDavid du Colombier 
1909a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
1919a747e4fSDavid du Colombier 		if(f->busy)
1929a747e4fSDavid du Colombier 			rclunk(f);
1939a747e4fSDavid du Colombier 	if(thdr.msize > sizeof mdata)
1949a747e4fSDavid du Colombier 		rhdr.msize = sizeof mdata;
1959a747e4fSDavid du Colombier 	else
1969a747e4fSDavid du Colombier 		rhdr.msize = thdr.msize;
1979a747e4fSDavid du Colombier 	messagesize = rhdr.msize;
1989a747e4fSDavid du Colombier 	if(strncmp(thdr.version, "9P2000", 6) != 0)
1999a747e4fSDavid du Colombier 		return Eversion;
2009a747e4fSDavid du Colombier 	rhdr.version = "9P2000";
2019a747e4fSDavid du Colombier 	return nil;
2029a747e4fSDavid du Colombier }
2039a747e4fSDavid du Colombier 
2049a747e4fSDavid du Colombier char*
rauth(Fid *)2059a747e4fSDavid du Colombier rauth(Fid*)
2069a747e4fSDavid du Colombier {
2073ff48bf5SDavid du Colombier 	return Enoauth;
2089a747e4fSDavid du Colombier }
2099a747e4fSDavid du Colombier 
2109a747e4fSDavid du Colombier char*
rflush(Fid * f)2119a747e4fSDavid du Colombier rflush(Fid *f)
2129a747e4fSDavid du Colombier {
2139a747e4fSDavid du Colombier 	USED(f);
2149a747e4fSDavid du Colombier 	return nil;
2159a747e4fSDavid du Colombier }
2169a747e4fSDavid du Colombier 
2179a747e4fSDavid du Colombier char*
rattach(Fid * f)2189a747e4fSDavid du Colombier rattach(Fid *f)
2199a747e4fSDavid du Colombier {
2209a747e4fSDavid du Colombier 	/* no authentication! */
2219a747e4fSDavid du Colombier 	f->busy = 1;
2229a747e4fSDavid du Colombier 	if(thdr.uname[0])
2239a747e4fSDavid du Colombier 		f->user = estrdup(thdr.uname);
2249a747e4fSDavid du Colombier 	else
2259a747e4fSDavid du Colombier 		f->user = "none";
2269a747e4fSDavid du Colombier 	if(strcmp(user, "none") == 0)
2279a747e4fSDavid du Colombier 		user = f->user;
2289a747e4fSDavid du Colombier 	if(f->path)
2299a747e4fSDavid du Colombier 		s_free(f->path);
2309a747e4fSDavid du Colombier 	f->path = s_copy(".");
2319a747e4fSDavid du Colombier 	fidqid(f, &rhdr.qid);
2329a747e4fSDavid du Colombier 	f->attach = 1;
2339a747e4fSDavid du Colombier 	return nil;
2349a747e4fSDavid du Colombier }
2359a747e4fSDavid du Colombier 
2369a747e4fSDavid du Colombier char*
clone(Fid * f,Fid ** nf)2379a747e4fSDavid du Colombier clone(Fid *f, Fid **nf)
2389a747e4fSDavid du Colombier {
2399a747e4fSDavid du Colombier 	if(f->fd >= 0)
2409a747e4fSDavid du Colombier 		return Eisopen;
2419a747e4fSDavid du Colombier 	*nf = newfid(thdr.newfid);
2429a747e4fSDavid du Colombier 	(*nf)->busy = 1;
2439a747e4fSDavid du Colombier 	if((*nf)->path)
2449a747e4fSDavid du Colombier 		s_free((*nf)->path);
2459a747e4fSDavid du Colombier 	(*nf)->path = s_clone(f->path);
2469a747e4fSDavid du Colombier 	(*nf)->fd = -1;
2479a747e4fSDavid du Colombier 	(*nf)->user = f->user;
2489a747e4fSDavid du Colombier 	(*nf)->attach = 0;
2499a747e4fSDavid du Colombier 	return nil;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier 
2529a747e4fSDavid du Colombier char*
rwalk(Fid * f)2539a747e4fSDavid du Colombier rwalk(Fid *f)
2549a747e4fSDavid du Colombier {
2559a747e4fSDavid du Colombier 	char *name;
2569a747e4fSDavid du Colombier 	Fid *nf;
2579a747e4fSDavid du Colombier 	char *err;
2589a747e4fSDavid du Colombier 	int i;
2599a747e4fSDavid du Colombier 	String *npath;
2609a747e4fSDavid du Colombier 	Dir *d;
2619a747e4fSDavid du Colombier 	char *cp;
2629a747e4fSDavid du Colombier 	Qid qid;
2639a747e4fSDavid du Colombier 
2649a747e4fSDavid du Colombier 	err = nil;
2659a747e4fSDavid du Colombier 	nf = nil;
2669a747e4fSDavid du Colombier 	rhdr.nwqid = 0;
2679a747e4fSDavid du Colombier 	if(rhdr.newfid != rhdr.fid){
2689a747e4fSDavid du Colombier 		err = clone(f, &nf);
2699a747e4fSDavid du Colombier 		if(err)
2709a747e4fSDavid du Colombier 			return err;
2719a747e4fSDavid du Colombier 		f = nf;	/* walk the new fid */
2729a747e4fSDavid du Colombier 	}
2739a747e4fSDavid du Colombier 	readnames();
2749a747e4fSDavid du Colombier 	npath = s_clone(f->path);
2759a747e4fSDavid du Colombier 	if(thdr.nwname > 0){
2769a747e4fSDavid du Colombier 		for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
2779a747e4fSDavid du Colombier 			name = long2short(thdr.wname[i], 0);
2789a747e4fSDavid du Colombier 			if(strcmp(name, ".") == 0){
2799a747e4fSDavid du Colombier 				;
2809a747e4fSDavid du Colombier 			} else if(strcmp(name, "..") == 0){
2819a747e4fSDavid du Colombier 				cp = strrchr(s_to_c(npath), '/');
2829a747e4fSDavid du Colombier 				if(cp != nil){
2839a747e4fSDavid du Colombier 					*cp = 0;
2849a747e4fSDavid du Colombier 					npath->ptr = cp;
2859a747e4fSDavid du Colombier 				}
2869a747e4fSDavid du Colombier 			} else {
2879a747e4fSDavid du Colombier 				s_append(npath, "/");
2889a747e4fSDavid du Colombier 				s_append(npath, name);
2899a747e4fSDavid du Colombier 			}
2909a747e4fSDavid du Colombier 			d = dirstat(s_to_c(npath));
2919a747e4fSDavid du Colombier 			if(d == nil)
2929a747e4fSDavid du Colombier 				break;
2939a747e4fSDavid du Colombier 			rhdr.nwqid++;
2949a747e4fSDavid du Colombier 			qid = d->qid;
2959a747e4fSDavid du Colombier 			rhdr.wqid[i] = qid;
2969a747e4fSDavid du Colombier 			free(d);
2979a747e4fSDavid du Colombier 		}
2989a747e4fSDavid du Colombier 		if(i==0 && err == nil)
2999a747e4fSDavid du Colombier 			err = Enotexist;
3009a747e4fSDavid du Colombier 	}
3019a747e4fSDavid du Colombier 
3029a747e4fSDavid du Colombier 	/* if there was an error and we cloned, get rid of the new fid */
3039a747e4fSDavid du Colombier 	if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
3049a747e4fSDavid du Colombier 		f->busy = 0;
3059a747e4fSDavid du Colombier 		s_free(npath);
3069a747e4fSDavid du Colombier 	}
3079a747e4fSDavid du Colombier 
3089a747e4fSDavid du Colombier 	/* update the fid after a successful walk */
3099a747e4fSDavid du Colombier 	if(rhdr.nwqid == thdr.nwname){
3109a747e4fSDavid du Colombier 		s_free(f->path);
3119a747e4fSDavid du Colombier 		f->path = npath;
3129a747e4fSDavid du Colombier 	}
3139a747e4fSDavid du Colombier 	return err;
3149a747e4fSDavid du Colombier }
3159a747e4fSDavid du Colombier 
3169a747e4fSDavid du Colombier static char*
passerror(void)3179a747e4fSDavid du Colombier passerror(void)
3189a747e4fSDavid du Colombier {
3199a747e4fSDavid du Colombier 	static char err[256];
3209a747e4fSDavid du Colombier 
3219a747e4fSDavid du Colombier 	rerrstr(err, sizeof err);
3229a747e4fSDavid du Colombier 	return err;
3239a747e4fSDavid du Colombier }
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier char*
ropen(Fid * f)3269a747e4fSDavid du Colombier ropen(Fid *f)
3279a747e4fSDavid du Colombier {
3289a747e4fSDavid du Colombier 	if(readonly && (thdr.mode & 3))
3299a747e4fSDavid du Colombier 		return Eperm;
3309a747e4fSDavid du Colombier 	if(f->fd >= 0)
3319a747e4fSDavid du Colombier 		return Eisopen;
3329a747e4fSDavid du Colombier 	f->fd = open(s_to_c(f->path), thdr.mode);
3339a747e4fSDavid du Colombier 	if(f->fd < 0)
3349a747e4fSDavid du Colombier 		return passerror();
3359a747e4fSDavid du Colombier 	fidqid(f, &rhdr.qid);
3369a747e4fSDavid du Colombier 	f->qid = rhdr.qid;
3379a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
3389a747e4fSDavid du Colombier 	return nil;
3399a747e4fSDavid du Colombier }
3409a747e4fSDavid du Colombier 
3419a747e4fSDavid du Colombier char*
rcreate(Fid * f)3429a747e4fSDavid du Colombier rcreate(Fid *f)
3439a747e4fSDavid du Colombier {
3449a747e4fSDavid du Colombier 	char *name;
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	if(readonly)
3479a747e4fSDavid du Colombier 		return Eperm;
3489a747e4fSDavid du Colombier 	readnames();
3499a747e4fSDavid du Colombier 	name = long2short(thdr.name, 1);
3509a747e4fSDavid du Colombier 	if(f->fd >= 0)
3519a747e4fSDavid du Colombier 		return Eisopen;
3529a747e4fSDavid du Colombier 	s_append(f->path, "/");
3539a747e4fSDavid du Colombier 	s_append(f->path, name);
3549a747e4fSDavid du Colombier 	f->fd = create(s_to_c(f->path), thdr.mode, thdr.perm);
3559a747e4fSDavid du Colombier 	if(f->fd < 0)
3569a747e4fSDavid du Colombier 		return passerror();
3579a747e4fSDavid du Colombier 	fidqid(f, &rhdr.qid);
3589a747e4fSDavid du Colombier 	f->qid = rhdr.qid;
3599a747e4fSDavid du Colombier 	rhdr.iounit = messagesize-IOHDRSZ;
3609a747e4fSDavid du Colombier 	return nil;
3619a747e4fSDavid du Colombier }
3629a747e4fSDavid du Colombier 
3639a747e4fSDavid du Colombier char*
rreaddir(Fid * f)3649a747e4fSDavid du Colombier rreaddir(Fid *f)
3659a747e4fSDavid du Colombier {
3669a747e4fSDavid du Colombier 	int i;
3679a747e4fSDavid du Colombier 	int n;
3689a747e4fSDavid du Colombier 
3699a747e4fSDavid du Colombier 	/* reread the directory */
3709a747e4fSDavid du Colombier 	if(thdr.offset == 0){
3719a747e4fSDavid du Colombier 		if(f->dir)
3729a747e4fSDavid du Colombier 			free(f->dir);
3739a747e4fSDavid du Colombier 		f->dir = nil;
3749a747e4fSDavid du Colombier 		if(f->diroff != 0)
3759a747e4fSDavid du Colombier 			seek(f->fd, 0, 0);
3769a747e4fSDavid du Colombier 		f->ndir = dirreadall(f->fd, &f->dir);
3779a747e4fSDavid du Colombier 		f->diroff = 0;
3789a747e4fSDavid du Colombier 		if(f->ndir < 0)
3799a747e4fSDavid du Colombier 			return passerror();
380d9306527SDavid du Colombier 		readnames();
3819a747e4fSDavid du Colombier 		for(i = 0; i < f->ndir; i++)
3829a747e4fSDavid du Colombier 			f->dir[i].name = short2long(f->dir[i].name);
3839a747e4fSDavid du Colombier 	}
3849a747e4fSDavid du Colombier 
3859a747e4fSDavid du Colombier 	/* copy in as many directory entries as possible */
3869a747e4fSDavid du Colombier 	for(n = 0; f->diroff < f->ndir; n += i){
3879a747e4fSDavid du Colombier 		i = convD2M(&f->dir[f->diroff], rdata+n, thdr.count - n);
3889a747e4fSDavid du Colombier 		if(i <= BIT16SZ)
3899a747e4fSDavid du Colombier 			break;
3909a747e4fSDavid du Colombier 		f->diroff++;
3919a747e4fSDavid du Colombier 	}
3929a747e4fSDavid du Colombier 	rhdr.data = (char*)rdata;
3939a747e4fSDavid du Colombier 	rhdr.count = n;
3949a747e4fSDavid du Colombier 	return nil;
3959a747e4fSDavid du Colombier }
3969a747e4fSDavid du Colombier 
3979a747e4fSDavid du Colombier char*
rread(Fid * f)3989a747e4fSDavid du Colombier rread(Fid *f)
3999a747e4fSDavid du Colombier {
4009a747e4fSDavid du Colombier 	long n;
4019a747e4fSDavid du Colombier 
4029a747e4fSDavid du Colombier 	if(f->fd < 0)
4039a747e4fSDavid du Colombier 		return Enotexist;
4049a747e4fSDavid du Colombier 	if(thdr.count > messagesize-IOHDRSZ)
4059a747e4fSDavid du Colombier 		thdr.count = messagesize-IOHDRSZ;
406*f6269f58SDavid du Colombier 	if(f->qid.type & QTDIR)
4079a747e4fSDavid du Colombier 		return rreaddir(f);
4089a747e4fSDavid du Colombier 	n = pread(f->fd, rdata, thdr.count, thdr.offset);
4099a747e4fSDavid du Colombier 	if(n < 0)
4109a747e4fSDavid du Colombier 		return passerror();
4119a747e4fSDavid du Colombier 	rhdr.data = (char*)rdata;
4129a747e4fSDavid du Colombier 	rhdr.count = n;
4139a747e4fSDavid du Colombier 	return nil;
4149a747e4fSDavid du Colombier }
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier char*
rwrite(Fid * f)4179a747e4fSDavid du Colombier rwrite(Fid *f)
4189a747e4fSDavid du Colombier {
4199a747e4fSDavid du Colombier 	long n;
4209a747e4fSDavid du Colombier 
421*f6269f58SDavid du Colombier 	if(readonly || (f->qid.type & QTDIR))
4229a747e4fSDavid du Colombier 		return Eperm;
4239a747e4fSDavid du Colombier 	if(f->fd < 0)
4249a747e4fSDavid du Colombier 		return Enotexist;
4259a747e4fSDavid du Colombier 	if(thdr.count > messagesize-IOHDRSZ)	/* shouldn't happen, anyway */
4269a747e4fSDavid du Colombier 		thdr.count = messagesize-IOHDRSZ;
4279a747e4fSDavid du Colombier 	n = pwrite(f->fd, thdr.data, thdr.count, thdr.offset);
4289a747e4fSDavid du Colombier 	if(n < 0)
4299a747e4fSDavid du Colombier 		return passerror();
4309a747e4fSDavid du Colombier 	rhdr.count = n;
4319a747e4fSDavid du Colombier 	return nil;
4329a747e4fSDavid du Colombier }
4339a747e4fSDavid du Colombier 
4349a747e4fSDavid du Colombier char*
rclunk(Fid * f)4359a747e4fSDavid du Colombier rclunk(Fid *f)
4369a747e4fSDavid du Colombier {
4379a747e4fSDavid du Colombier 	f->busy = 0;
4389a747e4fSDavid du Colombier 	close(f->fd);
4399a747e4fSDavid du Colombier 	f->fd = -1;
4409a747e4fSDavid du Colombier 	f->path = s_reset(f->path);
4419a747e4fSDavid du Colombier 	if(f->attach){
4429a747e4fSDavid du Colombier 		free(f->user);
4439a747e4fSDavid du Colombier 		f->user = nil;
4449a747e4fSDavid du Colombier 	}
4459a747e4fSDavid du Colombier 	f->attach = 0;
4469a747e4fSDavid du Colombier 	if(f->dir != nil){
4479a747e4fSDavid du Colombier 		free(f->dir);
4489a747e4fSDavid du Colombier 		f->dir = nil;
4499a747e4fSDavid du Colombier 	}
4509a747e4fSDavid du Colombier 	f->diroff = f->ndir = 0;
4519a747e4fSDavid du Colombier 	return nil;
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier char*
rremove(Fid * f)4559a747e4fSDavid du Colombier rremove(Fid *f)
4569a747e4fSDavid du Colombier {
4579a747e4fSDavid du Colombier 	if(remove(s_to_c(f->path)) < 0)
4589a747e4fSDavid du Colombier 		return passerror();
4599a747e4fSDavid du Colombier 	return nil;
4609a747e4fSDavid du Colombier }
4619a747e4fSDavid du Colombier 
4629a747e4fSDavid du Colombier char*
rstat(Fid * f)4639a747e4fSDavid du Colombier rstat(Fid *f)
4649a747e4fSDavid du Colombier {
4659a747e4fSDavid du Colombier 	int n;
4669a747e4fSDavid du Colombier 	Dir *d;
4679a747e4fSDavid du Colombier 
4689a747e4fSDavid du Colombier 	d = dirstat(s_to_c(f->path));
4699a747e4fSDavid du Colombier 	if(d == nil)
4709a747e4fSDavid du Colombier 		return passerror();
4719a747e4fSDavid du Colombier 	d->name = short2long(d->name);
4729a747e4fSDavid du Colombier 	n = convD2M(d, statbuf, sizeof statbuf);
4739a747e4fSDavid du Colombier 	free(d);
4749a747e4fSDavid du Colombier 	if(n <= BIT16SZ)
4759a747e4fSDavid du Colombier 		return passerror();
4769a747e4fSDavid du Colombier 	rhdr.nstat = n;
4779a747e4fSDavid du Colombier 	rhdr.stat = statbuf;
4789a747e4fSDavid du Colombier 	return nil;
4799a747e4fSDavid du Colombier }
4809a747e4fSDavid du Colombier 
4819a747e4fSDavid du Colombier char*
rwstat(Fid * f)4829a747e4fSDavid du Colombier rwstat(Fid *f)
4839a747e4fSDavid du Colombier {
4849a747e4fSDavid du Colombier 	int n;
4859a747e4fSDavid du Colombier 	Dir d;
4869a747e4fSDavid du Colombier 
4879a747e4fSDavid du Colombier 	if(readonly)
4889a747e4fSDavid du Colombier 		return Eperm;
4899a747e4fSDavid du Colombier 	convM2D(thdr.stat, thdr.nstat, &d, (char*)rdata);
4909a747e4fSDavid du Colombier 	d.name = long2short(d.name, 1);
4919a747e4fSDavid du Colombier 	n = dirwstat(s_to_c(f->path), &d);
4929a747e4fSDavid du Colombier 	if(n < 0)
4939a747e4fSDavid du Colombier 		return passerror();
4949a747e4fSDavid du Colombier 	return nil;
4959a747e4fSDavid du Colombier }
4969a747e4fSDavid du Colombier 
4979a747e4fSDavid du Colombier Fid *
newfid(int fid)4989a747e4fSDavid du Colombier newfid(int fid)
4999a747e4fSDavid du Colombier {
5009a747e4fSDavid du Colombier 	Fid *f, *ff;
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier 	ff = 0;
5039a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
5049a747e4fSDavid du Colombier 		if(f->fid == fid)
5059a747e4fSDavid du Colombier 			return f;
5069a747e4fSDavid du Colombier 		else if(!ff && !f->busy)
5079a747e4fSDavid du Colombier 			ff = f;
5089a747e4fSDavid du Colombier 	if(ff){
5099a747e4fSDavid du Colombier 		ff->fid = fid;
5109a747e4fSDavid du Colombier 		return ff;
5119a747e4fSDavid du Colombier 	}
5129a747e4fSDavid du Colombier 	f = emalloc(sizeof *f);
5139a747e4fSDavid du Colombier 	f->path = s_reset(f->path);
5149a747e4fSDavid du Colombier 	f->fd = -1;
5159a747e4fSDavid du Colombier 	f->fid = fid;
5169a747e4fSDavid du Colombier 	f->next = fids;
5179a747e4fSDavid du Colombier 	fids = f;
5189a747e4fSDavid du Colombier 	return f;
5199a747e4fSDavid du Colombier }
5209a747e4fSDavid du Colombier 
5219a747e4fSDavid du Colombier void
io(void)5229a747e4fSDavid du Colombier io(void)
5239a747e4fSDavid du Colombier {
5249a747e4fSDavid du Colombier 	char *err;
5259a747e4fSDavid du Colombier 	int n, pid;
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier 	pid = getpid();
5289a747e4fSDavid du Colombier 
5299a747e4fSDavid du Colombier 	for(;;){
5309a747e4fSDavid du Colombier 		/*
5319a747e4fSDavid du Colombier 		 * reading from a pipe or a network device
5329a747e4fSDavid du Colombier 		 * will give an error after a few eof reads.
5339a747e4fSDavid du Colombier 		 * however, we cannot tell the difference
5349a747e4fSDavid du Colombier 		 * between a zero-length read and an interrupt
5359a747e4fSDavid du Colombier 		 * on the processes writing to us,
5369a747e4fSDavid du Colombier 		 * so we wait for the error.
5379a747e4fSDavid du Colombier 		 */
5389a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, messagesize);
5399a747e4fSDavid du Colombier 		if(n < 0)
5409a747e4fSDavid du Colombier 			sysfatal("mount read");
5419a747e4fSDavid du Colombier 		if(n == 0)
5429a747e4fSDavid du Colombier 			continue;
5439a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &thdr) == 0)
5449a747e4fSDavid du Colombier 			continue;
5459a747e4fSDavid du Colombier 
5469a747e4fSDavid du Colombier 		if(debug)
5479a747e4fSDavid du Colombier 			fprint(2, "%s %d:<-%F\n", argv0, pid, &thdr);
5489a747e4fSDavid du Colombier 
5499a747e4fSDavid du Colombier 		if(!fcalls[thdr.type])
5509a747e4fSDavid du Colombier 			err = "bad fcall type";
5519a747e4fSDavid du Colombier 		else
5529a747e4fSDavid du Colombier 			err = (*fcalls[thdr.type])(newfid(thdr.fid));
5539a747e4fSDavid du Colombier 		if(err){
5549a747e4fSDavid du Colombier 			rhdr.type = Rerror;
5559a747e4fSDavid du Colombier 			rhdr.ename = err;
5569a747e4fSDavid du Colombier 		}else{
5579a747e4fSDavid du Colombier 			rhdr.type = thdr.type + 1;
5589a747e4fSDavid du Colombier 			rhdr.fid = thdr.fid;
5599a747e4fSDavid du Colombier 		}
5609a747e4fSDavid du Colombier 		rhdr.tag = thdr.tag;
5619a747e4fSDavid du Colombier 		if(debug)
5629a747e4fSDavid du Colombier 			fprint(2, "%s %d:->%F\n", argv0, pid, &rhdr);/**/
5639a747e4fSDavid du Colombier 		n = convS2M(&rhdr, mdata, messagesize);
5649a747e4fSDavid du Colombier 		if(n == 0)
5659a747e4fSDavid du Colombier 			sysfatal("convS2M error on write");
5669a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n) != n)
5679a747e4fSDavid du Colombier 			sysfatal("mount write");
5689a747e4fSDavid du Colombier 	}
5699a747e4fSDavid du Colombier }
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier void *
emalloc(ulong n)5729a747e4fSDavid du Colombier emalloc(ulong n)
5739a747e4fSDavid du Colombier {
5749a747e4fSDavid du Colombier 	void *p;
5759a747e4fSDavid du Colombier 
5769a747e4fSDavid du Colombier 	p = malloc(n);
5779a747e4fSDavid du Colombier 	if(!p)
5789a747e4fSDavid du Colombier 		sysfatal("out of memory");
5799a747e4fSDavid du Colombier 	memset(p, 0, n);
5809a747e4fSDavid du Colombier 	return p;
5819a747e4fSDavid du Colombier }
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier void *
erealloc(void * p,ulong n)5849a747e4fSDavid du Colombier erealloc(void *p, ulong n)
5859a747e4fSDavid du Colombier {
5869a747e4fSDavid du Colombier 	p = realloc(p, n);
5879a747e4fSDavid du Colombier 	if(!p)
5889a747e4fSDavid du Colombier 		sysfatal("out of memory");
5899a747e4fSDavid du Colombier 	return p;
5909a747e4fSDavid du Colombier }
5919a747e4fSDavid du Colombier 
5929a747e4fSDavid du Colombier char *
estrdup(char * q)5939a747e4fSDavid du Colombier estrdup(char *q)
5949a747e4fSDavid du Colombier {
5959a747e4fSDavid du Colombier 	char *p;
5969a747e4fSDavid du Colombier 	int n;
5979a747e4fSDavid du Colombier 
5989a747e4fSDavid du Colombier 	n = strlen(q)+1;
5999a747e4fSDavid du Colombier 	p = malloc(n);
6009a747e4fSDavid du Colombier 	if(!p)
6019a747e4fSDavid du Colombier 		sysfatal("out of memory");
6029a747e4fSDavid du Colombier 	memmove(p, q, n);
6039a747e4fSDavid du Colombier 	return p;
6049a747e4fSDavid du Colombier }
6059a747e4fSDavid du Colombier 
6069a747e4fSDavid du Colombier void
fidqid(Fid * f,Qid * q)6079a747e4fSDavid du Colombier fidqid(Fid *f, Qid *q)
6089a747e4fSDavid du Colombier {
6099a747e4fSDavid du Colombier 	Dir *d;
6109a747e4fSDavid du Colombier 
6119a747e4fSDavid du Colombier 	d = dirstat(s_to_c(f->path));
6129a747e4fSDavid du Colombier 	if(d == nil)
6139a747e4fSDavid du Colombier 		*q = (Qid){0, 0, QTFILE};
6149a747e4fSDavid du Colombier 	else {
6159a747e4fSDavid du Colombier 		*q = d->qid;
6169a747e4fSDavid du Colombier 		free(d);
6179a747e4fSDavid du Colombier 	}
6189a747e4fSDavid du Colombier }
6199a747e4fSDavid du Colombier 
6209a747e4fSDavid du Colombier /*
6219a747e4fSDavid du Colombier  *  table of name translations
6229a747e4fSDavid du Colombier  *
6239a747e4fSDavid du Colombier  *  the file ./.longnames contains all the known long names.
6249a747e4fSDavid du Colombier  *  the short name is the first NAMELEN-1 bytes of the base64
6259a747e4fSDavid du Colombier  *  encoding of the MD5 hash of the longname.
6269a747e4fSDavid du Colombier  */
6279a747e4fSDavid du Colombier 
6289a747e4fSDavid du Colombier typedef struct Name Name;
6299a747e4fSDavid du Colombier struct Name
6309a747e4fSDavid du Colombier {
6319a747e4fSDavid du Colombier 	Name	*next;
6329a747e4fSDavid du Colombier 	char	shortname[NAMELEN];
6339a747e4fSDavid du Colombier 	char	*longname;
6349a747e4fSDavid du Colombier };
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier Dir *dbstat;	/* last stat of the name file */
6379a747e4fSDavid du Colombier char *namefile = "./.longnames";
6389a747e4fSDavid du Colombier char *namebuf;
6399a747e4fSDavid du Colombier Name *names;
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier Name*
newname(char * longname,int writeflag)6429a747e4fSDavid du Colombier newname(char *longname, int writeflag)
6439a747e4fSDavid du Colombier {
6449a747e4fSDavid du Colombier 	Name *np;
6459a747e4fSDavid du Colombier 	int n;
6469a747e4fSDavid du Colombier 	uchar digest[MD5dlen];
6479a747e4fSDavid du Colombier 	int fd;
6489a747e4fSDavid du Colombier 
6499a747e4fSDavid du Colombier 	/* chain in new name */
6509a747e4fSDavid du Colombier 	n = strlen(longname);
6519a747e4fSDavid du Colombier 	np = emalloc(sizeof(*np)+n+1);
6529a747e4fSDavid du Colombier 	np->longname = (char*)&np[1];
6539a747e4fSDavid du Colombier 	strcpy(np->longname, longname);
6549a747e4fSDavid du Colombier 	md5((uchar*)longname, n, digest, nil);
6559a747e4fSDavid du Colombier 	enc32(np->shortname, sizeof(np->shortname), digest, MD5dlen);
6569a747e4fSDavid du Colombier 	np->next = names;
6579a747e4fSDavid du Colombier 	names = np;
6589a747e4fSDavid du Colombier 
6599a747e4fSDavid du Colombier 	/* don't change namefile if we're read only */
6609a747e4fSDavid du Colombier 	if(!writeflag)
6619a747e4fSDavid du Colombier 		return np;
6629a747e4fSDavid du Colombier 
6639a747e4fSDavid du Colombier 	/* add to namefile */
6649a747e4fSDavid du Colombier 	fd = open(namefile, OWRITE);
6659a747e4fSDavid du Colombier 	if(fd >= 0){
6669a747e4fSDavid du Colombier 		seek(fd, 0, 2);
6679a747e4fSDavid du Colombier 		fprint(fd, "%s\n", longname);
6689a747e4fSDavid du Colombier 		close(fd);
6699a747e4fSDavid du Colombier 	}
6709a747e4fSDavid du Colombier 	return np;
6719a747e4fSDavid du Colombier }
6729a747e4fSDavid du Colombier 
6739a747e4fSDavid du Colombier void
freenames(void)6749a747e4fSDavid du Colombier freenames(void)
6759a747e4fSDavid du Colombier {
6769a747e4fSDavid du Colombier 	Name *np, *next;
6779a747e4fSDavid du Colombier 
6789a747e4fSDavid du Colombier 	for(np = names; np != nil; np = next){
6799a747e4fSDavid du Colombier 		next = np->next;
6809a747e4fSDavid du Colombier 		free(np);
6819a747e4fSDavid du Colombier 	}
6829a747e4fSDavid du Colombier 	names = nil;
6839a747e4fSDavid du Colombier }
6849a747e4fSDavid du Colombier 
6859a747e4fSDavid du Colombier /*
6869a747e4fSDavid du Colombier  *  reread the file if the qid.path has changed.
6879a747e4fSDavid du Colombier  *
6889a747e4fSDavid du Colombier  *  read any new entries if length has changed.
6899a747e4fSDavid du Colombier  */
6909a747e4fSDavid du Colombier void
readnames(void)6919a747e4fSDavid du Colombier readnames(void)
6929a747e4fSDavid du Colombier {
6939a747e4fSDavid du Colombier 	Dir *d;
6949a747e4fSDavid du Colombier 	int fd;
6959a747e4fSDavid du Colombier 	vlong offset;
6969a747e4fSDavid du Colombier 	Biobuf *b;
6979a747e4fSDavid du Colombier 	char *p;
6989a747e4fSDavid du Colombier 
6999a747e4fSDavid du Colombier 	d = dirstat(namefile);
7009a747e4fSDavid du Colombier 	if(d == nil){
7019a747e4fSDavid du Colombier 		if(readonly)
7029a747e4fSDavid du Colombier 			return;
7039a747e4fSDavid du Colombier 
7049a747e4fSDavid du Colombier 		/* create file if it doesn't exist */
7059a747e4fSDavid du Colombier 		fd = create(namefile, OREAD, DMAPPEND|0666);
7069a747e4fSDavid du Colombier 		if(fd < 0)
7079a747e4fSDavid du Colombier 			return;
7089a747e4fSDavid du Colombier 		if(dbstat != nil)
7099a747e4fSDavid du Colombier 			free(dbstat);
7109a747e4fSDavid du Colombier 		dbstat = nil;
7119a747e4fSDavid du Colombier 		close(fd);
7129a747e4fSDavid du Colombier 		return;
7139a747e4fSDavid du Colombier 	}
7149a747e4fSDavid du Colombier 
7159a747e4fSDavid du Colombier 	/* up to date? */
7169a747e4fSDavid du Colombier 	offset = 0;
7179a747e4fSDavid du Colombier 	if(dbstat != nil){
7189a747e4fSDavid du Colombier 		if(d->qid.path == dbstat->qid.path){
7199a747e4fSDavid du Colombier 			if(d->length <= dbstat->length){
7209a747e4fSDavid du Colombier 				free(d);
7219a747e4fSDavid du Colombier 				return;
7229a747e4fSDavid du Colombier 			}
7239a747e4fSDavid du Colombier 			offset = dbstat->length;
7249a747e4fSDavid du Colombier 		} else {
7259a747e4fSDavid du Colombier 			freenames();
7269a747e4fSDavid du Colombier 		}
7279a747e4fSDavid du Colombier 		free(dbstat);
7289a747e4fSDavid du Colombier 		dbstat = nil;
7299a747e4fSDavid du Colombier 	}
7309a747e4fSDavid du Colombier 
7319a747e4fSDavid du Colombier 	/* read file */
7329a747e4fSDavid du Colombier 	b = Bopen(namefile, OREAD);
7339a747e4fSDavid du Colombier 	if(b == nil){
7349a747e4fSDavid du Colombier 		free(d);
7359a747e4fSDavid du Colombier 		return;
7369a747e4fSDavid du Colombier 	}
7379a747e4fSDavid du Colombier 	Bseek(b, offset, 0);
7389a747e4fSDavid du Colombier 	while((p = Brdline(b, '\n')) != nil){
7399a747e4fSDavid du Colombier 		p[Blinelen(b)-1] = 0;
7409a747e4fSDavid du Colombier 		newname(p, 0);
7419a747e4fSDavid du Colombier 	}
7429a747e4fSDavid du Colombier 	Bterm(b);
7439a747e4fSDavid du Colombier 	dbstat = d;
7449a747e4fSDavid du Colombier }
7459a747e4fSDavid du Colombier 
7469a747e4fSDavid du Colombier /*
7479a747e4fSDavid du Colombier  *  look up a long name,  if it doesn't exist in the
7489a747e4fSDavid du Colombier  *  file, add an entry to the file if the writeflag is
7499a747e4fSDavid du Colombier  *  non-zero.  Return a pointer to the short name.
7509a747e4fSDavid du Colombier  */
7519a747e4fSDavid du Colombier char*
long2short(char * longname,int writeflag)7529a747e4fSDavid du Colombier long2short(char *longname, int writeflag)
7539a747e4fSDavid du Colombier {
7549a747e4fSDavid du Colombier 	Name *np;
7559a747e4fSDavid du Colombier 
7569a747e4fSDavid du Colombier 	if(strlen(longname) < NAMELEN-1 && strpbrk(longname, " ")==nil)
7579a747e4fSDavid du Colombier 		return longname;
7589a747e4fSDavid du Colombier 
7599a747e4fSDavid du Colombier 	for(np = names; np != nil; np = np->next)
7609a747e4fSDavid du Colombier 		if(strcmp(longname, np->longname) == 0)
7619a747e4fSDavid du Colombier 			return np->shortname;
7629a747e4fSDavid du Colombier 	if(!writeflag)
7639a747e4fSDavid du Colombier 		return longname;
7649a747e4fSDavid du Colombier 	np = newname(longname, !readonly);
7659a747e4fSDavid du Colombier 	return np->shortname;
7669a747e4fSDavid du Colombier }
7679a747e4fSDavid du Colombier 
7689a747e4fSDavid du Colombier /*
7699a747e4fSDavid du Colombier  *  look up a short name, if it doesn't exist, return the
7709a747e4fSDavid du Colombier  *  longname.
7719a747e4fSDavid du Colombier  */
7729a747e4fSDavid du Colombier char*
short2long(char * shortname)7739a747e4fSDavid du Colombier short2long(char *shortname)
7749a747e4fSDavid du Colombier {
7759a747e4fSDavid du Colombier 	Name *np;
7769a747e4fSDavid du Colombier 
7779a747e4fSDavid du Colombier 	for(np = names; np != nil; np = np->next)
7789a747e4fSDavid du Colombier 		if(strcmp(shortname, np->shortname) == 0)
7799a747e4fSDavid du Colombier 			return np->longname;
7809a747e4fSDavid du Colombier 	return shortname;
7819a747e4fSDavid du Colombier }
782