xref: /plan9-contrib/sys/src/9/port/chan.c (revision 70b6ec21992a2c55178a99cc7dddb19f051e140a)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
89a747e4fSDavid du Colombier int chandebug=0;		/* toggled by sysr1 */
94afe124fSDavid du Colombier #define DBG if(chandebug)iprint
109a747e4fSDavid du Colombier 
117dd7cddfSDavid du Colombier enum
127dd7cddfSDavid du Colombier {
134afe124fSDavid du Colombier 	PATHSLOP	= 20,
144afe124fSDavid du Colombier 	PATHMSLOP	= 20,
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier 
173e12c5d1SDavid du Colombier struct
183e12c5d1SDavid du Colombier {
193e12c5d1SDavid du Colombier 	Lock;
203e12c5d1SDavid du Colombier 	int	fid;
217dd7cddfSDavid du Colombier 	Chan	*free;
227dd7cddfSDavid du Colombier 	Chan	*list;
233e12c5d1SDavid du Colombier }chanalloc;
243e12c5d1SDavid du Colombier 
259a747e4fSDavid du Colombier typedef struct Elemlist Elemlist;
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier struct Elemlist
289a747e4fSDavid du Colombier {
29312a1df1SDavid du Colombier 	char	*aname;	/* original name */
309a747e4fSDavid du Colombier 	char	*name;	/* copy of name, so '/' can be overwritten */
319a747e4fSDavid du Colombier 	int	nelems;
329a747e4fSDavid du Colombier 	char	**elems;
339a747e4fSDavid du Colombier 	int	*off;
34fb7f0c93SDavid du Colombier 	int	mustbedir;
35312a1df1SDavid du Colombier 	int	nerror;
368b6d9ba0SDavid du Colombier 	int	prefix;
379a747e4fSDavid du Colombier };
389a747e4fSDavid du Colombier 
397dd7cddfSDavid du Colombier #define SEP(c) ((c) == 0 || (c) == '/')
404afe124fSDavid du Colombier 
414afe124fSDavid du Colombier static void
dumpmount(void)424afe124fSDavid du Colombier dumpmount(void)		/* DEBUGGING */
434afe124fSDavid du Colombier {
444afe124fSDavid du Colombier 	Pgrp *pg;
454afe124fSDavid du Colombier 	Mount *t;
464afe124fSDavid du Colombier 	Mhead **h, **he, *f;
474afe124fSDavid du Colombier 
484afe124fSDavid du Colombier 	if(up == nil){
494afe124fSDavid du Colombier 		print("no process for dumpmount\n");
504afe124fSDavid du Colombier 		return;
514afe124fSDavid du Colombier 	}
524afe124fSDavid du Colombier 	pg = up->pgrp;
534afe124fSDavid du Colombier 	if(pg == nil){
544afe124fSDavid du Colombier 		print("no pgrp for dumpmount\n");
554afe124fSDavid du Colombier 		return;
564afe124fSDavid du Colombier 	}
574afe124fSDavid du Colombier 	rlock(&pg->ns);
584afe124fSDavid du Colombier 	if(waserror()){
594afe124fSDavid du Colombier 		runlock(&pg->ns);
604afe124fSDavid du Colombier 		nexterror();
614afe124fSDavid du Colombier 	}
624afe124fSDavid du Colombier 
634afe124fSDavid du Colombier 	he = &pg->mnthash[MNTHASH];
644afe124fSDavid du Colombier 	for(h = pg->mnthash; h < he; h++){
654afe124fSDavid du Colombier 		for(f = *h; f; f = f->hash){
66567483c8SDavid du Colombier 			print("head: %#p: %s %#llux.%lud %C %lud -> \n", f,
674afe124fSDavid du Colombier 				f->from->path->s, f->from->qid.path,
684afe124fSDavid du Colombier 				f->from->qid.vers, devtab[f->from->type]->dc,
694afe124fSDavid du Colombier 				f->from->dev);
704afe124fSDavid du Colombier 			for(t = f->mount; t; t = t->next)
71567483c8SDavid du Colombier 				print("\t%#p: %s (umh %#p) (path %#.8llux dev %C %lud)\n", t, t->to->path->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
724afe124fSDavid du Colombier 		}
734afe124fSDavid du Colombier 	}
744afe124fSDavid du Colombier 	poperror();
754afe124fSDavid du Colombier 	runlock(&pg->ns);
764afe124fSDavid du Colombier }
774afe124fSDavid du Colombier 
784afe124fSDavid du Colombier char*
chanpath(Chan * c)794afe124fSDavid du Colombier chanpath(Chan *c)
804afe124fSDavid du Colombier {
814afe124fSDavid du Colombier 	if(c == nil)
824afe124fSDavid du Colombier 		return "<nil chan>";
834afe124fSDavid du Colombier 	if(c->path == nil)
844afe124fSDavid du Colombier 		return "<nil path>";
854afe124fSDavid du Colombier 	if(c->path->s == nil)
864afe124fSDavid du Colombier 		return "<nil path.s>";
874afe124fSDavid du Colombier 	return c->path->s;
884afe124fSDavid du Colombier }
897dd7cddfSDavid du Colombier 
903e12c5d1SDavid du Colombier int
isdotdot(char * p)919a747e4fSDavid du Colombier isdotdot(char *p)
929a747e4fSDavid du Colombier {
939a747e4fSDavid du Colombier 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
949a747e4fSDavid du Colombier }
959a747e4fSDavid du Colombier 
96e288d156SDavid du Colombier long
incref(Ref * r)973e12c5d1SDavid du Colombier incref(Ref *r)
983e12c5d1SDavid du Colombier {
99e288d156SDavid du Colombier 	long x;
1003e12c5d1SDavid du Colombier 
101fe853e23SDavid du Colombier 	lock(r);
1023e12c5d1SDavid du Colombier 	x = ++r->ref;
103fe853e23SDavid du Colombier 	unlock(r);
1043e12c5d1SDavid du Colombier 	return x;
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier 
107e288d156SDavid du Colombier long
decref(Ref * r)1083e12c5d1SDavid du Colombier decref(Ref *r)
1093e12c5d1SDavid du Colombier {
110e288d156SDavid du Colombier 	long x;
1113e12c5d1SDavid du Colombier 
112fe853e23SDavid du Colombier 	lock(r);
1133e12c5d1SDavid du Colombier 	x = --r->ref;
114fe853e23SDavid du Colombier 	unlock(r);
1153e12c5d1SDavid du Colombier 	if(x < 0)
116567483c8SDavid du Colombier 		panic("decref pc=%#p", getcallerpc(&r));
1173e12c5d1SDavid du Colombier 
1183e12c5d1SDavid du Colombier 	return x;
1193e12c5d1SDavid du Colombier }
1203e12c5d1SDavid du Colombier 
1219a747e4fSDavid du Colombier /*
1229a747e4fSDavid du Colombier  * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
1239a747e4fSDavid du Colombier  * truncates if necessary, always zero terminates, does not zero fill,
1249a747e4fSDavid du Colombier  * and puts ... at the end of the string if it's too long.  Usually used to
1259a747e4fSDavid du Colombier  * save a string in up->genbuf;
1269a747e4fSDavid du Colombier  */
1279a747e4fSDavid du Colombier void
kstrcpy(char * s,char * t,int ns)1289a747e4fSDavid du Colombier kstrcpy(char *s, char *t, int ns)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier 	int nt;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	nt = strlen(t);
1339a747e4fSDavid du Colombier 	if(nt+1 <= ns){
1349a747e4fSDavid du Colombier 		memmove(s, t, nt+1);
1359a747e4fSDavid du Colombier 		return;
1369a747e4fSDavid du Colombier 	}
1379a747e4fSDavid du Colombier 	/* too long */
1389a747e4fSDavid du Colombier 	if(ns < 4){
1399a747e4fSDavid du Colombier 		/* but very short! */
1409a747e4fSDavid du Colombier 		strncpy(s, t, ns);
1419a747e4fSDavid du Colombier 		return;
1429a747e4fSDavid du Colombier 	}
1439a747e4fSDavid du Colombier 	/* truncate with ... at character boundary (very rare case) */
1449a747e4fSDavid du Colombier 	memmove(s, t, ns-4);
1459a747e4fSDavid du Colombier 	ns -= 4;
1469a747e4fSDavid du Colombier 	s[ns] = '\0';
1479a747e4fSDavid du Colombier 	/* look for first byte of UTF-8 sequence by skipping continuation bytes */
1489a747e4fSDavid du Colombier 	while(ns>0 && (s[--ns]&0xC0)==0x80)
1499a747e4fSDavid du Colombier 		;
1509a747e4fSDavid du Colombier 	strcpy(s+ns, "...");
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier int
emptystr(char * s)1549a747e4fSDavid du Colombier emptystr(char *s)
1559a747e4fSDavid du Colombier {
1569a747e4fSDavid du Colombier 	if(s == nil)
1579a747e4fSDavid du Colombier 		return 1;
1589a747e4fSDavid du Colombier 	if(s[0] == '\0')
1599a747e4fSDavid du Colombier 		return 1;
1609a747e4fSDavid du Colombier 	return 0;
1619a747e4fSDavid du Colombier }
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier /*
1649a747e4fSDavid du Colombier  * Atomically replace *p with copy of s
1659a747e4fSDavid du Colombier  */
1669a747e4fSDavid du Colombier void
kstrdup(char ** p,char * s)1679a747e4fSDavid du Colombier kstrdup(char **p, char *s)
1689a747e4fSDavid du Colombier {
1699a747e4fSDavid du Colombier 	int n;
1709a747e4fSDavid du Colombier 	char *t, *prev;
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	n = strlen(s)+1;
1739a747e4fSDavid du Colombier 	/* if it's a user, we can wait for memory; if not, something's very wrong */
1749a747e4fSDavid du Colombier 	if(up){
1759a747e4fSDavid du Colombier 		t = smalloc(n);
1769a747e4fSDavid du Colombier 		setmalloctag(t, getcallerpc(&p));
1779a747e4fSDavid du Colombier 	}else{
1789a747e4fSDavid du Colombier 		t = malloc(n);
1799a747e4fSDavid du Colombier 		if(t == nil)
1809a747e4fSDavid du Colombier 			panic("kstrdup: no memory");
1819a747e4fSDavid du Colombier 	}
1829a747e4fSDavid du Colombier 	memmove(t, s, n);
1839a747e4fSDavid du Colombier 	prev = *p;
1849a747e4fSDavid du Colombier 	*p = t;
1859a747e4fSDavid du Colombier 	free(prev);
1869a747e4fSDavid du Colombier }
1879a747e4fSDavid du Colombier 
188aeee3693SDavid du Colombier static int debugstart = 1;
189b4124be8SDavid du Colombier 
1903e12c5d1SDavid du Colombier void
chandevreset(void)1913e12c5d1SDavid du Colombier chandevreset(void)
1923e12c5d1SDavid du Colombier {
1933e12c5d1SDavid du Colombier 	int i;
1943e12c5d1SDavid du Colombier 
195922818baSDavid du Colombier 	todinit();	/* avoid later reentry causing infinite recursion */
196b4124be8SDavid du Colombier 	debugstart = getconf("*debugstart") != nil;
197b4124be8SDavid du Colombier 	if(debugstart)
198b4124be8SDavid du Colombier 		iprint("reset:");
199b4124be8SDavid du Colombier 	for(i=0; devtab[i] != nil; i++) {
200b4124be8SDavid du Colombier 		if(debugstart)
201b4124be8SDavid du Colombier 			iprint(" %s", devtab[i]->name);
2027dd7cddfSDavid du Colombier 		devtab[i]->reset();
2033e12c5d1SDavid du Colombier 	}
204b4124be8SDavid du Colombier 	if(debugstart)
205b4124be8SDavid du Colombier 		iprint("\n");
206b4124be8SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier void
chandevinit(void)2093e12c5d1SDavid du Colombier chandevinit(void)
2103e12c5d1SDavid du Colombier {
2113e12c5d1SDavid du Colombier 	int i;
2123e12c5d1SDavid du Colombier 
213b4124be8SDavid du Colombier 	if(debugstart)
214b4124be8SDavid du Colombier 		iprint("init:");
215b4124be8SDavid du Colombier 	for(i=0; devtab[i] != nil; i++) {
216b4124be8SDavid du Colombier 		if(debugstart)
217b4124be8SDavid du Colombier 			iprint(" %s", devtab[i]->name);
2187dd7cddfSDavid du Colombier 		devtab[i]->init();
2193e12c5d1SDavid du Colombier 	}
220b4124be8SDavid du Colombier 	if(debugstart)
221b4124be8SDavid du Colombier 		iprint("\n");
222b4124be8SDavid du Colombier }
2233e12c5d1SDavid du Colombier 
2249a747e4fSDavid du Colombier void
chandevshutdown(void)2259a747e4fSDavid du Colombier chandevshutdown(void)
2269a747e4fSDavid du Colombier {
2279a747e4fSDavid du Colombier 	int i;
2289a747e4fSDavid du Colombier 
2299a747e4fSDavid du Colombier 	/* shutdown in reverse order */
2309a747e4fSDavid du Colombier 	for(i=0; devtab[i] != nil; i++)
2319a747e4fSDavid du Colombier 		;
2329a747e4fSDavid du Colombier 	for(i--; i >= 0; i--)
2339a747e4fSDavid du Colombier 		devtab[i]->shutdown();
2349a747e4fSDavid du Colombier }
2359a747e4fSDavid du Colombier 
2363e12c5d1SDavid du Colombier Chan*
newchan(void)2373e12c5d1SDavid du Colombier newchan(void)
2383e12c5d1SDavid du Colombier {
2393e12c5d1SDavid du Colombier 	Chan *c;
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	lock(&chanalloc);
2423e12c5d1SDavid du Colombier 	c = chanalloc.free;
2437dd7cddfSDavid du Colombier 	if(c != 0)
2443e12c5d1SDavid du Colombier 		chanalloc.free = c->next;
2453e12c5d1SDavid du Colombier 	unlock(&chanalloc);
2463e12c5d1SDavid du Colombier 
2479a747e4fSDavid du Colombier 	if(c == nil){
2483e12c5d1SDavid du Colombier 		c = smalloc(sizeof(Chan));
2497dd7cddfSDavid du Colombier 		lock(&chanalloc);
2507dd7cddfSDavid du Colombier 		c->fid = ++chanalloc.fid;
2517dd7cddfSDavid du Colombier 		c->link = chanalloc.list;
2527dd7cddfSDavid du Colombier 		chanalloc.list = c;
2537dd7cddfSDavid du Colombier 		unlock(&chanalloc);
2543e12c5d1SDavid du Colombier 	}
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier 	/* if you get an error before associating with a dev,
2573e12c5d1SDavid du Colombier 	   close calls rootclose, a nop */
2583e12c5d1SDavid du Colombier 	c->type = 0;
2593e12c5d1SDavid du Colombier 	c->flag = 0;
2603e12c5d1SDavid du Colombier 	c->ref = 1;
2613e12c5d1SDavid du Colombier 	c->dev = 0;
2623e12c5d1SDavid du Colombier 	c->offset = 0;
263dc5a79c1SDavid du Colombier 	c->devoffset = 0;
2649a747e4fSDavid du Colombier 	c->iounit = 0;
2659a747e4fSDavid du Colombier 	c->umh = 0;
2667dd7cddfSDavid du Colombier 	c->uri = 0;
2679a747e4fSDavid du Colombier 	c->dri = 0;
2683e12c5d1SDavid du Colombier 	c->aux = 0;
2693e12c5d1SDavid du Colombier 	c->mchan = 0;
2707dd7cddfSDavid du Colombier 	c->mcp = 0;
2719a747e4fSDavid du Colombier 	c->mux = 0;
2729a747e4fSDavid du Colombier 	memset(&c->mqid, 0, sizeof(c->mqid));
2734afe124fSDavid du Colombier 	c->path = 0;
274dc5a79c1SDavid du Colombier 	c->ismtpt = 0;
2754afe124fSDavid du Colombier 
2763e12c5d1SDavid du Colombier 	return c;
2773e12c5d1SDavid du Colombier }
2783e12c5d1SDavid du Colombier 
2794afe124fSDavid du Colombier Ref npath;
2807dd7cddfSDavid du Colombier 
2814afe124fSDavid du Colombier Path*
newpath(char * s)2824afe124fSDavid du Colombier newpath(char *s)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier 	int i;
2854afe124fSDavid du Colombier 	Path *p;
2867dd7cddfSDavid du Colombier 
2874afe124fSDavid du Colombier 	p = smalloc(sizeof(Path));
2887dd7cddfSDavid du Colombier 	i = strlen(s);
2894afe124fSDavid du Colombier 	p->len = i;
2904afe124fSDavid du Colombier 	p->alen = i+PATHSLOP;
2914afe124fSDavid du Colombier 	p->s = smalloc(p->alen);
2924afe124fSDavid du Colombier 	memmove(p->s, s, i+1);
2934afe124fSDavid du Colombier 	p->ref = 1;
2944afe124fSDavid du Colombier 	incref(&npath);
2954afe124fSDavid du Colombier 
2964afe124fSDavid du Colombier 	/*
2974afe124fSDavid du Colombier 	 * Cannot use newpath for arbitrary names because the mtpt
2984afe124fSDavid du Colombier 	 * array will not be populated correctly.  The names #/ and / are
2994afe124fSDavid du Colombier 	 * allowed, but other names with / in them draw warnings.
3004afe124fSDavid du Colombier 	 */
3014afe124fSDavid du Colombier 	if(strchr(s, '/') && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
302567483c8SDavid du Colombier 		print("newpath: %s from %#p\n", s, getcallerpc(&s));
3034afe124fSDavid du Colombier 
3044afe124fSDavid du Colombier 	p->mlen = 1;
3054afe124fSDavid du Colombier 	p->malen = PATHMSLOP;
3064afe124fSDavid du Colombier 	p->mtpt = smalloc(p->malen*sizeof p->mtpt[0]);
3074afe124fSDavid du Colombier 	return p;
3084afe124fSDavid du Colombier }
3094afe124fSDavid du Colombier 
3104afe124fSDavid du Colombier static Path*
copypath(Path * p)3114afe124fSDavid du Colombier copypath(Path *p)
3124afe124fSDavid du Colombier {
3134afe124fSDavid du Colombier 	int i;
3144afe124fSDavid du Colombier 	Path *pp;
3154afe124fSDavid du Colombier 
3164afe124fSDavid du Colombier 	pp = smalloc(sizeof(Path));
3174afe124fSDavid du Colombier 	pp->ref = 1;
3184afe124fSDavid du Colombier 	incref(&npath);
3194afe124fSDavid du Colombier 	DBG("copypath %s %p => %p\n", p->s, p, pp);
3204afe124fSDavid du Colombier 
3214afe124fSDavid du Colombier 	pp->len = p->len;
3224afe124fSDavid du Colombier 	pp->alen = p->alen;
3234afe124fSDavid du Colombier 	pp->s = smalloc(p->alen);
3244afe124fSDavid du Colombier 	memmove(pp->s, p->s, p->len+1);
3254afe124fSDavid du Colombier 
3264afe124fSDavid du Colombier 	pp->mlen = p->mlen;
3274afe124fSDavid du Colombier 	pp->malen = p->malen;
3284afe124fSDavid du Colombier 	pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]);
3294afe124fSDavid du Colombier 	for(i=0; i<pp->mlen; i++){
3304afe124fSDavid du Colombier 		pp->mtpt[i] = p->mtpt[i];
3314afe124fSDavid du Colombier 		if(pp->mtpt[i])
3324afe124fSDavid du Colombier 			incref(pp->mtpt[i]);
3334afe124fSDavid du Colombier 	}
3344afe124fSDavid du Colombier 
3354afe124fSDavid du Colombier 	return pp;
3367dd7cddfSDavid du Colombier }
3377dd7cddfSDavid du Colombier 
3387dd7cddfSDavid du Colombier void
pathclose(Path * p)3394afe124fSDavid du Colombier pathclose(Path *p)
3407dd7cddfSDavid du Colombier {
3414afe124fSDavid du Colombier 	int i;
3424afe124fSDavid du Colombier 
3434afe124fSDavid du Colombier 	if(p == nil)
3447dd7cddfSDavid du Colombier 		return;
3454afe124fSDavid du Colombier //XXX
3464afe124fSDavid du Colombier 	DBG("pathclose %p %s ref=%ld =>", p, p->s, p->ref);
3474afe124fSDavid du Colombier 	for(i=0; i<p->mlen; i++)
3484afe124fSDavid du Colombier 		DBG(" %p", p->mtpt[i]);
3494afe124fSDavid du Colombier 	DBG("\n");
3504afe124fSDavid du Colombier 
3514afe124fSDavid du Colombier 	if(decref(p))
3527dd7cddfSDavid du Colombier 		return;
3534afe124fSDavid du Colombier 	decref(&npath);
3544afe124fSDavid du Colombier 	free(p->s);
3554afe124fSDavid du Colombier 	for(i=0; i<p->mlen; i++)
3564afe124fSDavid du Colombier 		if(p->mtpt[i])
3574afe124fSDavid du Colombier 			cclose(p->mtpt[i]);
3584afe124fSDavid du Colombier 	free(p->mtpt);
3594afe124fSDavid du Colombier 	free(p);
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier 
3624afe124fSDavid du Colombier /*
3634afe124fSDavid du Colombier  * In place, rewrite name to compress multiple /, eliminate ., and process ..
3644afe124fSDavid du Colombier  * (Really only called to remove a trailing .. that has been added.
3654afe124fSDavid du Colombier  * Otherwise would need to update n->mtpt as well.)
3664afe124fSDavid du Colombier  */
3674afe124fSDavid du Colombier static void
fixdotdotname(Path * p)3684afe124fSDavid du Colombier fixdotdotname(Path *p)
3697dd7cddfSDavid du Colombier {
3704afe124fSDavid du Colombier 	char *r;
3714afe124fSDavid du Colombier 
3724afe124fSDavid du Colombier 	if(p->s[0] == '#'){
3734afe124fSDavid du Colombier 		r = strchr(p->s, '/');
3744afe124fSDavid du Colombier 		if(r == nil)
3754afe124fSDavid du Colombier 			return;
3764afe124fSDavid du Colombier 		cleanname(r);
3774afe124fSDavid du Colombier 
3784afe124fSDavid du Colombier 		/*
3794afe124fSDavid du Colombier 		 * The correct name is #i rather than #i/,
3804afe124fSDavid du Colombier 		 * but the correct name of #/ is #/.
3814afe124fSDavid du Colombier 		 */
3824afe124fSDavid du Colombier 		if(strcmp(r, "/")==0 && p->s[1] != '/')
3834afe124fSDavid du Colombier 			*r = '\0';
3844afe124fSDavid du Colombier 	}else
3854afe124fSDavid du Colombier 		cleanname(p->s);
3864afe124fSDavid du Colombier 	p->len = strlen(p->s);
3874afe124fSDavid du Colombier }
3884afe124fSDavid du Colombier 
3894afe124fSDavid du Colombier static Path*
uniquepath(Path * p)3904afe124fSDavid du Colombier uniquepath(Path *p)
3914afe124fSDavid du Colombier {
3924afe124fSDavid du Colombier 	Path *new;
3934afe124fSDavid du Colombier 
3944afe124fSDavid du Colombier 	if(p->ref > 1){
3954afe124fSDavid du Colombier 		/* copy on write */
3964afe124fSDavid du Colombier 		new = copypath(p);
3974afe124fSDavid du Colombier 		pathclose(p);
3984afe124fSDavid du Colombier 		p = new;
3994afe124fSDavid du Colombier 	}
4004afe124fSDavid du Colombier 	return p;
4014afe124fSDavid du Colombier }
4024afe124fSDavid du Colombier 
4034afe124fSDavid du Colombier static Path*
addelem(Path * p,char * s,Chan * from)4044afe124fSDavid du Colombier addelem(Path *p, char *s, Chan *from)
4054afe124fSDavid du Colombier {
4067dd7cddfSDavid du Colombier 	char *t;
4074afe124fSDavid du Colombier 	int a, i;
4084afe124fSDavid du Colombier 	Chan *c, **tt;
4097dd7cddfSDavid du Colombier 
4109a747e4fSDavid du Colombier 	if(s[0]=='.' && s[1]=='\0')
4114afe124fSDavid du Colombier 		return p;
4129a747e4fSDavid du Colombier 
4134afe124fSDavid du Colombier 	p = uniquepath(p);
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	i = strlen(s);
4164afe124fSDavid du Colombier 	if(p->len+1+i+1 > p->alen){
4174afe124fSDavid du Colombier 		a = p->len+1+i+1 + PATHSLOP;
4187dd7cddfSDavid du Colombier 		t = smalloc(a);
4194afe124fSDavid du Colombier 		memmove(t, p->s, p->len+1);
4204afe124fSDavid du Colombier 		free(p->s);
4214afe124fSDavid du Colombier 		p->s = t;
4224afe124fSDavid du Colombier 		p->alen = a;
4237dd7cddfSDavid du Colombier 	}
4244afe124fSDavid du Colombier 	/* don't insert extra slash if one is present */
4254afe124fSDavid du Colombier 	if(p->len>0 && p->s[p->len-1]!='/' && s[0]!='/')
4264afe124fSDavid du Colombier 		p->s[p->len++] = '/';
4274afe124fSDavid du Colombier 	memmove(p->s+p->len, s, i+1);
4284afe124fSDavid du Colombier 	p->len += i;
4294afe124fSDavid du Colombier 	if(isdotdot(s)){
4304afe124fSDavid du Colombier 		fixdotdotname(p);
4314afe124fSDavid du Colombier 		DBG("addelem %s .. => rm %p\n", p->s, p->mtpt[p->mlen-1]);
4321fa40b8eSDavid du Colombier 		if(p->mlen>1 && (c = p->mtpt[--p->mlen])){
4334afe124fSDavid du Colombier 			p->mtpt[p->mlen] = nil;
4344afe124fSDavid du Colombier 			cclose(c);
4354afe124fSDavid du Colombier 		}
4364afe124fSDavid du Colombier 	}else{
4374afe124fSDavid du Colombier 		if(p->mlen >= p->malen){
4384afe124fSDavid du Colombier 			p->malen = p->mlen+1+PATHMSLOP;
4394afe124fSDavid du Colombier 			tt = smalloc(p->malen*sizeof tt[0]);
4404afe124fSDavid du Colombier 			memmove(tt, p->mtpt, p->mlen*sizeof tt[0]);
4414afe124fSDavid du Colombier 			free(p->mtpt);
4424afe124fSDavid du Colombier 			p->mtpt = tt;
4434afe124fSDavid du Colombier 		}
4444afe124fSDavid du Colombier 		DBG("addelem %s %s => add %p\n", p->s, s, from);
4454afe124fSDavid du Colombier 		p->mtpt[p->mlen++] = from;
4464afe124fSDavid du Colombier 		if(from)
4474afe124fSDavid du Colombier 			incref(from);
4484afe124fSDavid du Colombier 	}
4494afe124fSDavid du Colombier 	return p;
4507dd7cddfSDavid du Colombier }
4517dd7cddfSDavid du Colombier 
4523e12c5d1SDavid du Colombier void
chanfree(Chan * c)4533e12c5d1SDavid du Colombier chanfree(Chan *c)
4543e12c5d1SDavid du Colombier {
4553e12c5d1SDavid du Colombier 	c->flag = CFREE;
4567dd7cddfSDavid du Colombier 
457dc5a79c1SDavid du Colombier 	if(c->dirrock != nil){
458dc5a79c1SDavid du Colombier 		free(c->dirrock);
459dc5a79c1SDavid du Colombier 		c->dirrock = 0;
460dc5a79c1SDavid du Colombier 		c->nrock = 0;
461dc5a79c1SDavid du Colombier 		c->mrock = 0;
462dc5a79c1SDavid du Colombier 	}
4639a747e4fSDavid du Colombier 	if(c->umh != nil){
4649a747e4fSDavid du Colombier 		putmhead(c->umh);
4659a747e4fSDavid du Colombier 		c->umh = nil;
466219b2ee8SDavid du Colombier 	}
4679a747e4fSDavid du Colombier 	if(c->umc != nil){
4689a747e4fSDavid du Colombier 		cclose(c->umc);
4699a747e4fSDavid du Colombier 		c->umc = nil;
4709a747e4fSDavid du Colombier 	}
4719a747e4fSDavid du Colombier 	if(c->mux != nil){
4729a747e4fSDavid du Colombier 		muxclose(c->mux);
4739a747e4fSDavid du Colombier 		c->mux = nil;
4749a747e4fSDavid du Colombier 	}
4759a747e4fSDavid du Colombier 	if(c->mchan != nil){
4769a747e4fSDavid du Colombier 		cclose(c->mchan);
4779a747e4fSDavid du Colombier 		c->mchan = nil;
4787dd7cddfSDavid du Colombier 	}
4797dd7cddfSDavid du Colombier 
4804afe124fSDavid du Colombier 	pathclose(c->path);
4814afe124fSDavid du Colombier 	c->path = nil;
4827dd7cddfSDavid du Colombier 
4833e12c5d1SDavid du Colombier 	lock(&chanalloc);
4843e12c5d1SDavid du Colombier 	c->next = chanalloc.free;
4853e12c5d1SDavid du Colombier 	chanalloc.free = c;
4863e12c5d1SDavid du Colombier 	unlock(&chanalloc);
4873e12c5d1SDavid du Colombier }
4883e12c5d1SDavid du Colombier 
4893e12c5d1SDavid du Colombier void
cclose(Chan * c)4907dd7cddfSDavid du Colombier cclose(Chan *c)
4913e12c5d1SDavid du Colombier {
4923e12c5d1SDavid du Colombier 	if(c->flag&CFREE)
493567483c8SDavid du Colombier 		panic("cclose %#p", getcallerpc(&c));
4949a747e4fSDavid du Colombier 
4954afe124fSDavid du Colombier 	DBG("cclose %p name=%s ref=%ld\n", c, c->path->s, c->ref);
4967dd7cddfSDavid du Colombier 	if(decref(c))
4977dd7cddfSDavid du Colombier 		return;
4983e12c5d1SDavid du Colombier 
4993e12c5d1SDavid du Colombier 	if(!waserror()){
5007dd7cddfSDavid du Colombier 		devtab[c->type]->close(c);
5013e12c5d1SDavid du Colombier 		poperror();
5023e12c5d1SDavid du Colombier 	}
5033e12c5d1SDavid du Colombier 	chanfree(c);
5043e12c5d1SDavid du Colombier }
5053e12c5d1SDavid du Colombier 
5069a747e4fSDavid du Colombier /*
5072cca75a1SDavid du Colombier  * Queue a chan to be closed by one of the clunk procs.
5082cca75a1SDavid du Colombier  */
5092cca75a1SDavid du Colombier struct {
5102cca75a1SDavid du Colombier 	Chan *head;
5112cca75a1SDavid du Colombier 	Chan *tail;
5122cca75a1SDavid du Colombier 	int nqueued;
5132cca75a1SDavid du Colombier 	int nclosed;
5142cca75a1SDavid du Colombier 	Lock l;
5152cca75a1SDavid du Colombier 	QLock q;
5162cca75a1SDavid du Colombier 	Rendez r;
5172cca75a1SDavid du Colombier } clunkq;
5182cca75a1SDavid du Colombier void closeproc(void*);
5192cca75a1SDavid du Colombier 
5202cca75a1SDavid du Colombier void
ccloseq(Chan * c)5212cca75a1SDavid du Colombier ccloseq(Chan *c)
5222cca75a1SDavid du Colombier {
5232cca75a1SDavid du Colombier 	if(c->flag&CFREE)
524567483c8SDavid du Colombier 		panic("cclose %#p", getcallerpc(&c));
5252cca75a1SDavid du Colombier 
5262cca75a1SDavid du Colombier 	DBG("ccloseq %p name=%s ref=%ld\n", c, c->path->s, c->ref);
5272cca75a1SDavid du Colombier 
5282cca75a1SDavid du Colombier 	if(decref(c))
5292cca75a1SDavid du Colombier 		return;
5302cca75a1SDavid du Colombier 
5312cca75a1SDavid du Colombier 	lock(&clunkq.l);
5322cca75a1SDavid du Colombier 	clunkq.nqueued++;
5332cca75a1SDavid du Colombier 	c->next = nil;
5342cca75a1SDavid du Colombier 	if(clunkq.head)
5352cca75a1SDavid du Colombier 		clunkq.tail->next = c;
5362cca75a1SDavid du Colombier 	else
5372cca75a1SDavid du Colombier 		clunkq.head = c;
5382cca75a1SDavid du Colombier 	clunkq.tail = c;
5392cca75a1SDavid du Colombier 	unlock(&clunkq.l);
5402cca75a1SDavid du Colombier 
5412cca75a1SDavid du Colombier 	if(!wakeup(&clunkq.r))
5422cca75a1SDavid du Colombier 		kproc("closeproc", closeproc, nil);
5432cca75a1SDavid du Colombier }
5442cca75a1SDavid du Colombier 
5452cca75a1SDavid du Colombier static int
clunkwork(void *)5462cca75a1SDavid du Colombier clunkwork(void*)
5472cca75a1SDavid du Colombier {
5482cca75a1SDavid du Colombier 	return clunkq.head != nil;
5492cca75a1SDavid du Colombier }
5502cca75a1SDavid du Colombier 
5512cca75a1SDavid du Colombier void
closeproc(void *)5522cca75a1SDavid du Colombier closeproc(void*)
5532cca75a1SDavid du Colombier {
5542cca75a1SDavid du Colombier 	Chan *c;
5552cca75a1SDavid du Colombier 
5562cca75a1SDavid du Colombier 	for(;;){
5572cca75a1SDavid du Colombier 		qlock(&clunkq.q);
5582cca75a1SDavid du Colombier 		if(clunkq.head == nil){
5592cca75a1SDavid du Colombier 			if(!waserror()){
5602cca75a1SDavid du Colombier 				tsleep(&clunkq.r, clunkwork, nil, 5000);
5612cca75a1SDavid du Colombier 				poperror();
5622cca75a1SDavid du Colombier 			}
5632cca75a1SDavid du Colombier 			if(clunkq.head == nil){
5642cca75a1SDavid du Colombier 				qunlock(&clunkq.q);
5652cca75a1SDavid du Colombier 				pexit("no work", 1);
5662cca75a1SDavid du Colombier 			}
5672cca75a1SDavid du Colombier 		}
5682cca75a1SDavid du Colombier 		lock(&clunkq.l);
5692cca75a1SDavid du Colombier 		c = clunkq.head;
5702cca75a1SDavid du Colombier 		clunkq.head = c->next;
5712cca75a1SDavid du Colombier 		clunkq.nclosed++;
5722cca75a1SDavid du Colombier 		unlock(&clunkq.l);
5732cca75a1SDavid du Colombier 		qunlock(&clunkq.q);
5742cca75a1SDavid du Colombier 		if(!waserror()){
5752cca75a1SDavid du Colombier 			devtab[c->type]->close(c);
5762cca75a1SDavid du Colombier 			poperror();
5772cca75a1SDavid du Colombier 		}
5782cca75a1SDavid du Colombier 		chanfree(c);
5792cca75a1SDavid du Colombier 	}
5802cca75a1SDavid du Colombier }
5812cca75a1SDavid du Colombier 
5822cca75a1SDavid du Colombier /*
5839a747e4fSDavid du Colombier  * Make sure we have the only copy of c.  (Copy on write.)
5849a747e4fSDavid du Colombier  */
5859a747e4fSDavid du Colombier Chan*
cunique(Chan * c)5869a747e4fSDavid du Colombier cunique(Chan *c)
5879a747e4fSDavid du Colombier {
5889a747e4fSDavid du Colombier 	Chan *nc;
5899a747e4fSDavid du Colombier 
5909a747e4fSDavid du Colombier 	if(c->ref != 1){
5919a747e4fSDavid du Colombier 		nc = cclone(c);
5929a747e4fSDavid du Colombier 		cclose(c);
5939a747e4fSDavid du Colombier 		c = nc;
5949a747e4fSDavid du Colombier 	}
5959a747e4fSDavid du Colombier 
5969a747e4fSDavid du Colombier 	return c;
5979a747e4fSDavid du Colombier }
5989a747e4fSDavid du Colombier 
5993e12c5d1SDavid du Colombier int
eqqid(Qid a,Qid b)6003e12c5d1SDavid du Colombier eqqid(Qid a, Qid b)
6013e12c5d1SDavid du Colombier {
6023e12c5d1SDavid du Colombier 	return a.path==b.path && a.vers==b.vers;
6033e12c5d1SDavid du Colombier }
6043e12c5d1SDavid du Colombier 
6053e12c5d1SDavid du Colombier int
eqchan(Chan * a,Chan * b,int skipvers)6064afe124fSDavid du Colombier eqchan(Chan *a, Chan *b, int skipvers)
6073e12c5d1SDavid du Colombier {
6083e12c5d1SDavid du Colombier 	if(a->qid.path != b->qid.path)
6093e12c5d1SDavid du Colombier 		return 0;
6104afe124fSDavid du Colombier 	if(!skipvers && a->qid.vers!=b->qid.vers)
6113e12c5d1SDavid du Colombier 		return 0;
6123e12c5d1SDavid du Colombier 	if(a->type != b->type)
6133e12c5d1SDavid du Colombier 		return 0;
6143e12c5d1SDavid du Colombier 	if(a->dev != b->dev)
6153e12c5d1SDavid du Colombier 		return 0;
6163e12c5d1SDavid du Colombier 	return 1;
6173e12c5d1SDavid du Colombier }
6183e12c5d1SDavid du Colombier 
6193e12c5d1SDavid du Colombier int
eqchantdqid(Chan * a,int type,int dev,Qid qid,int skipvers)6204afe124fSDavid du Colombier eqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers)
6219a747e4fSDavid du Colombier {
6229a747e4fSDavid du Colombier 	if(a->qid.path != qid.path)
6239a747e4fSDavid du Colombier 		return 0;
6244afe124fSDavid du Colombier 	if(!skipvers && a->qid.vers!=qid.vers)
6259a747e4fSDavid du Colombier 		return 0;
6269a747e4fSDavid du Colombier 	if(a->type != type)
6279a747e4fSDavid du Colombier 		return 0;
6289a747e4fSDavid du Colombier 	if(a->dev != dev)
6299a747e4fSDavid du Colombier 		return 0;
6309a747e4fSDavid du Colombier 	return 1;
6319a747e4fSDavid du Colombier }
6329a747e4fSDavid du Colombier 
6333ff48bf5SDavid du Colombier Mhead*
newmhead(Chan * from)6343ff48bf5SDavid du Colombier newmhead(Chan *from)
6353ff48bf5SDavid du Colombier {
6363ff48bf5SDavid du Colombier 	Mhead *mh;
6373ff48bf5SDavid du Colombier 
6383ff48bf5SDavid du Colombier 	mh = smalloc(sizeof(Mhead));
6393ff48bf5SDavid du Colombier 	mh->ref = 1;
6403ff48bf5SDavid du Colombier 	mh->from = from;
6413ff48bf5SDavid du Colombier 	incref(from);
6423ff48bf5SDavid du Colombier 	return mh;
6433ff48bf5SDavid du Colombier }
6443ff48bf5SDavid du Colombier 
6459a747e4fSDavid du Colombier int
cmount(Chan ** newp,Chan * old,int flag,char * spec)6469a747e4fSDavid du Colombier cmount(Chan **newp, Chan *old, int flag, char *spec)
6473e12c5d1SDavid du Colombier {
6487dd7cddfSDavid du Colombier 	int order, flg;
6494afe124fSDavid du Colombier 	Chan *new;
6509a747e4fSDavid du Colombier 	Mhead *m, **l, *mh;
6517dd7cddfSDavid du Colombier 	Mount *nm, *f, *um, **h;
6524afe124fSDavid du Colombier 	Pgrp *pg;
6533e12c5d1SDavid du Colombier 
6549a747e4fSDavid du Colombier 	if(QTDIR & (old->qid.type^(*newp)->qid.type))
6553e12c5d1SDavid du Colombier 		error(Emount);
6563e12c5d1SDavid du Colombier 
6574afe124fSDavid du Colombier 	if(old->umh)
658567483c8SDavid du Colombier 		print("cmount: unexpected umh, caller %#p\n", getcallerpc(&newp));
6599a747e4fSDavid du Colombier 
6603e12c5d1SDavid du Colombier 	order = flag&MORDER;
6613e12c5d1SDavid du Colombier 
6629a747e4fSDavid du Colombier 	if((old->qid.type&QTDIR)==0 && order != MREPL)
6639a747e4fSDavid du Colombier 		error(Emount);
6649a747e4fSDavid du Colombier 
6659a747e4fSDavid du Colombier 	new = *newp;
6669a747e4fSDavid du Colombier 	mh = new->umh;
6679a747e4fSDavid du Colombier 
6689a747e4fSDavid du Colombier 	/*
6694afe124fSDavid du Colombier 	 * Not allowed to bind when the old directory is itself a union.
6704afe124fSDavid du Colombier 	 * (Maybe it should be allowed, but I don't see what the semantics
6714afe124fSDavid du Colombier 	 * would be.)
6729a747e4fSDavid du Colombier 	 *
6739a747e4fSDavid du Colombier 	 * We need to check mh->mount->next to tell unions apart from
6749a747e4fSDavid du Colombier 	 * simple mount points, so that things like
6759a747e4fSDavid du Colombier 	 *	mount -c fd /root
6769a747e4fSDavid du Colombier 	 *	bind -c /root /
6774afe124fSDavid du Colombier 	 * work.
6784afe124fSDavid du Colombier 	 *
6794afe124fSDavid du Colombier 	 * The check of mount->mflag allows things like
6809a747e4fSDavid du Colombier 	 *	mount fd /root
6819a747e4fSDavid du Colombier 	 *	bind -c /root /
6829a747e4fSDavid du Colombier 	 *
6839a747e4fSDavid du Colombier 	 * This is far more complicated than it should be, but I don't
6844afe124fSDavid du Colombier 	 * see an easier way at the moment.
6859a747e4fSDavid du Colombier 	 */
6869a747e4fSDavid du Colombier 	if((flag&MCREATE) && mh && mh->mount
6879a747e4fSDavid du Colombier 	&& (mh->mount->next || !(mh->mount->mflag&MCREATE)))
6883e12c5d1SDavid du Colombier 		error(Emount);
6893e12c5d1SDavid du Colombier 
6907dd7cddfSDavid du Colombier 	pg = up->pgrp;
6913e12c5d1SDavid du Colombier 	wlock(&pg->ns);
6923e12c5d1SDavid du Colombier 
6939a747e4fSDavid du Colombier 	l = &MOUNTH(pg, old->qid);
6943e12c5d1SDavid du Colombier 	for(m = *l; m; m = m->hash){
6953e12c5d1SDavid du Colombier 		if(eqchan(m->from, old, 1))
6963e12c5d1SDavid du Colombier 			break;
6973e12c5d1SDavid du Colombier 		l = &m->hash;
6983e12c5d1SDavid du Colombier 	}
6993e12c5d1SDavid du Colombier 
7009a747e4fSDavid du Colombier 	if(m == nil){
7017dd7cddfSDavid du Colombier 		/*
7027dd7cddfSDavid du Colombier 		 *  nothing mounted here yet.  create a mount
7037dd7cddfSDavid du Colombier 		 *  head and add to the hash table.
7047dd7cddfSDavid du Colombier 		 */
7053ff48bf5SDavid du Colombier 		m = newmhead(old);
7063e12c5d1SDavid du Colombier 		*l = m;
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier 		/*
7097dd7cddfSDavid du Colombier 		 *  if this is a union mount, add the old
7107dd7cddfSDavid du Colombier 		 *  node to the mount chain.
7117dd7cddfSDavid du Colombier 		 */
7123e12c5d1SDavid du Colombier 		if(order != MREPL)
7137dd7cddfSDavid du Colombier 			m->mount = newmount(m, old, 0, 0);
7147dd7cddfSDavid du Colombier 	}
7157dd7cddfSDavid du Colombier 	wlock(&m->lock);
7167dd7cddfSDavid du Colombier 	if(waserror()){
7177dd7cddfSDavid du Colombier 		wunlock(&m->lock);
7187dd7cddfSDavid du Colombier 		nexterror();
7197dd7cddfSDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 	wunlock(&pg->ns);
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier 	nm = newmount(m, new, flag, spec);
7239a747e4fSDavid du Colombier 	if(mh != nil && mh->mount != nil){
7247dd7cddfSDavid du Colombier 		/*
7257dd7cddfSDavid du Colombier 		 *  copy a union when binding it onto a directory
7267dd7cddfSDavid du Colombier 		 */
7277dd7cddfSDavid du Colombier 		flg = order;
7287dd7cddfSDavid du Colombier 		if(order == MREPL)
7297dd7cddfSDavid du Colombier 			flg = MAFTER;
7307dd7cddfSDavid du Colombier 		h = &nm->next;
7319a747e4fSDavid du Colombier 		um = mh->mount;
7327dd7cddfSDavid du Colombier 		for(um = um->next; um; um = um->next){
7337dd7cddfSDavid du Colombier 			f = newmount(m, um->to, flg, um->spec);
7347dd7cddfSDavid du Colombier 			*h = f;
7357dd7cddfSDavid du Colombier 			h = &f->next;
7367dd7cddfSDavid du Colombier 		}
7373e12c5d1SDavid du Colombier 	}
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier 	if(m->mount && order == MREPL){
7403e12c5d1SDavid du Colombier 		mountfree(m->mount);
7413e12c5d1SDavid du Colombier 		m->mount = 0;
7423e12c5d1SDavid du Colombier 	}
7433e12c5d1SDavid du Colombier 
7443e12c5d1SDavid du Colombier 	if(flag & MCREATE)
7459a747e4fSDavid du Colombier 		nm->mflag |= MCREATE;
7463e12c5d1SDavid du Colombier 
7473e12c5d1SDavid du Colombier 	if(m->mount && order == MAFTER){
7483e12c5d1SDavid du Colombier 		for(f = m->mount; f->next; f = f->next)
7493e12c5d1SDavid du Colombier 			;
7503e12c5d1SDavid du Colombier 		f->next = nm;
7514afe124fSDavid du Colombier 	}else{
7527dd7cddfSDavid du Colombier 		for(f = nm; f->next; f = f->next)
7537dd7cddfSDavid du Colombier 			;
7547dd7cddfSDavid du Colombier 		f->next = m->mount;
7553e12c5d1SDavid du Colombier 		m->mount = nm;
7563e12c5d1SDavid du Colombier 	}
7573e12c5d1SDavid du Colombier 
7587dd7cddfSDavid du Colombier 	wunlock(&m->lock);
7593e12c5d1SDavid du Colombier 	poperror();
7603e12c5d1SDavid du Colombier 	return nm->mountid;
7613e12c5d1SDavid du Colombier }
7623e12c5d1SDavid du Colombier 
7633e12c5d1SDavid du Colombier void
cunmount(Chan * mnt,Chan * mounted)7647dd7cddfSDavid du Colombier cunmount(Chan *mnt, Chan *mounted)
7653e12c5d1SDavid du Colombier {
7663e12c5d1SDavid du Colombier 	Pgrp *pg;
7673e12c5d1SDavid du Colombier 	Mhead *m, **l;
7683e12c5d1SDavid du Colombier 	Mount *f, **p;
7693e12c5d1SDavid du Colombier 
7709a747e4fSDavid du Colombier 	if(mnt->umh)	/* should not happen */
7719a747e4fSDavid du Colombier 		print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
7729a747e4fSDavid du Colombier 
7739a747e4fSDavid du Colombier 	/*
7749a747e4fSDavid du Colombier 	 * It _can_ happen that mounted->umh is non-nil,
7759a747e4fSDavid du Colombier 	 * because mounted is the result of namec(Aopen)
7769a747e4fSDavid du Colombier 	 * (see sysfile.c:/^sysunmount).
7779a747e4fSDavid du Colombier 	 * If we open a union directory, it will have a umh.
7789a747e4fSDavid du Colombier 	 * Although surprising, this is okay, since the
7799a747e4fSDavid du Colombier 	 * cclose will take care of freeing the umh.
7809a747e4fSDavid du Colombier 	 */
7819a747e4fSDavid du Colombier 
7827dd7cddfSDavid du Colombier 	pg = up->pgrp;
7833e12c5d1SDavid du Colombier 	wlock(&pg->ns);
7843e12c5d1SDavid du Colombier 
7859a747e4fSDavid du Colombier 	l = &MOUNTH(pg, mnt->qid);
7863e12c5d1SDavid du Colombier 	for(m = *l; m; m = m->hash){
7873e12c5d1SDavid du Colombier 		if(eqchan(m->from, mnt, 1))
7883e12c5d1SDavid du Colombier 			break;
7893e12c5d1SDavid du Colombier 		l = &m->hash;
7903e12c5d1SDavid du Colombier 	}
7913e12c5d1SDavid du Colombier 
7923e12c5d1SDavid du Colombier 	if(m == 0){
7933e12c5d1SDavid du Colombier 		wunlock(&pg->ns);
7943e12c5d1SDavid du Colombier 		error(Eunmount);
7953e12c5d1SDavid du Colombier 	}
7963e12c5d1SDavid du Colombier 
7977dd7cddfSDavid du Colombier 	wlock(&m->lock);
7983e12c5d1SDavid du Colombier 	if(mounted == 0){
7993e12c5d1SDavid du Colombier 		*l = m->hash;
8003e12c5d1SDavid du Colombier 		wunlock(&pg->ns);
8013e12c5d1SDavid du Colombier 		mountfree(m->mount);
8027dd7cddfSDavid du Colombier 		m->mount = nil;
8037dd7cddfSDavid du Colombier 		cclose(m->from);
8047dd7cddfSDavid du Colombier 		wunlock(&m->lock);
8057dd7cddfSDavid du Colombier 		putmhead(m);
8063e12c5d1SDavid du Colombier 		return;
8073e12c5d1SDavid du Colombier 	}
8083e12c5d1SDavid du Colombier 
8093e12c5d1SDavid du Colombier 	p = &m->mount;
8103e12c5d1SDavid du Colombier 	for(f = *p; f; f = f->next){
8117dd7cddfSDavid du Colombier 		/* BUG: Needs to be 2 pass */
8127dd7cddfSDavid du Colombier 		if(eqchan(f->to, mounted, 1) ||
8137dd7cddfSDavid du Colombier 		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))){
8143e12c5d1SDavid du Colombier 			*p = f->next;
8153e12c5d1SDavid du Colombier 			f->next = 0;
8163e12c5d1SDavid du Colombier 			mountfree(f);
8177dd7cddfSDavid du Colombier 			if(m->mount == nil){
8183e12c5d1SDavid du Colombier 				*l = m->hash;
8197dd7cddfSDavid du Colombier 				cclose(m->from);
8207dd7cddfSDavid du Colombier 				wunlock(&m->lock);
8213ff48bf5SDavid du Colombier 				wunlock(&pg->ns);
8227dd7cddfSDavid du Colombier 				putmhead(m);
8233e12c5d1SDavid du Colombier 				return;
8243e12c5d1SDavid du Colombier 			}
8257dd7cddfSDavid du Colombier 			wunlock(&m->lock);
8263ff48bf5SDavid du Colombier 			wunlock(&pg->ns);
8273e12c5d1SDavid du Colombier 			return;
8283e12c5d1SDavid du Colombier 		}
8293e12c5d1SDavid du Colombier 		p = &f->next;
8303e12c5d1SDavid du Colombier 	}
8317dd7cddfSDavid du Colombier 	wunlock(&m->lock);
8323ff48bf5SDavid du Colombier 	wunlock(&pg->ns);
8333e12c5d1SDavid du Colombier 	error(Eunion);
8343e12c5d1SDavid du Colombier }
8353e12c5d1SDavid du Colombier 
8363e12c5d1SDavid du Colombier Chan*
cclone(Chan * c)8379a747e4fSDavid du Colombier cclone(Chan *c)
8383e12c5d1SDavid du Colombier {
8399a747e4fSDavid du Colombier 	Chan *nc;
8409a747e4fSDavid du Colombier 	Walkqid *wq;
8419a747e4fSDavid du Colombier 
8429a747e4fSDavid du Colombier 	wq = devtab[c->type]->walk(c, nil, nil, 0);
8439a747e4fSDavid du Colombier 	if(wq == nil)
8449a747e4fSDavid du Colombier 		error("clone failed");
8459a747e4fSDavid du Colombier 	nc = wq->clone;
8469a747e4fSDavid du Colombier 	free(wq);
8474afe124fSDavid du Colombier 	nc->path = c->path;
8484afe124fSDavid du Colombier 	if(c->path)
8494afe124fSDavid du Colombier 		incref(c->path);
8507dd7cddfSDavid du Colombier 	return nc;
8513e12c5d1SDavid du Colombier }
8523e12c5d1SDavid du Colombier 
8534afe124fSDavid du Colombier /* also used by sysfile.c:/^mountfix */
8549a747e4fSDavid du Colombier int
findmount(Chan ** cp,Mhead ** mp,int type,int dev,Qid qid)8559a747e4fSDavid du Colombier findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
8563e12c5d1SDavid du Colombier {
8573e12c5d1SDavid du Colombier 	Pgrp *pg;
8583e12c5d1SDavid du Colombier 	Mhead *m;
8593e12c5d1SDavid du Colombier 
8607dd7cddfSDavid du Colombier 	pg = up->pgrp;
8613e12c5d1SDavid du Colombier 	rlock(&pg->ns);
8629a747e4fSDavid du Colombier 	for(m = MOUNTH(pg, qid); m; m = m->hash){
8637dd7cddfSDavid du Colombier 		rlock(&m->lock);
8649a747e4fSDavid du Colombier 		if(m->from == nil){
8659a747e4fSDavid du Colombier 			print("m %p m->from 0\n", m);
8667dd7cddfSDavid du Colombier 			runlock(&m->lock);
8679a747e4fSDavid du Colombier 			continue;
8683e12c5d1SDavid du Colombier 		}
8699a747e4fSDavid du Colombier 		if(eqchantdqid(m->from, type, dev, qid, 1)){
8707dd7cddfSDavid du Colombier 			runlock(&pg->ns);
8719a747e4fSDavid du Colombier 			if(mp != nil){
8727dd7cddfSDavid du Colombier 				incref(m);
8739a747e4fSDavid du Colombier 				if(*mp != nil)
8749a747e4fSDavid du Colombier 					putmhead(*mp);
8759a747e4fSDavid du Colombier 				*mp = m;
8769a747e4fSDavid du Colombier 			}
8779a747e4fSDavid du Colombier 			if(*cp != nil)
8789a747e4fSDavid du Colombier 				cclose(*cp);
8799a747e4fSDavid du Colombier 			incref(m->mount->to);
8809a747e4fSDavid du Colombier 			*cp = m->mount->to;
8817dd7cddfSDavid du Colombier 			runlock(&m->lock);
8829a747e4fSDavid du Colombier 			return 1;
8837dd7cddfSDavid du Colombier 		}
8847dd7cddfSDavid du Colombier 		runlock(&m->lock);
8853e12c5d1SDavid du Colombier 	}
8863e12c5d1SDavid du Colombier 
8873e12c5d1SDavid du Colombier 	runlock(&pg->ns);
8889a747e4fSDavid du Colombier 	return 0;
8899a747e4fSDavid du Colombier }
8909a747e4fSDavid du Colombier 
8914afe124fSDavid du Colombier /*
8924afe124fSDavid du Colombier  * Calls findmount but also updates path.
8934afe124fSDavid du Colombier  */
8944afe124fSDavid du Colombier static int
domount(Chan ** cp,Mhead ** mp,Path ** path)8954afe124fSDavid du Colombier domount(Chan **cp, Mhead **mp, Path **path)
8969a747e4fSDavid du Colombier {
8974afe124fSDavid du Colombier 	Chan **lc;
8984afe124fSDavid du Colombier 	Path *p;
8994afe124fSDavid du Colombier 
9004afe124fSDavid du Colombier 	if(findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid) == 0)
9014afe124fSDavid du Colombier 		return 0;
9024afe124fSDavid du Colombier 
9034afe124fSDavid du Colombier 	if(path){
9044afe124fSDavid du Colombier 		p = *path;
9054afe124fSDavid du Colombier 		p = uniquepath(p);
9064afe124fSDavid du Colombier 		if(p->mlen <= 0)
9074afe124fSDavid du Colombier 			print("domount: path %s has mlen==%d\n", p->s, p->mlen);
9084afe124fSDavid du Colombier 		else{
9094afe124fSDavid du Colombier 			lc = &p->mtpt[p->mlen-1];
9104afe124fSDavid du Colombier DBG("domount %p %s => add %p (was %p)\n", p, p->s, (*mp)->from, p->mtpt[p->mlen-1]);
9114afe124fSDavid du Colombier 			incref((*mp)->from);
9124afe124fSDavid du Colombier 			if(*lc)
9134afe124fSDavid du Colombier 				cclose(*lc);
9144afe124fSDavid du Colombier 			*lc = (*mp)->from;
9154afe124fSDavid du Colombier 		}
9164afe124fSDavid du Colombier 		*path = p;
9174afe124fSDavid du Colombier 	}
9184afe124fSDavid du Colombier 	return 1;
9193e12c5d1SDavid du Colombier }
9203e12c5d1SDavid du Colombier 
9214afe124fSDavid du Colombier /*
9224afe124fSDavid du Colombier  * If c is the right-hand-side of a mount point, returns the left hand side.
9234afe124fSDavid du Colombier  * Changes name to reflect the fact that we've uncrossed the mountpoint,
9244afe124fSDavid du Colombier  * so name had better be ours to change!
9254afe124fSDavid du Colombier  */
9264afe124fSDavid du Colombier static Chan*
undomount(Chan * c,Path * path)9274afe124fSDavid du Colombier undomount(Chan *c, Path *path)
9283e12c5d1SDavid du Colombier {
9297dd7cddfSDavid du Colombier 	Chan *nc;
9303e12c5d1SDavid du Colombier 
9314afe124fSDavid du Colombier 	if(path->ref != 1 || path->mlen == 0)
932567483c8SDavid du Colombier 		print("undomount: path %s ref %ld mlen %d caller %#p\n",
9334afe124fSDavid du Colombier 			path->s, path->ref, path->mlen, getcallerpc(&c));
9343e12c5d1SDavid du Colombier 
9354afe124fSDavid du Colombier 	if(path->mlen>0 && (nc=path->mtpt[path->mlen-1]) != nil){
9364afe124fSDavid du Colombier DBG("undomount %p %s => remove %p\n", path, path->s, nc);
9377dd7cddfSDavid du Colombier 		cclose(c);
9384afe124fSDavid du Colombier 		path->mtpt[path->mlen-1] = nil;
9397dd7cddfSDavid du Colombier 		c = nc;
9403e12c5d1SDavid du Colombier 	}
9413e12c5d1SDavid du Colombier 	return c;
9423e12c5d1SDavid du Colombier }
9433e12c5d1SDavid du Colombier 
9449a747e4fSDavid du Colombier /*
9454afe124fSDavid du Colombier  * Call dev walk but catch errors.
9468b6d9ba0SDavid du Colombier  */
9478b6d9ba0SDavid du Colombier static Walkqid*
ewalk(Chan * c,Chan * nc,char ** name,int nname)9488b6d9ba0SDavid du Colombier ewalk(Chan *c, Chan *nc, char **name, int nname)
9498b6d9ba0SDavid du Colombier {
9508b6d9ba0SDavid du Colombier 	Walkqid *wq;
9518b6d9ba0SDavid du Colombier 
9528b6d9ba0SDavid du Colombier 	if(waserror())
9538b6d9ba0SDavid du Colombier 		return nil;
9548b6d9ba0SDavid du Colombier 	wq = devtab[c->type]->walk(c, nc, name, nname);
9558b6d9ba0SDavid du Colombier 	poperror();
9568b6d9ba0SDavid du Colombier 	return wq;
9578b6d9ba0SDavid du Colombier }
9588b6d9ba0SDavid du Colombier 
9598b6d9ba0SDavid du Colombier /*
9609a747e4fSDavid du Colombier  * Either walks all the way or not at all.  No partial results in *cp.
9619a747e4fSDavid du Colombier  * *nerror is the number of names to display in an error message.
9629a747e4fSDavid du Colombier  */
9639a747e4fSDavid du Colombier static char Edoesnotexist[] = "does not exist";
9647dd7cddfSDavid du Colombier int
walk(Chan ** cp,char ** names,int nnames,int nomount,int * nerror)9659a747e4fSDavid du Colombier walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
9667dd7cddfSDavid du Colombier {
967c716ae23SDavid du Colombier 	int dev, didmount, dotdot, i, n, nhave, ntry, type;
9684afe124fSDavid du Colombier 	Chan *c, *nc, *mtpt;
9694afe124fSDavid du Colombier 	Path *path;
9709a747e4fSDavid du Colombier 	Mhead *mh, *nmh;
9714afe124fSDavid du Colombier 	Mount *f;
9729a747e4fSDavid du Colombier 	Walkqid *wq;
9733e12c5d1SDavid du Colombier 
9749a747e4fSDavid du Colombier 	c = *cp;
9759a747e4fSDavid du Colombier 	incref(c);
9764afe124fSDavid du Colombier 	path = c->path;
9774afe124fSDavid du Colombier 	incref(path);
9789a747e4fSDavid du Colombier 	mh = nil;
9797dd7cddfSDavid du Colombier 
9809a747e4fSDavid du Colombier 	/*
9819a747e4fSDavid du Colombier 	 * While we haven't gotten all the way down the path:
9829a747e4fSDavid du Colombier 	 *    1. step through a mount point, if any
9839a747e4fSDavid du Colombier 	 *    2. send a walk request for initial dotdot or initial prefix without dotdot
9849a747e4fSDavid du Colombier 	 *    3. move to the first mountpoint along the way.
9859a747e4fSDavid du Colombier 	 *    4. repeat.
9869a747e4fSDavid du Colombier 	 *
987c716ae23SDavid du Colombier 	 * Each time through the loop:
988c716ae23SDavid du Colombier 	 *
989c716ae23SDavid du Colombier 	 *	If didmount==0, c is on the undomount side of the mount point.
990c716ae23SDavid du Colombier 	 *	If didmount==1, c is on the domount side of the mount point.
991c716ae23SDavid du Colombier 	 * 	Either way, c's full path is path.
9929a747e4fSDavid du Colombier 	 */
993c716ae23SDavid du Colombier 	didmount = 0;
9949a747e4fSDavid du Colombier 	for(nhave=0; nhave<nnames; nhave+=n){
9959a747e4fSDavid du Colombier 		if((c->qid.type&QTDIR)==0){
9969a747e4fSDavid du Colombier 			if(nerror)
9979a747e4fSDavid du Colombier 				*nerror = nhave;
9984afe124fSDavid du Colombier 			pathclose(path);
9999a747e4fSDavid du Colombier 			cclose(c);
10009a747e4fSDavid du Colombier 			strcpy(up->errstr, Enotdir);
10013ff48bf5SDavid du Colombier 			if(mh != nil)
10023ff48bf5SDavid du Colombier 				putmhead(mh);
10039a747e4fSDavid du Colombier 			return -1;
10049a747e4fSDavid du Colombier 		}
10059a747e4fSDavid du Colombier 		ntry = nnames - nhave;
10069a747e4fSDavid du Colombier 		if(ntry > MAXWELEM)
10079a747e4fSDavid du Colombier 			ntry = MAXWELEM;
10083e12c5d1SDavid du Colombier 		dotdot = 0;
10099a747e4fSDavid du Colombier 		for(i=0; i<ntry; i++){
10109a747e4fSDavid du Colombier 			if(isdotdot(names[nhave+i])){
10119a747e4fSDavid du Colombier 				if(i==0){
10123e12c5d1SDavid du Colombier 					dotdot = 1;
10139a747e4fSDavid du Colombier 					ntry = 1;
10149a747e4fSDavid du Colombier 				}else
10159a747e4fSDavid du Colombier 					ntry = i;
10163e12c5d1SDavid du Colombier 				break;
10179a747e4fSDavid du Colombier 			}
10189a747e4fSDavid du Colombier 		}
10199a747e4fSDavid du Colombier 
1020c716ae23SDavid du Colombier 		if(!dotdot && !nomount && !didmount)
10214afe124fSDavid du Colombier 			domount(&c, &mh, &path);
10229a747e4fSDavid du Colombier 
10239a747e4fSDavid du Colombier 		type = c->type;
10249a747e4fSDavid du Colombier 		dev = c->dev;
10259a747e4fSDavid du Colombier 
10268b6d9ba0SDavid du Colombier 		if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
10279a747e4fSDavid du Colombier 			/* try a union mount, if any */
10289a747e4fSDavid du Colombier 			if(mh && !nomount){
10299a747e4fSDavid du Colombier 				/*
1030dc5a79c1SDavid du Colombier 				 * mh->mount->to == c, so start at mh->mount->next
10319a747e4fSDavid du Colombier 				 */
10329a747e4fSDavid du Colombier 				rlock(&mh->lock);
1033d584e620SDavid du Colombier 				f = mh->mount;
1034d584e620SDavid du Colombier 				for(f = (f? f->next: f); f; f = f->next)
10358b6d9ba0SDavid du Colombier 					if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)
10369a747e4fSDavid du Colombier 						break;
10379a747e4fSDavid du Colombier 				runlock(&mh->lock);
10389a747e4fSDavid du Colombier 				if(f != nil){
10399a747e4fSDavid du Colombier 					type = f->to->type;
10409a747e4fSDavid du Colombier 					dev = f->to->dev;
10419a747e4fSDavid du Colombier 				}
10429a747e4fSDavid du Colombier 			}
10439a747e4fSDavid du Colombier 			if(wq == nil){
10447dd7cddfSDavid du Colombier 				cclose(c);
10454afe124fSDavid du Colombier 				pathclose(path);
10469a747e4fSDavid du Colombier 				if(nerror)
10479a747e4fSDavid du Colombier 					*nerror = nhave+1;
10483ff48bf5SDavid du Colombier 				if(mh != nil)
10493ff48bf5SDavid du Colombier 					putmhead(mh);
10507dd7cddfSDavid du Colombier 				return -1;
10519a747e4fSDavid du Colombier 			}
10523e12c5d1SDavid du Colombier 		}
10537dd7cddfSDavid du Colombier 
1054c716ae23SDavid du Colombier 		didmount = 0;
10559a747e4fSDavid du Colombier 		if(dotdot){
10569a747e4fSDavid du Colombier 			assert(wq->nqid == 1);
10579a747e4fSDavid du Colombier 			assert(wq->clone != nil);
10587dd7cddfSDavid du Colombier 
10594afe124fSDavid du Colombier 			path = addelem(path, "..", nil);
10604afe124fSDavid du Colombier 			nc = undomount(wq->clone, path);
1061c716ae23SDavid du Colombier 			nmh = nil;
10629a747e4fSDavid du Colombier 			n = 1;
10639a747e4fSDavid du Colombier 		}else{
10649a747e4fSDavid du Colombier 			nc = nil;
10654afe124fSDavid du Colombier 			nmh = nil;
1066c716ae23SDavid du Colombier 			if(!nomount){
1067c716ae23SDavid du Colombier 				for(i=0; i<wq->nqid && i<ntry-1; i++){
1068c716ae23SDavid du Colombier 					if(findmount(&nc, &nmh, type, dev, wq->qid[i])){
1069c716ae23SDavid du Colombier 						didmount = 1;
10709a747e4fSDavid du Colombier 						break;
1071c716ae23SDavid du Colombier 					}
1072c716ae23SDavid du Colombier 				}
1073c716ae23SDavid du Colombier 			}
10749a747e4fSDavid du Colombier 			if(nc == nil){	/* no mount points along path */
10759a747e4fSDavid du Colombier 				if(wq->clone == nil){
10769a747e4fSDavid du Colombier 					cclose(c);
10774afe124fSDavid du Colombier 					pathclose(path);
10789a747e4fSDavid du Colombier 					if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
10799a747e4fSDavid du Colombier 						if(nerror)
10809a747e4fSDavid du Colombier 							*nerror = nhave+wq->nqid+1;
10819a747e4fSDavid du Colombier 						strcpy(up->errstr, Edoesnotexist);
10829a747e4fSDavid du Colombier 					}else{
10839a747e4fSDavid du Colombier 						if(nerror)
10849a747e4fSDavid du Colombier 							*nerror = nhave+wq->nqid;
10859a747e4fSDavid du Colombier 						strcpy(up->errstr, Enotdir);
10869a747e4fSDavid du Colombier 					}
10879a747e4fSDavid du Colombier 					free(wq);
10883ff48bf5SDavid du Colombier 					if(mh != nil)
10893ff48bf5SDavid du Colombier 						putmhead(mh);
10909a747e4fSDavid du Colombier 					return -1;
10919a747e4fSDavid du Colombier 				}
10929a747e4fSDavid du Colombier 				n = wq->nqid;
10939a747e4fSDavid du Colombier 				nc = wq->clone;
10949a747e4fSDavid du Colombier 			}else{		/* stopped early, at a mount point */
1095c716ae23SDavid du Colombier 				didmount = 1;
10969a747e4fSDavid du Colombier 				if(wq->clone != nil){
10979a747e4fSDavid du Colombier 					cclose(wq->clone);
10989a747e4fSDavid du Colombier 					wq->clone = nil;
10999a747e4fSDavid du Colombier 				}
11009a747e4fSDavid du Colombier 				n = i+1;
11019a747e4fSDavid du Colombier 			}
11024afe124fSDavid du Colombier 			for(i=0; i<n; i++){
11034afe124fSDavid du Colombier 				mtpt = nil;
11044afe124fSDavid du Colombier 				if(i==n-1 && nmh)
11054afe124fSDavid du Colombier 					mtpt = nmh->from;
11064afe124fSDavid du Colombier 				path = addelem(path, names[nhave+i], mtpt);
11074afe124fSDavid du Colombier 			}
11089a747e4fSDavid du Colombier 		}
11099a747e4fSDavid du Colombier 		cclose(c);
11109a747e4fSDavid du Colombier 		c = nc;
11119a747e4fSDavid du Colombier 		putmhead(mh);
11129a747e4fSDavid du Colombier 		mh = nmh;
11139a747e4fSDavid du Colombier 		free(wq);
11149a747e4fSDavid du Colombier 	}
11159a747e4fSDavid du Colombier 
11169a747e4fSDavid du Colombier 	putmhead(mh);
11179a747e4fSDavid du Colombier 
11189a747e4fSDavid du Colombier 	c = cunique(c);
11199a747e4fSDavid du Colombier 
11209a747e4fSDavid du Colombier 	if(c->umh != nil){	//BUG
11219a747e4fSDavid du Colombier 		print("walk umh\n");
11229a747e4fSDavid du Colombier 		putmhead(c->umh);
11239a747e4fSDavid du Colombier 		c->umh = nil;
11249a747e4fSDavid du Colombier 	}
11259a747e4fSDavid du Colombier 
11264afe124fSDavid du Colombier 	pathclose(c->path);
11274afe124fSDavid du Colombier 	c->path = path;
11289a747e4fSDavid du Colombier 
11299a747e4fSDavid du Colombier 	cclose(*cp);
11309a747e4fSDavid du Colombier 	*cp = c;
11319a747e4fSDavid du Colombier 	if(nerror)
1132312a1df1SDavid du Colombier 		*nerror = nhave;
11337dd7cddfSDavid du Colombier 	return 0;
11343e12c5d1SDavid du Colombier }
11353e12c5d1SDavid du Colombier 
11363e12c5d1SDavid du Colombier /*
11373e12c5d1SDavid du Colombier  * c is a mounted non-creatable directory.  find a creatable one.
11383e12c5d1SDavid du Colombier  */
11393e12c5d1SDavid du Colombier Chan*
createdir(Chan * c,Mhead * m)11409a747e4fSDavid du Colombier createdir(Chan *c, Mhead *m)
11413e12c5d1SDavid du Colombier {
11423e12c5d1SDavid du Colombier 	Chan *nc;
11433e12c5d1SDavid du Colombier 	Mount *f;
11443e12c5d1SDavid du Colombier 
11459a747e4fSDavid du Colombier 	rlock(&m->lock);
11463e12c5d1SDavid du Colombier 	if(waserror()){
11479a747e4fSDavid du Colombier 		runlock(&m->lock);
11483e12c5d1SDavid du Colombier 		nexterror();
11493e12c5d1SDavid du Colombier 	}
11509a747e4fSDavid du Colombier 	for(f = m->mount; f; f = f->next){
11519a747e4fSDavid du Colombier 		if(f->mflag&MCREATE){
11529a747e4fSDavid du Colombier 			nc = cclone(f->to);
11539a747e4fSDavid du Colombier 			runlock(&m->lock);
11543e12c5d1SDavid du Colombier 			poperror();
11557dd7cddfSDavid du Colombier 			cclose(c);
11563e12c5d1SDavid du Colombier 			return nc;
11573e12c5d1SDavid du Colombier 		}
11583e12c5d1SDavid du Colombier 	}
11593e12c5d1SDavid du Colombier 	error(Enocreate);
11607dd7cddfSDavid du Colombier 	return 0;
11613e12c5d1SDavid du Colombier }
11623e12c5d1SDavid du Colombier 
11633e12c5d1SDavid du Colombier void
saveregisters(void)11643e12c5d1SDavid du Colombier saveregisters(void)
11653e12c5d1SDavid du Colombier {
11663e12c5d1SDavid du Colombier }
11673e12c5d1SDavid du Colombier 
11689a747e4fSDavid du Colombier static void
growparse(Elemlist * e)11699a747e4fSDavid du Colombier growparse(Elemlist *e)
11709a747e4fSDavid du Colombier {
11719a747e4fSDavid du Colombier 	char **new;
11729a747e4fSDavid du Colombier 	int *inew;
11739a747e4fSDavid du Colombier 	enum { Delta = 8 };
11749a747e4fSDavid du Colombier 
11759a747e4fSDavid du Colombier 	if(e->nelems % Delta == 0){
11769a747e4fSDavid du Colombier 		new = smalloc((e->nelems+Delta) * sizeof(char*));
11779a747e4fSDavid du Colombier 		memmove(new, e->elems, e->nelems*sizeof(char*));
11789a747e4fSDavid du Colombier 		free(e->elems);
11799a747e4fSDavid du Colombier 		e->elems = new;
11809a747e4fSDavid du Colombier 		inew = smalloc((e->nelems+Delta+1) * sizeof(int));
11818b6d9ba0SDavid du Colombier 		memmove(inew, e->off, (e->nelems+1)*sizeof(int));
11829a747e4fSDavid du Colombier 		free(e->off);
11839a747e4fSDavid du Colombier 		e->off = inew;
11849a747e4fSDavid du Colombier 	}
11859a747e4fSDavid du Colombier }
11869a747e4fSDavid du Colombier 
11879a747e4fSDavid du Colombier /*
11889a747e4fSDavid du Colombier  * The name is known to be valid.
11899a747e4fSDavid du Colombier  * Copy the name so slashes can be overwritten.
11909a747e4fSDavid du Colombier  * An empty string will set nelem=0.
1191fb7f0c93SDavid du Colombier  * A path ending in / or /. or /.//./ etc. will have
1192fb7f0c93SDavid du Colombier  * e.mustbedir = 1, so that we correctly
1193fb7f0c93SDavid du Colombier  * reject, e.g., "/adm/users/." when /adm/users is a file
1194fb7f0c93SDavid du Colombier  * rather than a directory.
11959a747e4fSDavid du Colombier  */
11969a747e4fSDavid du Colombier static void
parsename(char * aname,Elemlist * e)11978b6d9ba0SDavid du Colombier parsename(char *aname, Elemlist *e)
11989a747e4fSDavid du Colombier {
11998b6d9ba0SDavid du Colombier 	char *name, *slash;
12009a747e4fSDavid du Colombier 
12018b6d9ba0SDavid du Colombier 	kstrdup(&e->name, aname);
12029a747e4fSDavid du Colombier 	name = e->name;
12039a747e4fSDavid du Colombier 	e->nelems = 0;
12049a747e4fSDavid du Colombier 	e->elems = nil;
12059a747e4fSDavid du Colombier 	e->off = smalloc(sizeof(int));
1206fb7f0c93SDavid du Colombier 	e->off[0] = skipslash(name) - name;
12079a747e4fSDavid du Colombier 	for(;;){
12089a747e4fSDavid du Colombier 		name = skipslash(name);
1209fb7f0c93SDavid du Colombier 		if(*name == '\0'){
12108b6d9ba0SDavid du Colombier 			e->off[e->nelems] = name+strlen(name) - e->name;
1211fb7f0c93SDavid du Colombier 			e->mustbedir = 1;
12129a747e4fSDavid du Colombier 			break;
1213fb7f0c93SDavid du Colombier 		}
12149a747e4fSDavid du Colombier 		growparse(e);
12159a747e4fSDavid du Colombier 		e->elems[e->nelems++] = name;
12169a747e4fSDavid du Colombier 		slash = utfrune(name, '/');
12179a747e4fSDavid du Colombier 		if(slash == nil){
12189a747e4fSDavid du Colombier 			e->off[e->nelems] = name+strlen(name) - e->name;
1219fb7f0c93SDavid du Colombier 			e->mustbedir = 0;
12209a747e4fSDavid du Colombier 			break;
12219a747e4fSDavid du Colombier 		}
12229a747e4fSDavid du Colombier 		e->off[e->nelems] = slash - e->name;
12239a747e4fSDavid du Colombier 		*slash++ = '\0';
12249a747e4fSDavid du Colombier 		name = slash;
12259a747e4fSDavid du Colombier 	}
12268b6d9ba0SDavid du Colombier 
12274afe124fSDavid du Colombier 	if(0 && chandebug){
12288b6d9ba0SDavid du Colombier 		int i;
12298b6d9ba0SDavid du Colombier 
12308b6d9ba0SDavid du Colombier 		print("parsename %s:", e->name);
12318b6d9ba0SDavid du Colombier 		for(i=0; i<=e->nelems; i++)
12328b6d9ba0SDavid du Colombier 			print(" %d", e->off[i]);
12338b6d9ba0SDavid du Colombier 		print("\n");
12348b6d9ba0SDavid du Colombier 	}
12359a747e4fSDavid du Colombier }
12369a747e4fSDavid du Colombier 
12379a747e4fSDavid du Colombier void*
memrchr(void * va,int c,long n)12389a747e4fSDavid du Colombier memrchr(void *va, int c, long n)
12399a747e4fSDavid du Colombier {
12409a747e4fSDavid du Colombier 	uchar *a, *e;
12419a747e4fSDavid du Colombier 
12429a747e4fSDavid du Colombier 	a = va;
12439a747e4fSDavid du Colombier 	for(e=a+n-1; e>a; e--)
12449a747e4fSDavid du Colombier 		if(*e == c)
12459a747e4fSDavid du Colombier 			return e;
12469a747e4fSDavid du Colombier 	return nil;
12479a747e4fSDavid du Colombier }
12489a747e4fSDavid du Colombier 
1249dc5a79c1SDavid du Colombier void
namelenerror(char * aname,int len,char * err)1250312a1df1SDavid du Colombier namelenerror(char *aname, int len, char *err)
1251dc5a79c1SDavid du Colombier {
12528b6d9ba0SDavid du Colombier 	char *ename, *name, *next;
12538b6d9ba0SDavid du Colombier 	int i, errlen;
1254dc5a79c1SDavid du Colombier 
12558b6d9ba0SDavid du Colombier 	/*
12568b6d9ba0SDavid du Colombier 	 * If the name is short enough, just use the whole thing.
12578b6d9ba0SDavid du Colombier 	 */
12588b6d9ba0SDavid du Colombier 	errlen = strlen(err);
12598b6d9ba0SDavid du Colombier 	if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)
12608b6d9ba0SDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "%.*s",
12618b6d9ba0SDavid du Colombier 			utfnlen(aname, len), aname);
12628b6d9ba0SDavid du Colombier 	else{
12638b6d9ba0SDavid du Colombier 		/*
12648b6d9ba0SDavid du Colombier 		 * Print a suffix of the name, but try to get a little info.
12658b6d9ba0SDavid du Colombier 		 */
12668b6d9ba0SDavid du Colombier 		ename = aname+len;
12678b6d9ba0SDavid du Colombier 		next = ename;
12688b6d9ba0SDavid du Colombier 		do{
12698b6d9ba0SDavid du Colombier 			name = next;
12708b6d9ba0SDavid du Colombier 			next = memrchr(aname, '/', name-aname);
12718b6d9ba0SDavid du Colombier 			if(next == nil)
12728b6d9ba0SDavid du Colombier 				next = aname;
12738b6d9ba0SDavid du Colombier 			len = ename-next;
12748b6d9ba0SDavid du Colombier 		}while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);
12758b6d9ba0SDavid du Colombier 
12768b6d9ba0SDavid du Colombier 		/*
12778b6d9ba0SDavid du Colombier 		 * If the name is ridiculously long, chop it.
12788b6d9ba0SDavid du Colombier 		 */
12798b6d9ba0SDavid du Colombier 		if(name == ename){
12808b6d9ba0SDavid du Colombier 			name = ename-ERRMAX/4;
12818b6d9ba0SDavid du Colombier 			if(name <= aname)
12828b6d9ba0SDavid du Colombier 				panic("bad math in namelenerror");
12838b6d9ba0SDavid du Colombier 			/* walk out of current UTF sequence */
1284d584e620SDavid du Colombier 			for(i=0; (*name&0xC0)==0x80 && i<UTFmax; i++)
12858b6d9ba0SDavid du Colombier 				name++;
12868b6d9ba0SDavid du Colombier 		}
12878b6d9ba0SDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
12888b6d9ba0SDavid du Colombier 			utfnlen(name, ename-name), name);
12898b6d9ba0SDavid du Colombier 	}
1290312a1df1SDavid du Colombier 	snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
1291dc5a79c1SDavid du Colombier 	nexterror();
1292dc5a79c1SDavid du Colombier }
1293dc5a79c1SDavid du Colombier 
1294312a1df1SDavid du Colombier void
nameerror(char * name,char * err)1295312a1df1SDavid du Colombier nameerror(char *name, char *err)
1296312a1df1SDavid du Colombier {
1297312a1df1SDavid du Colombier 	namelenerror(name, strlen(name), err);
1298312a1df1SDavid du Colombier }
1299312a1df1SDavid du Colombier 
13007dd7cddfSDavid du Colombier /*
13013e12c5d1SDavid du Colombier  * Turn a name into a channel.
13023e12c5d1SDavid du Colombier  * &name[0] is known to be a valid address.  It may be a kernel address.
13039a747e4fSDavid du Colombier  *
1304dc5a79c1SDavid du Colombier  * Opening with amode Aopen, Acreate, Aremove, or Aaccess guarantees
13059a747e4fSDavid du Colombier  * that the result will be the only reference to that particular fid.
13069a747e4fSDavid du Colombier  * This is necessary since we might pass the result to
13079a747e4fSDavid du Colombier  * devtab[]->remove().
13089a747e4fSDavid du Colombier  *
1309dc5a79c1SDavid du Colombier  * Opening Atodir or Amount does not guarantee this.
13109a747e4fSDavid du Colombier  *
1311dc5a79c1SDavid du Colombier  * Under certain circumstances, opening Aaccess will cause
1312dc5a79c1SDavid du Colombier  * an unnecessary clone in order to get a cunique Chan so it
1313dc5a79c1SDavid du Colombier  * can attach the correct name.  Sysstat and sys_stat need the
1314dc5a79c1SDavid du Colombier  * correct name so they can rewrite the stat info.
13153e12c5d1SDavid du Colombier  */
13163e12c5d1SDavid du Colombier Chan*
namec(char * aname,int amode,int omode,ulong perm)13179a747e4fSDavid du Colombier namec(char *aname, int amode, int omode, ulong perm)
13183e12c5d1SDavid du Colombier {
13198b6d9ba0SDavid du Colombier 	int len, n, t, nomount;
13209a747e4fSDavid du Colombier 	Chan *c, *cnew;
13214afe124fSDavid du Colombier 	Path *path;
13229a747e4fSDavid du Colombier 	Elemlist e;
13239a747e4fSDavid du Colombier 	Rune r;
13249a747e4fSDavid du Colombier 	Mhead *m;
13259a747e4fSDavid du Colombier 	char *createerr, tmperrbuf[ERRMAX];
13269a747e4fSDavid du Colombier 	char *name;
13273e12c5d1SDavid du Colombier 
1328312a1df1SDavid du Colombier 	if(aname[0] == '\0')
13299a747e4fSDavid du Colombier 		error("empty file name");
1330312a1df1SDavid du Colombier 	aname = validnamedup(aname, 1);
13312db064f5SDavid du Colombier 	if(waserror()){
1332312a1df1SDavid du Colombier 		free(aname);
13332db064f5SDavid du Colombier 		nexterror();
13342db064f5SDavid du Colombier 	}
13354afe124fSDavid du Colombier 	DBG("namec %s %d %d\n", aname, amode, omode);
1336312a1df1SDavid du Colombier 	name = aname;
13373e12c5d1SDavid du Colombier 
13389a747e4fSDavid du Colombier 	/*
13399a747e4fSDavid du Colombier 	 * Find the starting off point (the current slash, the root of
13409a747e4fSDavid du Colombier 	 * a device tree, or the current dot) as well as the name to
13419a747e4fSDavid du Colombier 	 * evaluate starting there.
13429a747e4fSDavid du Colombier 	 */
13439a747e4fSDavid du Colombier 	nomount = 0;
13447dd7cddfSDavid du Colombier 	switch(name[0]){
13457dd7cddfSDavid du Colombier 	case '/':
13469a747e4fSDavid du Colombier 		c = up->slash;
13479a747e4fSDavid du Colombier 		incref(c);
13487dd7cddfSDavid du Colombier 		break;
13499a747e4fSDavid du Colombier 
13507dd7cddfSDavid du Colombier 	case '#':
13519a747e4fSDavid du Colombier 		nomount = 1;
13529a747e4fSDavid du Colombier 		up->genbuf[0] = '\0';
13537dd7cddfSDavid du Colombier 		n = 0;
13549a747e4fSDavid du Colombier 		while(*name != '\0' && (*name != '/' || n < 2)){
13559a747e4fSDavid du Colombier 			if(n >= sizeof(up->genbuf)-1)
13567dd7cddfSDavid du Colombier 				error(Efilename);
13579a747e4fSDavid du Colombier 			up->genbuf[n++] = *name++;
13587dd7cddfSDavid du Colombier 		}
13599a747e4fSDavid du Colombier 		up->genbuf[n] = '\0';
13607dd7cddfSDavid du Colombier 		/*
13617dd7cddfSDavid du Colombier 		 *  noattach is sandboxing.
13627dd7cddfSDavid du Colombier 		 *
13637dd7cddfSDavid du Colombier 		 *  the OK exceptions are:
13647dd7cddfSDavid du Colombier 		 *	|  it only gives access to pipes you create
13657dd7cddfSDavid du Colombier 		 *	d  this process's file descriptors
13667dd7cddfSDavid du Colombier 		 *	e  this process's environment
13677dd7cddfSDavid du Colombier 		 *  the iffy exceptions are:
13687dd7cddfSDavid du Colombier 		 *	c  time and pid, but also cons and consctl
13697dd7cddfSDavid du Colombier 		 *	p  control of your own processes (and unfortunately
13707dd7cddfSDavid du Colombier 		 *	   any others left unprotected)
13717dd7cddfSDavid du Colombier 		 */
13729a747e4fSDavid du Colombier 		n = chartorune(&r, up->genbuf+1)+1;
13737dd7cddfSDavid du Colombier 		/* actually / is caught by parsing earlier */
13747dd7cddfSDavid du Colombier 		if(utfrune("M", r))
13757dd7cddfSDavid du Colombier 			error(Enoattach);
137680ee5cbfSDavid du Colombier 		if(up->pgrp->noattach && utfrune("|decp", r)==nil)
13777dd7cddfSDavid du Colombier 			error(Enoattach);
1378bd389b36SDavid du Colombier 		t = devno(r, 1);
13793e12c5d1SDavid du Colombier 		if(t == -1)
13803e12c5d1SDavid du Colombier 			error(Ebadsharp);
1381aeee3693SDavid du Colombier 		if(debugstart && !devtab[t]->attached)
1382*70b6ec21SDavid du Colombier 			print("#%C...", devtab[t]->dc);
13839a747e4fSDavid du Colombier 		c = devtab[t]->attach(up->genbuf+n);
1384aeee3693SDavid du Colombier 		if(debugstart && c != nil)
1385aeee3693SDavid du Colombier 			devtab[t]->attached = 1;
13869a747e4fSDavid du Colombier 		break;
13877dd7cddfSDavid du Colombier 
13889a747e4fSDavid du Colombier 	default:
13899a747e4fSDavid du Colombier 		c = up->dot;
13909a747e4fSDavid du Colombier 		incref(c);
13917dd7cddfSDavid du Colombier 		break;
13923e12c5d1SDavid du Colombier 	}
13933e12c5d1SDavid du Colombier 
1394312a1df1SDavid du Colombier 	e.aname = aname;
13958b6d9ba0SDavid du Colombier 	e.prefix = name - aname;
13969a747e4fSDavid du Colombier 	e.name = nil;
13979a747e4fSDavid du Colombier 	e.elems = nil;
13989a747e4fSDavid du Colombier 	e.off = nil;
13999a747e4fSDavid du Colombier 	e.nelems = 0;
1400312a1df1SDavid du Colombier 	e.nerror = 0;
14013e12c5d1SDavid du Colombier 	if(waserror()){
14027dd7cddfSDavid du Colombier 		cclose(c);
14039a747e4fSDavid du Colombier 		free(e.name);
14049a747e4fSDavid du Colombier 		free(e.elems);
1405312a1df1SDavid du Colombier 		/*
1406312a1df1SDavid du Colombier 		 * Prepare nice error, showing first e.nerror elements of name.
1407312a1df1SDavid du Colombier 		 */
1408312a1df1SDavid du Colombier 		if(e.nerror == 0)
14093e12c5d1SDavid du Colombier 			nexterror();
1410312a1df1SDavid du Colombier 		strcpy(tmperrbuf, up->errstr);
14118b6d9ba0SDavid du Colombier 		if(e.off[e.nerror]==0)
14128b6d9ba0SDavid du Colombier 			print("nerror=%d but off=%d\n",
14138b6d9ba0SDavid du Colombier 				e.nerror, e.off[e.nerror]);
14144afe124fSDavid du Colombier 		if(0 && chandebug)
14158b6d9ba0SDavid du Colombier 			print("showing %d+%d/%d (of %d) of %s (%d %d)\n", e.prefix, e.off[e.nerror], e.nerror, e.nelems, aname, e.off[0], e.off[1]);
14168b6d9ba0SDavid du Colombier 		len = e.prefix+e.off[e.nerror];
14178b6d9ba0SDavid du Colombier 		free(e.off);
14188b6d9ba0SDavid du Colombier 		namelenerror(aname, len, tmperrbuf);
14193e12c5d1SDavid du Colombier 	}
14203e12c5d1SDavid du Colombier 
14219a747e4fSDavid du Colombier 	/*
14224afe124fSDavid du Colombier 	 * Build a list of elements in the name.
14239a747e4fSDavid du Colombier 	 */
14249a747e4fSDavid du Colombier 	parsename(name, &e);
14253e12c5d1SDavid du Colombier 
14263e12c5d1SDavid du Colombier 	/*
1427fb7f0c93SDavid du Colombier 	 * On create, ....
14283e12c5d1SDavid du Colombier 	 */
14299a747e4fSDavid du Colombier 	if(amode == Acreate){
1430fb7f0c93SDavid du Colombier 		/* perm must have DMDIR if last element is / or /. */
1431fb7f0c93SDavid du Colombier 		if(e.mustbedir && !(perm&DMDIR)){
1432312a1df1SDavid du Colombier 			e.nerror = e.nelems;
1433312a1df1SDavid du Colombier 			error("create without DMDIR");
1434fb7f0c93SDavid du Colombier 		}
1435fb7f0c93SDavid du Colombier 
1436fb7f0c93SDavid du Colombier 		/* don't try to walk the last path element just yet. */
14379a747e4fSDavid du Colombier 		if(e.nelems == 0)
1438fb7f0c93SDavid du Colombier 			error(Eexist);
14399a747e4fSDavid du Colombier 		e.nelems--;
14409a747e4fSDavid du Colombier 	}
14413e12c5d1SDavid du Colombier 
1442312a1df1SDavid du Colombier 	if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){
1443312a1df1SDavid du Colombier 		if(e.nerror < 0 || e.nerror > e.nelems){
1444312a1df1SDavid du Colombier 			print("namec %s walk error nerror=%d\n", aname, e.nerror);
1445312a1df1SDavid du Colombier 			e.nerror = 0;
1446312a1df1SDavid du Colombier 		}
14479a747e4fSDavid du Colombier 		nexterror();
14489a747e4fSDavid du Colombier 	}
14493e12c5d1SDavid du Colombier 
1450312a1df1SDavid du Colombier 	if(e.mustbedir && !(c->qid.type&QTDIR))
1451312a1df1SDavid du Colombier 		error("not a directory");
1452fb7f0c93SDavid du Colombier 
1453312a1df1SDavid du Colombier 	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR))
1454fb7f0c93SDavid du Colombier 		error("cannot exec directory");
1455fb7f0c93SDavid du Colombier 
14563e12c5d1SDavid du Colombier 	switch(amode){
14579a747e4fSDavid du Colombier 	case Abind:
14584afe124fSDavid du Colombier 		/* no need to maintain path - cannot dotdot an Abind */
14599a747e4fSDavid du Colombier 		m = nil;
14609a747e4fSDavid du Colombier 		if(!nomount)
14614afe124fSDavid du Colombier 			domount(&c, &m, nil);
14623ff48bf5SDavid du Colombier 		if(c->umh != nil)
14633ff48bf5SDavid du Colombier 			putmhead(c->umh);
14649a747e4fSDavid du Colombier 		c->umh = m;
14659a747e4fSDavid du Colombier 		break;
14669a747e4fSDavid du Colombier 
1467dc5a79c1SDavid du Colombier 	case Aaccess:
14689a747e4fSDavid du Colombier 	case Aremove:
14699a747e4fSDavid du Colombier 	case Aopen:
14709a747e4fSDavid du Colombier 	Open:
14714afe124fSDavid du Colombier 		/* save&update the name; domount might change c */
14724afe124fSDavid du Colombier 		path = c->path;
14734afe124fSDavid du Colombier 		incref(path);
14749a747e4fSDavid du Colombier 		m = nil;
14759a747e4fSDavid du Colombier 		if(!nomount)
14764afe124fSDavid du Colombier 			domount(&c, &m, &path);
14779a747e4fSDavid du Colombier 
14789a747e4fSDavid du Colombier 		/* our own copy to open or remove */
14799a747e4fSDavid du Colombier 		c = cunique(c);
14809a747e4fSDavid du Colombier 
14819a747e4fSDavid du Colombier 		/* now it's our copy anyway, we can put the name back */
14824afe124fSDavid du Colombier 		pathclose(c->path);
14834afe124fSDavid du Colombier 		c->path = path;
14849a747e4fSDavid du Colombier 
1485dc5a79c1SDavid du Colombier 		/* record whether c is on a mount point */
1486dc5a79c1SDavid du Colombier 		c->ismtpt = m!=nil;
1487dc5a79c1SDavid du Colombier 
14889a747e4fSDavid du Colombier 		switch(amode){
1489dc5a79c1SDavid du Colombier 		case Aaccess:
14909a747e4fSDavid du Colombier 		case Aremove:
14919a747e4fSDavid du Colombier 			putmhead(m);
14929a747e4fSDavid du Colombier 			break;
14939a747e4fSDavid du Colombier 
14949a747e4fSDavid du Colombier 		case Aopen:
14959a747e4fSDavid du Colombier 		case Acreate:
14969a747e4fSDavid du Colombier if(c->umh != nil){
14973ff48bf5SDavid du Colombier 	print("cunique umh Open\n");
14989a747e4fSDavid du Colombier 	putmhead(c->umh);
14993ff48bf5SDavid du Colombier 	c->umh = nil;
15009a747e4fSDavid du Colombier }
15019a747e4fSDavid du Colombier 			/* only save the mount head if it's a multiple element union */
15029a747e4fSDavid du Colombier 			if(m && m->mount && m->mount->next)
15039a747e4fSDavid du Colombier 				c->umh = m;
15049a747e4fSDavid du Colombier 			else
15059a747e4fSDavid du Colombier 				putmhead(m);
15069a747e4fSDavid du Colombier 
15079a747e4fSDavid du Colombier 			/* save registers else error() in open has wrong value of c saved */
15089a747e4fSDavid du Colombier 			saveregisters();
15099a747e4fSDavid du Colombier 
15109a747e4fSDavid du Colombier 			if(omode == OEXEC)
15119a747e4fSDavid du Colombier 				c->flag &= ~CCACHE;
15129a747e4fSDavid du Colombier 
15139a747e4fSDavid du Colombier 			c = devtab[c->type]->open(c, omode&~OCEXEC);
15149a747e4fSDavid du Colombier 
15159a747e4fSDavid du Colombier 			if(omode & OCEXEC)
15169a747e4fSDavid du Colombier 				c->flag |= CCEXEC;
15179a747e4fSDavid du Colombier 			if(omode & ORCLOSE)
15189a747e4fSDavid du Colombier 				c->flag |= CRCLOSE;
15197dd7cddfSDavid du Colombier 			break;
15203e12c5d1SDavid du Colombier 		}
15213e12c5d1SDavid du Colombier 		break;
15223e12c5d1SDavid du Colombier 
15233e12c5d1SDavid du Colombier 	case Atodir:
15243e12c5d1SDavid du Colombier 		/*
15253e12c5d1SDavid du Colombier 		 * Directories (e.g. for cd) are left before the mount point,
15263e12c5d1SDavid du Colombier 		 * so one may mount on / or . and see the effect.
15273e12c5d1SDavid du Colombier 		 */
15289a747e4fSDavid du Colombier 		if(!(c->qid.type & QTDIR))
15293e12c5d1SDavid du Colombier 			error(Enotdir);
15303e12c5d1SDavid du Colombier 		break;
15313e12c5d1SDavid du Colombier 
15323e12c5d1SDavid du Colombier 	case Amount:
15333e12c5d1SDavid du Colombier 		/*
15347dd7cddfSDavid du Colombier 		 * When mounting on an already mounted upon directory,
15357dd7cddfSDavid du Colombier 		 * one wants subsequent mounts to be attached to the
15369a747e4fSDavid du Colombier 		 * original directory, not the replacement.  Don't domount.
15373e12c5d1SDavid du Colombier 		 */
15383e12c5d1SDavid du Colombier 		break;
15393e12c5d1SDavid du Colombier 
15403e12c5d1SDavid du Colombier 	case Acreate:
15413e12c5d1SDavid du Colombier 		/*
15429a747e4fSDavid du Colombier 		 * We've already walked all but the last element.
15439a747e4fSDavid du Colombier 		 * If the last exists, try to open it OTRUNC.
15449a747e4fSDavid du Colombier 		 * If omode&OEXCL is set, just give up.
15453e12c5d1SDavid du Colombier 		 */
15469a747e4fSDavid du Colombier 		e.nelems++;
1547312a1df1SDavid du Colombier 		e.nerror++;
15489a747e4fSDavid du Colombier 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
15499a747e4fSDavid du Colombier 			if(omode&OEXCL)
15509a747e4fSDavid du Colombier 				error(Eexist);
15513e12c5d1SDavid du Colombier 			omode |= OTRUNC;
15523e12c5d1SDavid du Colombier 			goto Open;
15533e12c5d1SDavid du Colombier 		}
15543e12c5d1SDavid du Colombier 
15553e12c5d1SDavid du Colombier 		/*
15569a747e4fSDavid du Colombier 		 * The semantics of the create(2) system call are that if the
15579a747e4fSDavid du Colombier 		 * file exists and can be written, it is to be opened with truncation.
15589a747e4fSDavid du Colombier 		 * On the other hand, the create(5) message fails if the file exists.
15599a747e4fSDavid du Colombier 		 * If we get two create(2) calls happening simultaneously,
15609a747e4fSDavid du Colombier 		 * they might both get here and send create(5) messages, but only
15619a747e4fSDavid du Colombier 		 * one of the messages will succeed.  To provide the expected create(2)
15629a747e4fSDavid du Colombier 		 * semantics, the call with the failed message needs to try the above
15639a747e4fSDavid du Colombier 		 * walk again, opening for truncation.  This correctly solves the
15649a747e4fSDavid du Colombier 		 * create/create race, in the sense that any observable outcome can
15659a747e4fSDavid du Colombier 		 * be explained as one happening before the other.
15669a747e4fSDavid du Colombier 		 * The create/create race is quite common.  For example, it happens
15679a747e4fSDavid du Colombier 		 * when two rc subshells simultaneously update the same
15689a747e4fSDavid du Colombier 		 * environment variable.
15699a747e4fSDavid du Colombier 		 *
15709a747e4fSDavid du Colombier 		 * The implementation still admits a create/create/remove race:
15719a747e4fSDavid du Colombier 		 * (A) walk to file, fails
15729a747e4fSDavid du Colombier 		 * (B) walk to file, fails
15739a747e4fSDavid du Colombier 		 * (A) create file, succeeds, returns
15749a747e4fSDavid du Colombier 		 * (B) create file, fails
15759a747e4fSDavid du Colombier 		 * (A) remove file, succeeds, returns
15769a747e4fSDavid du Colombier 		 * (B) walk to file, return failure.
15779a747e4fSDavid du Colombier 		 *
15789a747e4fSDavid du Colombier 		 * This is hardly as common as the create/create race, and is really
15799a747e4fSDavid du Colombier 		 * not too much worse than what might happen if (B) got a hold of a
15809a747e4fSDavid du Colombier 		 * file descriptor and then the file was removed -- either way (B) can't do
15819a747e4fSDavid du Colombier 		 * anything with the result of the create call.  So we don't care about this race.
15829a747e4fSDavid du Colombier 		 *
15839a747e4fSDavid du Colombier 		 * Applications that care about more fine-grained decision of the races
15849a747e4fSDavid du Colombier 		 * can use the OEXCL flag to get at the underlying create(5) semantics;
15859a747e4fSDavid du Colombier 		 * by default we provide the common case.
15869a747e4fSDavid du Colombier 		 *
15879a747e4fSDavid du Colombier 		 * We need to stay behind the mount point in case we
15889a747e4fSDavid du Colombier 		 * need to do the first walk again (should the create fail).
15899a747e4fSDavid du Colombier 		 *
15909a747e4fSDavid du Colombier 		 * We also need to cross the mount point and find the directory
15919a747e4fSDavid du Colombier 		 * in the union in which we should be creating.
15929a747e4fSDavid du Colombier 		 *
15939a747e4fSDavid du Colombier 		 * The channel staying behind is c, the one moving forward is cnew.
15943e12c5d1SDavid du Colombier 		 */
15959a747e4fSDavid du Colombier 		m = nil;
15969a747e4fSDavid du Colombier 		cnew = nil;	/* is this assignment necessary? */
15979a747e4fSDavid du Colombier 		if(!waserror()){	/* try create */
15989a747e4fSDavid du Colombier 			if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))
15999a747e4fSDavid du Colombier 				cnew = createdir(cnew, m);
16009a747e4fSDavid du Colombier 			else{
16019a747e4fSDavid du Colombier 				cnew = c;
16029a747e4fSDavid du Colombier 				incref(cnew);
16033e12c5d1SDavid du Colombier 			}
16049a747e4fSDavid du Colombier 
16059a747e4fSDavid du Colombier 			/*
16069a747e4fSDavid du Colombier 			 * We need our own copy of the Chan because we're
16079a747e4fSDavid du Colombier 			 * about to send a create, which will move it.  Once we have
16089a747e4fSDavid du Colombier 			 * our own copy, we can fix the name, which might be wrong
16099a747e4fSDavid du Colombier 			 * if findmount gave us a new Chan.
16109a747e4fSDavid du Colombier 			 */
16119a747e4fSDavid du Colombier 			cnew = cunique(cnew);
16124afe124fSDavid du Colombier 			pathclose(cnew->path);
16134afe124fSDavid du Colombier 			cnew->path = c->path;
16144afe124fSDavid du Colombier 			incref(cnew->path);
16159a747e4fSDavid du Colombier 
16169a747e4fSDavid du Colombier 			devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
16179a747e4fSDavid du Colombier 			poperror();
16183e12c5d1SDavid du Colombier 			if(omode & OCEXEC)
16199a747e4fSDavid du Colombier 				cnew->flag |= CCEXEC;
16207dd7cddfSDavid du Colombier 			if(omode & ORCLOSE)
16219a747e4fSDavid du Colombier 				cnew->flag |= CRCLOSE;
16229a747e4fSDavid du Colombier 			if(m)
16239a747e4fSDavid du Colombier 				putmhead(m);
16249a747e4fSDavid du Colombier 			cclose(c);
16259a747e4fSDavid du Colombier 			c = cnew;
16264afe124fSDavid du Colombier 			c->path = addelem(c->path, e.elems[e.nelems-1], nil);
16273e12c5d1SDavid du Colombier 			break;
16289acf0835SDavid du Colombier 		}
16299acf0835SDavid du Colombier 
16309acf0835SDavid du Colombier 		/* create failed */
16319a747e4fSDavid du Colombier 		cclose(cnew);
16329a747e4fSDavid du Colombier 		if(m)
16339a747e4fSDavid du Colombier 			putmhead(m);
16349a747e4fSDavid du Colombier 		if(omode & OEXCL)
16359a747e4fSDavid du Colombier 			nexterror();
16369a747e4fSDavid du Colombier 		/* save error */
16379a747e4fSDavid du Colombier 		createerr = up->errstr;
16389a747e4fSDavid du Colombier 		up->errstr = tmperrbuf;
16399a747e4fSDavid du Colombier 		/* note: we depend that walk does not error */
16409a747e4fSDavid du Colombier 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
16419a747e4fSDavid du Colombier 			up->errstr = createerr;
16429a747e4fSDavid du Colombier 			error(createerr);	/* report true error */
16439a747e4fSDavid du Colombier 		}
16449a747e4fSDavid du Colombier 		up->errstr = createerr;
16459a747e4fSDavid du Colombier 		omode |= OTRUNC;
16469a747e4fSDavid du Colombier 		goto Open;
16473e12c5d1SDavid du Colombier 
16483e12c5d1SDavid du Colombier 	default:
16493e12c5d1SDavid du Colombier 		panic("unknown namec access %d\n", amode);
16503e12c5d1SDavid du Colombier 	}
16517dd7cddfSDavid du Colombier 
16529a747e4fSDavid du Colombier 	/* place final element in genbuf for e.g. exec */
16539a747e4fSDavid du Colombier 	if(e.nelems > 0)
16549a747e4fSDavid du Colombier 		kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
16559a747e4fSDavid du Colombier 	else
16569a747e4fSDavid du Colombier 		kstrcpy(up->genbuf, ".", sizeof up->genbuf);
16579a747e4fSDavid du Colombier 	free(e.name);
16589a747e4fSDavid du Colombier 	free(e.elems);
16599a747e4fSDavid du Colombier 	free(e.off);
16602db064f5SDavid du Colombier 	poperror();	/* e c */
1661a4aabefcSDavid du Colombier 	free(aname);
1662a4aabefcSDavid du Colombier 	poperror();	/* aname */
16637dd7cddfSDavid du Colombier 
16643e12c5d1SDavid du Colombier 	return c;
16653e12c5d1SDavid du Colombier }
16663e12c5d1SDavid du Colombier 
16673e12c5d1SDavid du Colombier /*
1668fb7f0c93SDavid du Colombier  * name is valid. skip leading / and ./ as much as possible
16693e12c5d1SDavid du Colombier  */
16703e12c5d1SDavid du Colombier char*
skipslash(char * name)16713e12c5d1SDavid du Colombier skipslash(char *name)
16723e12c5d1SDavid du Colombier {
1673fb7f0c93SDavid du Colombier 	while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
16743e12c5d1SDavid du Colombier 		name++;
16753e12c5d1SDavid du Colombier 	return name;
16763e12c5d1SDavid du Colombier }
16773e12c5d1SDavid du Colombier 
16783e12c5d1SDavid du Colombier char isfrog[256]={
16793e12c5d1SDavid du Colombier 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
16803e12c5d1SDavid du Colombier 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
16813e12c5d1SDavid du Colombier 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
16823e12c5d1SDavid du Colombier 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
16833e12c5d1SDavid du Colombier 	['/']	1,
16843e12c5d1SDavid du Colombier 	[0x7f]	1,
16853e12c5d1SDavid du Colombier };
16863e12c5d1SDavid du Colombier 
16873e12c5d1SDavid du Colombier /*
16889a747e4fSDavid du Colombier  * Check that the name
16899a747e4fSDavid du Colombier  *  a) is in valid memory.
16909a747e4fSDavid du Colombier  *  b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
16919a747e4fSDavid du Colombier  *  c) contains no frogs.
16929a747e4fSDavid du Colombier  * The first byte is known to be addressible by the requester, so the
16939a747e4fSDavid du Colombier  * routine works for kernel and user memory both.
16949a747e4fSDavid du Colombier  * The parameter slashok flags whether a slash character is an error
16959a747e4fSDavid du Colombier  * or a valid character.
16962db064f5SDavid du Colombier  *
16972db064f5SDavid du Colombier  * The parameter dup flags whether the string should be copied
16982db064f5SDavid du Colombier  * out of user space before being scanned the second time.
16992db064f5SDavid du Colombier  * (Otherwise a malicious thread could remove the NUL, causing us
17002db064f5SDavid du Colombier  * to access unchecked addresses.)
17013e12c5d1SDavid du Colombier  */
17022db064f5SDavid du Colombier static char*
validname0(char * aname,int slashok,int dup,ulong pc)17032db064f5SDavid du Colombier validname0(char *aname, int slashok, int dup, ulong pc)
17043e12c5d1SDavid du Colombier {
1705e1a0fcefSDavid du Colombier 	char *ename, *name, *s;
17062db064f5SDavid du Colombier 	int c, n;
17073e12c5d1SDavid du Colombier 	Rune r;
17083e12c5d1SDavid du Colombier 
17099a747e4fSDavid du Colombier 	name = aname;
17104de34a7eSDavid du Colombier 	if((ulong)name < KZERO){
17112db064f5SDavid du Colombier 		if(!dup)
1712d584e620SDavid du Colombier 			print("warning: validname called from %#p with user pointer", pc);
1713e1a0fcefSDavid du Colombier 		ename = vmemchr(name, 0, (1<<16));
17149a747e4fSDavid du Colombier 	}else
17159a747e4fSDavid du Colombier 		ename = memchr(name, 0, (1<<16));
17169a747e4fSDavid du Colombier 
17179a747e4fSDavid du Colombier 	if(ename==nil || ename-name>=(1<<16))
17189a747e4fSDavid du Colombier 		error("name too long");
17199a747e4fSDavid du Colombier 
17202db064f5SDavid du Colombier 	s = nil;
17212db064f5SDavid du Colombier 	if(dup){
17222db064f5SDavid du Colombier 		n = ename-name;
17232db064f5SDavid du Colombier 		s = smalloc(n+1);
17242db064f5SDavid du Colombier 		memmove(s, name, n);
17252db064f5SDavid du Colombier 		s[n] = 0;
17262db064f5SDavid du Colombier 		aname = s;
17272db064f5SDavid du Colombier 		name = s;
1728824682f6SDavid du Colombier 		setmalloctag(s, pc);
17292db064f5SDavid du Colombier 	}
17302db064f5SDavid du Colombier 
17319a747e4fSDavid du Colombier 	while(*name){
17329a747e4fSDavid du Colombier 		/* all characters above '~' are ok */
17339a747e4fSDavid du Colombier 		c = *(uchar*)name;
17349a747e4fSDavid du Colombier 		if(c >= Runeself)
17359a747e4fSDavid du Colombier 			name += chartorune(&r, name);
17369a747e4fSDavid du Colombier 		else{
17379a747e4fSDavid du Colombier 			if(isfrog[c])
17389a747e4fSDavid du Colombier 				if(!slashok || c!='/'){
17399a747e4fSDavid du Colombier 					snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
17402db064f5SDavid du Colombier 					free(s);
17419a747e4fSDavid du Colombier 					error(up->genbuf);
17429a747e4fSDavid du Colombier 			}
17439a747e4fSDavid du Colombier 			name++;
17449a747e4fSDavid du Colombier 		}
17459a747e4fSDavid du Colombier 	}
17462db064f5SDavid du Colombier 	return s;
17472db064f5SDavid du Colombier }
17482db064f5SDavid du Colombier 
17492db064f5SDavid du Colombier void
validname(char * aname,int slashok)17502db064f5SDavid du Colombier validname(char *aname, int slashok)
17512db064f5SDavid du Colombier {
17522db064f5SDavid du Colombier 	validname0(aname, slashok, 0, getcallerpc(&aname));
17532db064f5SDavid du Colombier }
17542db064f5SDavid du Colombier 
17552db064f5SDavid du Colombier char*
validnamedup(char * aname,int slashok)17562db064f5SDavid du Colombier validnamedup(char *aname, int slashok)
17572db064f5SDavid du Colombier {
1758824682f6SDavid du Colombier 	return validname0(aname, slashok, 1, getcallerpc(&aname));
17593e12c5d1SDavid du Colombier }
17603e12c5d1SDavid du Colombier 
17613e12c5d1SDavid du Colombier void
isdir(Chan * c)17623e12c5d1SDavid du Colombier isdir(Chan *c)
17633e12c5d1SDavid du Colombier {
17649a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
17653e12c5d1SDavid du Colombier 		return;
17663e12c5d1SDavid du Colombier 	error(Enotdir);
17673e12c5d1SDavid du Colombier }
17687dd7cddfSDavid du Colombier 
17699a747e4fSDavid du Colombier /*
17709a747e4fSDavid du Colombier  * This is necessary because there are many
17719a747e4fSDavid du Colombier  * pointers to the top of a given mount list:
17729a747e4fSDavid du Colombier  *
17739a747e4fSDavid du Colombier  *	- the mhead in the namespace hash table
17749a747e4fSDavid du Colombier  *	- the mhead in chans returned from findmount:
17759a747e4fSDavid du Colombier  *	  used in namec and then by unionread.
17769a747e4fSDavid du Colombier  *	- the mhead in chans returned from createdir:
17779a747e4fSDavid du Colombier  *	  used in the open/create race protect, which is gone.
17789a747e4fSDavid du Colombier  *
17799a747e4fSDavid du Colombier  * The RWlock in the Mhead protects the mount list it contains.
17809a747e4fSDavid du Colombier  * The mount list is deleted when we cunmount.
17819a747e4fSDavid du Colombier  * The RWlock ensures that nothing is using the mount list at that time.
17829a747e4fSDavid du Colombier  *
17839a747e4fSDavid du Colombier  * It is okay to replace c->mh with whatever you want as
17849a747e4fSDavid du Colombier  * long as you are sure you have a unique reference to it.
17859a747e4fSDavid du Colombier  *
17869a747e4fSDavid du Colombier  * This comment might belong somewhere else.
17879a747e4fSDavid du Colombier  */
17887dd7cddfSDavid du Colombier void
putmhead(Mhead * m)17897dd7cddfSDavid du Colombier putmhead(Mhead *m)
17907dd7cddfSDavid du Colombier {
17919a747e4fSDavid du Colombier 	if(m && decref(m) == 0){
17929a747e4fSDavid du Colombier 		m->mount = (Mount*)0xCafeBeef;
17937dd7cddfSDavid du Colombier 		free(m);
17947dd7cddfSDavid du Colombier 	}
17959a747e4fSDavid du Colombier }
17962cca75a1SDavid du Colombier 
1797