xref: /plan9/sys/src/cmd/unix/drawterm/kern/chan.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include	"u.h"
2*8ccd4a63SDavid du Colombier #include	"lib.h"
3*8ccd4a63SDavid du Colombier #include	"dat.h"
4*8ccd4a63SDavid du Colombier #include	"fns.h"
5*8ccd4a63SDavid du Colombier #include	"error.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier int chandebug=0;		/* toggled by sysr1 */
8*8ccd4a63SDavid du Colombier QLock chanprint;		/* probably asking for trouble (deadlocks) -rsc */
9*8ccd4a63SDavid du Colombier 
10*8ccd4a63SDavid du Colombier int domount(Chan**, Mhead**);
11*8ccd4a63SDavid du Colombier 
12*8ccd4a63SDavid du Colombier void
13*8ccd4a63SDavid du Colombier dumpmount(void)		/* DEBUGGING */
14*8ccd4a63SDavid du Colombier {
15*8ccd4a63SDavid du Colombier 	Pgrp *pg;
16*8ccd4a63SDavid du Colombier 	Mount *t;
17*8ccd4a63SDavid du Colombier 	Mhead **h, **he, *f;
18*8ccd4a63SDavid du Colombier 
19*8ccd4a63SDavid du Colombier 	if(up == nil){
20*8ccd4a63SDavid du Colombier 		print("no process for dumpmount\n");
21*8ccd4a63SDavid du Colombier 		return;
22*8ccd4a63SDavid du Colombier 	}
23*8ccd4a63SDavid du Colombier 	pg = up->pgrp;
24*8ccd4a63SDavid du Colombier 	if(pg == nil){
25*8ccd4a63SDavid du Colombier 		print("no pgrp for dumpmount\n");
26*8ccd4a63SDavid du Colombier 		return;
27*8ccd4a63SDavid du Colombier 	}
28*8ccd4a63SDavid du Colombier 	rlock(&pg->ns);
29*8ccd4a63SDavid du Colombier 	if(waserror()) {
30*8ccd4a63SDavid du Colombier 		runlock(&pg->ns);
31*8ccd4a63SDavid du Colombier 		nexterror();
32*8ccd4a63SDavid du Colombier 	}
33*8ccd4a63SDavid du Colombier 
34*8ccd4a63SDavid du Colombier 	he = &pg->mnthash[MNTHASH];
35*8ccd4a63SDavid du Colombier 	for(h = pg->mnthash; h < he; h++) {
36*8ccd4a63SDavid du Colombier 		for(f = *h; f; f = f->hash) {
37*8ccd4a63SDavid du Colombier 			print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f,
38*8ccd4a63SDavid du Colombier 				f->from->name->s, f->from->qid.path,
39*8ccd4a63SDavid du Colombier 				f->from->qid.vers, devtab[f->from->type]->dc,
40*8ccd4a63SDavid du Colombier 				f->from->dev);
41*8ccd4a63SDavid du Colombier 			for(t = f->mount; t; t = t->next)
42*8ccd4a63SDavid du Colombier 				print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
43*8ccd4a63SDavid du Colombier 		}
44*8ccd4a63SDavid du Colombier 	}
45*8ccd4a63SDavid du Colombier 	poperror();
46*8ccd4a63SDavid du Colombier 	runlock(&pg->ns);
47*8ccd4a63SDavid du Colombier }
48*8ccd4a63SDavid du Colombier 
49*8ccd4a63SDavid du Colombier 
50*8ccd4a63SDavid du Colombier char*
51*8ccd4a63SDavid du Colombier c2name(Chan *c)		/* DEBUGGING */
52*8ccd4a63SDavid du Colombier {
53*8ccd4a63SDavid du Colombier 	if(c == nil)
54*8ccd4a63SDavid du Colombier 		return "<nil chan>";
55*8ccd4a63SDavid du Colombier 	if(c->name == nil)
56*8ccd4a63SDavid du Colombier 		return "<nil name>";
57*8ccd4a63SDavid du Colombier 	if(c->name->s == nil)
58*8ccd4a63SDavid du Colombier 		return "<nil name.s>";
59*8ccd4a63SDavid du Colombier 	return c->name->s;
60*8ccd4a63SDavid du Colombier }
61*8ccd4a63SDavid du Colombier 
62*8ccd4a63SDavid du Colombier enum
63*8ccd4a63SDavid du Colombier {
64*8ccd4a63SDavid du Colombier 	CNAMESLOP	= 20
65*8ccd4a63SDavid du Colombier };
66*8ccd4a63SDavid du Colombier 
67*8ccd4a63SDavid du Colombier struct
68*8ccd4a63SDavid du Colombier {
69*8ccd4a63SDavid du Colombier 	Lock lk;
70*8ccd4a63SDavid du Colombier 	int	fid;
71*8ccd4a63SDavid du Colombier 	Chan	*free;
72*8ccd4a63SDavid du Colombier 	Chan	*list;
73*8ccd4a63SDavid du Colombier }chanalloc;
74*8ccd4a63SDavid du Colombier 
75*8ccd4a63SDavid du Colombier typedef struct Elemlist Elemlist;
76*8ccd4a63SDavid du Colombier 
77*8ccd4a63SDavid du Colombier struct Elemlist
78*8ccd4a63SDavid du Colombier {
79*8ccd4a63SDavid du Colombier 	char	*name;	/* copy of name, so '/' can be overwritten */
80*8ccd4a63SDavid du Colombier 	int	nelems;
81*8ccd4a63SDavid du Colombier 	char	**elems;
82*8ccd4a63SDavid du Colombier 	int	*off;
83*8ccd4a63SDavid du Colombier 	int	mustbedir;
84*8ccd4a63SDavid du Colombier };
85*8ccd4a63SDavid du Colombier 
86*8ccd4a63SDavid du Colombier #define SEP(c) ((c) == 0 || (c) == '/')
87*8ccd4a63SDavid du Colombier void cleancname(Cname*);
88*8ccd4a63SDavid du Colombier 
89*8ccd4a63SDavid du Colombier int
90*8ccd4a63SDavid du Colombier isdotdot(char *p)
91*8ccd4a63SDavid du Colombier {
92*8ccd4a63SDavid du Colombier 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
93*8ccd4a63SDavid du Colombier }
94*8ccd4a63SDavid du Colombier 
95*8ccd4a63SDavid du Colombier int
96*8ccd4a63SDavid du Colombier incref(Ref *r)
97*8ccd4a63SDavid du Colombier {
98*8ccd4a63SDavid du Colombier 	int x;
99*8ccd4a63SDavid du Colombier 
100*8ccd4a63SDavid du Colombier 	lock(&r->lk);
101*8ccd4a63SDavid du Colombier 	x = ++r->ref;
102*8ccd4a63SDavid du Colombier 	unlock(&r->lk);
103*8ccd4a63SDavid du Colombier 	return x;
104*8ccd4a63SDavid du Colombier }
105*8ccd4a63SDavid du Colombier 
106*8ccd4a63SDavid du Colombier int
107*8ccd4a63SDavid du Colombier decref(Ref *r)
108*8ccd4a63SDavid du Colombier {
109*8ccd4a63SDavid du Colombier 	int x;
110*8ccd4a63SDavid du Colombier 
111*8ccd4a63SDavid du Colombier 	lock(&r->lk);
112*8ccd4a63SDavid du Colombier 	x = --r->ref;
113*8ccd4a63SDavid du Colombier 	unlock(&r->lk);
114*8ccd4a63SDavid du Colombier 	if(x < 0)
115*8ccd4a63SDavid du Colombier 		panic("decref, pc=0x%lux", getcallerpc(&r));
116*8ccd4a63SDavid du Colombier 
117*8ccd4a63SDavid du Colombier 	return x;
118*8ccd4a63SDavid du Colombier }
119*8ccd4a63SDavid du Colombier 
120*8ccd4a63SDavid du Colombier /*
121*8ccd4a63SDavid du Colombier  * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
122*8ccd4a63SDavid du Colombier  * truncates if necessary, always zero terminates, does not zero fill,
123*8ccd4a63SDavid du Colombier  * and puts ... at the end of the string if it's too long.  Usually used to
124*8ccd4a63SDavid du Colombier  * save a string in up->genbuf;
125*8ccd4a63SDavid du Colombier  */
126*8ccd4a63SDavid du Colombier void
127*8ccd4a63SDavid du Colombier kstrcpy(char *s, char *t, int ns)
128*8ccd4a63SDavid du Colombier {
129*8ccd4a63SDavid du Colombier 	int nt;
130*8ccd4a63SDavid du Colombier 
131*8ccd4a63SDavid du Colombier 	nt = strlen(t);
132*8ccd4a63SDavid du Colombier 	if(nt+1 <= ns){
133*8ccd4a63SDavid du Colombier 		memmove(s, t, nt+1);
134*8ccd4a63SDavid du Colombier 		return;
135*8ccd4a63SDavid du Colombier 	}
136*8ccd4a63SDavid du Colombier 	/* too long */
137*8ccd4a63SDavid du Colombier 	if(ns < 4){
138*8ccd4a63SDavid du Colombier 		/* but very short! */
139*8ccd4a63SDavid du Colombier 		strncpy(s, t, ns);
140*8ccd4a63SDavid du Colombier 		return;
141*8ccd4a63SDavid du Colombier 	}
142*8ccd4a63SDavid du Colombier 	/* truncate with ... at character boundary (very rare case) */
143*8ccd4a63SDavid du Colombier 	memmove(s, t, ns-4);
144*8ccd4a63SDavid du Colombier 	ns -= 4;
145*8ccd4a63SDavid du Colombier 	s[ns] = '\0';
146*8ccd4a63SDavid du Colombier 	/* look for first byte of UTF-8 sequence by skipping continuation bytes */
147*8ccd4a63SDavid du Colombier 	while(ns>0 && (s[--ns]&0xC0)==0x80)
148*8ccd4a63SDavid du Colombier 		;
149*8ccd4a63SDavid du Colombier 	strcpy(s+ns, "...");
150*8ccd4a63SDavid du Colombier }
151*8ccd4a63SDavid du Colombier 
152*8ccd4a63SDavid du Colombier int
153*8ccd4a63SDavid du Colombier emptystr(char *s)
154*8ccd4a63SDavid du Colombier {
155*8ccd4a63SDavid du Colombier 	if(s == nil)
156*8ccd4a63SDavid du Colombier 		return 1;
157*8ccd4a63SDavid du Colombier 	if(s[0] == '\0')
158*8ccd4a63SDavid du Colombier 		return 1;
159*8ccd4a63SDavid du Colombier 	return 0;
160*8ccd4a63SDavid du Colombier }
161*8ccd4a63SDavid du Colombier 
162*8ccd4a63SDavid du Colombier /*
163*8ccd4a63SDavid du Colombier  * Atomically replace *p with copy of s
164*8ccd4a63SDavid du Colombier  */
165*8ccd4a63SDavid du Colombier void
166*8ccd4a63SDavid du Colombier kstrdup(char **p, char *s)
167*8ccd4a63SDavid du Colombier {
168*8ccd4a63SDavid du Colombier 	int n;
169*8ccd4a63SDavid du Colombier 	char *t, *prev;
170*8ccd4a63SDavid du Colombier 
171*8ccd4a63SDavid du Colombier 	n = strlen(s)+1;
172*8ccd4a63SDavid du Colombier 	/* if it's a user, we can wait for memory; if not, something's very wrong */
173*8ccd4a63SDavid du Colombier 	if(up){
174*8ccd4a63SDavid du Colombier 		t = smalloc(n);
175*8ccd4a63SDavid du Colombier 		setmalloctag(t, getcallerpc(&p));
176*8ccd4a63SDavid du Colombier 	}else{
177*8ccd4a63SDavid du Colombier 		t = malloc(n);
178*8ccd4a63SDavid du Colombier 		if(t == nil)
179*8ccd4a63SDavid du Colombier 			panic("kstrdup: no memory");
180*8ccd4a63SDavid du Colombier 	}
181*8ccd4a63SDavid du Colombier 	memmove(t, s, n);
182*8ccd4a63SDavid du Colombier 	prev = *p;
183*8ccd4a63SDavid du Colombier 	*p = t;
184*8ccd4a63SDavid du Colombier 	free(prev);
185*8ccd4a63SDavid du Colombier }
186*8ccd4a63SDavid du Colombier 
187*8ccd4a63SDavid du Colombier void
188*8ccd4a63SDavid du Colombier chandevreset(void)
189*8ccd4a63SDavid du Colombier {
190*8ccd4a63SDavid du Colombier 	int i;
191*8ccd4a63SDavid du Colombier 
192*8ccd4a63SDavid du Colombier 	for(i=0; devtab[i] != nil; i++)
193*8ccd4a63SDavid du Colombier 		devtab[i]->reset();
194*8ccd4a63SDavid du Colombier }
195*8ccd4a63SDavid du Colombier 
196*8ccd4a63SDavid du Colombier void
197*8ccd4a63SDavid du Colombier chandevinit(void)
198*8ccd4a63SDavid du Colombier {
199*8ccd4a63SDavid du Colombier 	int i;
200*8ccd4a63SDavid du Colombier 
201*8ccd4a63SDavid du Colombier 	for(i=0; devtab[i] != nil; i++)
202*8ccd4a63SDavid du Colombier 		devtab[i]->init();
203*8ccd4a63SDavid du Colombier }
204*8ccd4a63SDavid du Colombier 
205*8ccd4a63SDavid du Colombier void
206*8ccd4a63SDavid du Colombier chandevshutdown(void)
207*8ccd4a63SDavid du Colombier {
208*8ccd4a63SDavid du Colombier 	int i;
209*8ccd4a63SDavid du Colombier 
210*8ccd4a63SDavid du Colombier 	/* shutdown in reverse order */
211*8ccd4a63SDavid du Colombier 	for(i=0; devtab[i] != nil; i++)
212*8ccd4a63SDavid du Colombier 		;
213*8ccd4a63SDavid du Colombier 	for(i--; i >= 0; i--)
214*8ccd4a63SDavid du Colombier 		devtab[i]->shutdown();
215*8ccd4a63SDavid du Colombier }
216*8ccd4a63SDavid du Colombier 
217*8ccd4a63SDavid du Colombier Chan*
218*8ccd4a63SDavid du Colombier newchan(void)
219*8ccd4a63SDavid du Colombier {
220*8ccd4a63SDavid du Colombier 	Chan *c;
221*8ccd4a63SDavid du Colombier 
222*8ccd4a63SDavid du Colombier 	lock(&chanalloc.lk);
223*8ccd4a63SDavid du Colombier 	c = chanalloc.free;
224*8ccd4a63SDavid du Colombier 	if(c != 0)
225*8ccd4a63SDavid du Colombier 		chanalloc.free = c->next;
226*8ccd4a63SDavid du Colombier 	unlock(&chanalloc.lk);
227*8ccd4a63SDavid du Colombier 
228*8ccd4a63SDavid du Colombier 	if(c == nil) {
229*8ccd4a63SDavid du Colombier 		c = smalloc(sizeof(Chan));
230*8ccd4a63SDavid du Colombier 		lock(&chanalloc.lk);
231*8ccd4a63SDavid du Colombier 		c->fid = ++chanalloc.fid;
232*8ccd4a63SDavid du Colombier 		c->link = chanalloc.list;
233*8ccd4a63SDavid du Colombier 		chanalloc.list = c;
234*8ccd4a63SDavid du Colombier 		unlock(&chanalloc.lk);
235*8ccd4a63SDavid du Colombier 	}
236*8ccd4a63SDavid du Colombier 
237*8ccd4a63SDavid du Colombier 	/* if you get an error before associating with a dev,
238*8ccd4a63SDavid du Colombier 	   close calls rootclose, a nop */
239*8ccd4a63SDavid du Colombier 	c->type = 0;
240*8ccd4a63SDavid du Colombier 	c->flag = 0;
241*8ccd4a63SDavid du Colombier 	c->ref.ref = 1;
242*8ccd4a63SDavid du Colombier 	c->dev = 0;
243*8ccd4a63SDavid du Colombier 	c->offset = 0;
244*8ccd4a63SDavid du Colombier 	c->iounit = 0;
245*8ccd4a63SDavid du Colombier 	c->umh = 0;
246*8ccd4a63SDavid du Colombier 	c->uri = 0;
247*8ccd4a63SDavid du Colombier 	c->dri = 0;
248*8ccd4a63SDavid du Colombier 	c->aux = 0;
249*8ccd4a63SDavid du Colombier 	c->mchan = 0;
250*8ccd4a63SDavid du Colombier 	c->mcp = 0;
251*8ccd4a63SDavid du Colombier 	c->mux = 0;
252*8ccd4a63SDavid du Colombier 	memset(&c->mqid, 0, sizeof(c->mqid));
253*8ccd4a63SDavid du Colombier 	c->name = 0;
254*8ccd4a63SDavid du Colombier 	return c;
255*8ccd4a63SDavid du Colombier }
256*8ccd4a63SDavid du Colombier 
257*8ccd4a63SDavid du Colombier static Ref ncname;
258*8ccd4a63SDavid du Colombier 
259*8ccd4a63SDavid du Colombier Cname*
260*8ccd4a63SDavid du Colombier newcname(char *s)
261*8ccd4a63SDavid du Colombier {
262*8ccd4a63SDavid du Colombier 	Cname *n;
263*8ccd4a63SDavid du Colombier 	int i;
264*8ccd4a63SDavid du Colombier 
265*8ccd4a63SDavid du Colombier 	n = smalloc(sizeof(Cname));
266*8ccd4a63SDavid du Colombier 	i = strlen(s);
267*8ccd4a63SDavid du Colombier 	n->len = i;
268*8ccd4a63SDavid du Colombier 	n->alen = i+CNAMESLOP;
269*8ccd4a63SDavid du Colombier 	n->s = smalloc(n->alen);
270*8ccd4a63SDavid du Colombier 	memmove(n->s, s, i+1);
271*8ccd4a63SDavid du Colombier 	n->ref.ref = 1;
272*8ccd4a63SDavid du Colombier 	incref(&ncname);
273*8ccd4a63SDavid du Colombier 	return n;
274*8ccd4a63SDavid du Colombier }
275*8ccd4a63SDavid du Colombier 
276*8ccd4a63SDavid du Colombier void
277*8ccd4a63SDavid du Colombier cnameclose(Cname *n)
278*8ccd4a63SDavid du Colombier {
279*8ccd4a63SDavid du Colombier 	if(n == nil)
280*8ccd4a63SDavid du Colombier 		return;
281*8ccd4a63SDavid du Colombier 	if(decref(&n->ref))
282*8ccd4a63SDavid du Colombier 		return;
283*8ccd4a63SDavid du Colombier 	decref(&ncname);
284*8ccd4a63SDavid du Colombier 	free(n->s);
285*8ccd4a63SDavid du Colombier 	free(n);
286*8ccd4a63SDavid du Colombier }
287*8ccd4a63SDavid du Colombier 
288*8ccd4a63SDavid du Colombier Cname*
289*8ccd4a63SDavid du Colombier addelem(Cname *n, char *s)
290*8ccd4a63SDavid du Colombier {
291*8ccd4a63SDavid du Colombier 	int i, a;
292*8ccd4a63SDavid du Colombier 	char *t;
293*8ccd4a63SDavid du Colombier 	Cname *new;
294*8ccd4a63SDavid du Colombier 
295*8ccd4a63SDavid du Colombier 	if(s[0]=='.' && s[1]=='\0')
296*8ccd4a63SDavid du Colombier 		return n;
297*8ccd4a63SDavid du Colombier 
298*8ccd4a63SDavid du Colombier 	if(n->ref.ref > 1){
299*8ccd4a63SDavid du Colombier 		/* copy on write */
300*8ccd4a63SDavid du Colombier 		new = newcname(n->s);
301*8ccd4a63SDavid du Colombier 		cnameclose(n);
302*8ccd4a63SDavid du Colombier 		n = new;
303*8ccd4a63SDavid du Colombier 	}
304*8ccd4a63SDavid du Colombier 
305*8ccd4a63SDavid du Colombier 	i = strlen(s);
306*8ccd4a63SDavid du Colombier 	if(n->len+1+i+1 > n->alen){
307*8ccd4a63SDavid du Colombier 		a = n->len+1+i+1 + CNAMESLOP;
308*8ccd4a63SDavid du Colombier 		t = smalloc(a);
309*8ccd4a63SDavid du Colombier 		memmove(t, n->s, n->len+1);
310*8ccd4a63SDavid du Colombier 		free(n->s);
311*8ccd4a63SDavid du Colombier 		n->s = t;
312*8ccd4a63SDavid du Colombier 		n->alen = a;
313*8ccd4a63SDavid du Colombier 	}
314*8ccd4a63SDavid du Colombier 	if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')	/* don't insert extra slash if one is present */
315*8ccd4a63SDavid du Colombier 		n->s[n->len++] = '/';
316*8ccd4a63SDavid du Colombier 	memmove(n->s+n->len, s, i+1);
317*8ccd4a63SDavid du Colombier 	n->len += i;
318*8ccd4a63SDavid du Colombier 	if(isdotdot(s))
319*8ccd4a63SDavid du Colombier 		cleancname(n);
320*8ccd4a63SDavid du Colombier 	return n;
321*8ccd4a63SDavid du Colombier }
322*8ccd4a63SDavid du Colombier 
323*8ccd4a63SDavid du Colombier void
324*8ccd4a63SDavid du Colombier chanfree(Chan *c)
325*8ccd4a63SDavid du Colombier {
326*8ccd4a63SDavid du Colombier 	c->flag = CFREE;
327*8ccd4a63SDavid du Colombier 
328*8ccd4a63SDavid du Colombier 	if(c->umh != nil){
329*8ccd4a63SDavid du Colombier 		putmhead(c->umh);
330*8ccd4a63SDavid du Colombier 		c->umh = nil;
331*8ccd4a63SDavid du Colombier 	}
332*8ccd4a63SDavid du Colombier 	if(c->umc != nil){
333*8ccd4a63SDavid du Colombier 		cclose(c->umc);
334*8ccd4a63SDavid du Colombier 		c->umc = nil;
335*8ccd4a63SDavid du Colombier 	}
336*8ccd4a63SDavid du Colombier 	if(c->mux != nil){
337*8ccd4a63SDavid du Colombier 		muxclose(c->mux);
338*8ccd4a63SDavid du Colombier 		c->mux = nil;
339*8ccd4a63SDavid du Colombier 	}
340*8ccd4a63SDavid du Colombier 	if(c->mchan != nil){
341*8ccd4a63SDavid du Colombier 		cclose(c->mchan);
342*8ccd4a63SDavid du Colombier 		c->mchan = nil;
343*8ccd4a63SDavid du Colombier 	}
344*8ccd4a63SDavid du Colombier 
345*8ccd4a63SDavid du Colombier 	cnameclose(c->name);
346*8ccd4a63SDavid du Colombier 
347*8ccd4a63SDavid du Colombier 	lock(&chanalloc.lk);
348*8ccd4a63SDavid du Colombier 	c->next = chanalloc.free;
349*8ccd4a63SDavid du Colombier 	chanalloc.free = c;
350*8ccd4a63SDavid du Colombier 	unlock(&chanalloc.lk);
351*8ccd4a63SDavid du Colombier }
352*8ccd4a63SDavid du Colombier 
353*8ccd4a63SDavid du Colombier void
354*8ccd4a63SDavid du Colombier cclose(Chan *c)
355*8ccd4a63SDavid du Colombier {
356*8ccd4a63SDavid du Colombier 	if(c->flag&CFREE)
357*8ccd4a63SDavid du Colombier 		panic("cclose %lux", getcallerpc(&c));
358*8ccd4a63SDavid du Colombier 
359*8ccd4a63SDavid du Colombier 	if(decref(&c->ref))
360*8ccd4a63SDavid du Colombier 		return;
361*8ccd4a63SDavid du Colombier 
362*8ccd4a63SDavid du Colombier 	if(!waserror()){
363*8ccd4a63SDavid du Colombier 		devtab[c->type]->close(c);
364*8ccd4a63SDavid du Colombier 		poperror();
365*8ccd4a63SDavid du Colombier 	}
366*8ccd4a63SDavid du Colombier 	chanfree(c);
367*8ccd4a63SDavid du Colombier }
368*8ccd4a63SDavid du Colombier 
369*8ccd4a63SDavid du Colombier /*
370*8ccd4a63SDavid du Colombier  * Make sure we have the only copy of c.  (Copy on write.)
371*8ccd4a63SDavid du Colombier  */
372*8ccd4a63SDavid du Colombier Chan*
373*8ccd4a63SDavid du Colombier cunique(Chan *c)
374*8ccd4a63SDavid du Colombier {
375*8ccd4a63SDavid du Colombier 	Chan *nc;
376*8ccd4a63SDavid du Colombier 
377*8ccd4a63SDavid du Colombier 	if(c->ref.ref != 1) {
378*8ccd4a63SDavid du Colombier 		nc = cclone(c);
379*8ccd4a63SDavid du Colombier 		cclose(c);
380*8ccd4a63SDavid du Colombier 		c = nc;
381*8ccd4a63SDavid du Colombier 	}
382*8ccd4a63SDavid du Colombier 
383*8ccd4a63SDavid du Colombier 	return c;
384*8ccd4a63SDavid du Colombier }
385*8ccd4a63SDavid du Colombier 
386*8ccd4a63SDavid du Colombier int
387*8ccd4a63SDavid du Colombier eqqid(Qid a, Qid b)
388*8ccd4a63SDavid du Colombier {
389*8ccd4a63SDavid du Colombier 	return a.path==b.path && a.vers==b.vers;
390*8ccd4a63SDavid du Colombier }
391*8ccd4a63SDavid du Colombier 
392*8ccd4a63SDavid du Colombier int
393*8ccd4a63SDavid du Colombier eqchan(Chan *a, Chan *b, int pathonly)
394*8ccd4a63SDavid du Colombier {
395*8ccd4a63SDavid du Colombier 	if(a->qid.path != b->qid.path)
396*8ccd4a63SDavid du Colombier 		return 0;
397*8ccd4a63SDavid du Colombier 	if(!pathonly && a->qid.vers!=b->qid.vers)
398*8ccd4a63SDavid du Colombier 		return 0;
399*8ccd4a63SDavid du Colombier 	if(a->type != b->type)
400*8ccd4a63SDavid du Colombier 		return 0;
401*8ccd4a63SDavid du Colombier 	if(a->dev != b->dev)
402*8ccd4a63SDavid du Colombier 		return 0;
403*8ccd4a63SDavid du Colombier 	return 1;
404*8ccd4a63SDavid du Colombier }
405*8ccd4a63SDavid du Colombier 
406*8ccd4a63SDavid du Colombier int
407*8ccd4a63SDavid du Colombier eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly)
408*8ccd4a63SDavid du Colombier {
409*8ccd4a63SDavid du Colombier 	if(a->qid.path != qid.path)
410*8ccd4a63SDavid du Colombier 		return 0;
411*8ccd4a63SDavid du Colombier 	if(!pathonly && a->qid.vers!=qid.vers)
412*8ccd4a63SDavid du Colombier 		return 0;
413*8ccd4a63SDavid du Colombier 	if(a->type != type)
414*8ccd4a63SDavid du Colombier 		return 0;
415*8ccd4a63SDavid du Colombier 	if(a->dev != dev)
416*8ccd4a63SDavid du Colombier 		return 0;
417*8ccd4a63SDavid du Colombier 	return 1;
418*8ccd4a63SDavid du Colombier }
419*8ccd4a63SDavid du Colombier 
420*8ccd4a63SDavid du Colombier Mhead*
421*8ccd4a63SDavid du Colombier newmhead(Chan *from)
422*8ccd4a63SDavid du Colombier {
423*8ccd4a63SDavid du Colombier 	Mhead *mh;
424*8ccd4a63SDavid du Colombier 
425*8ccd4a63SDavid du Colombier 	mh = smalloc(sizeof(Mhead));
426*8ccd4a63SDavid du Colombier 	mh->ref.ref = 1;
427*8ccd4a63SDavid du Colombier 	mh->from = from;
428*8ccd4a63SDavid du Colombier 	incref(&from->ref);
429*8ccd4a63SDavid du Colombier 
430*8ccd4a63SDavid du Colombier /*
431*8ccd4a63SDavid du Colombier 	n = from->name->len;
432*8ccd4a63SDavid du Colombier 	if(n >= sizeof(mh->fromname))
433*8ccd4a63SDavid du Colombier 		n = sizeof(mh->fromname)-1;
434*8ccd4a63SDavid du Colombier 	memmove(mh->fromname, from->name->s, n);
435*8ccd4a63SDavid du Colombier 	mh->fromname[n] = 0;
436*8ccd4a63SDavid du Colombier */
437*8ccd4a63SDavid du Colombier 	return mh;
438*8ccd4a63SDavid du Colombier }
439*8ccd4a63SDavid du Colombier 
440*8ccd4a63SDavid du Colombier int
441*8ccd4a63SDavid du Colombier cmount(Chan **newp, Chan *old, int flag, char *spec)
442*8ccd4a63SDavid du Colombier {
443*8ccd4a63SDavid du Colombier 	Pgrp *pg;
444*8ccd4a63SDavid du Colombier 	int order, flg;
445*8ccd4a63SDavid du Colombier 	Mhead *m, **l, *mh;
446*8ccd4a63SDavid du Colombier 	Mount *nm, *f, *um, **h;
447*8ccd4a63SDavid du Colombier 	Chan *new;
448*8ccd4a63SDavid du Colombier 
449*8ccd4a63SDavid du Colombier 	if(QTDIR & (old->qid.type^(*newp)->qid.type))
450*8ccd4a63SDavid du Colombier 		error(Emount);
451*8ccd4a63SDavid du Colombier 
452*8ccd4a63SDavid du Colombier if(old->umh)print("cmount old extra umh\n");
453*8ccd4a63SDavid du Colombier 
454*8ccd4a63SDavid du Colombier 	order = flag&MORDER;
455*8ccd4a63SDavid du Colombier 
456*8ccd4a63SDavid du Colombier 	if((old->qid.type&QTDIR)==0 && order != MREPL)
457*8ccd4a63SDavid du Colombier 		error(Emount);
458*8ccd4a63SDavid du Colombier 
459*8ccd4a63SDavid du Colombier 	new = *newp;
460*8ccd4a63SDavid du Colombier 	mh = new->umh;
461*8ccd4a63SDavid du Colombier 
462*8ccd4a63SDavid du Colombier 	/*
463*8ccd4a63SDavid du Colombier 	 * Not allowed to bind when the old directory
464*8ccd4a63SDavid du Colombier 	 * is itself a union.  (Maybe it should be allowed, but I don't see
465*8ccd4a63SDavid du Colombier 	 * what the semantics would be.)
466*8ccd4a63SDavid du Colombier 	 *
467*8ccd4a63SDavid du Colombier 	 * We need to check mh->mount->next to tell unions apart from
468*8ccd4a63SDavid du Colombier 	 * simple mount points, so that things like
469*8ccd4a63SDavid du Colombier 	 *	mount -c fd /root
470*8ccd4a63SDavid du Colombier 	 *	bind -c /root /
471*8ccd4a63SDavid du Colombier 	 * work.  The check of mount->mflag catches things like
472*8ccd4a63SDavid du Colombier 	 *	mount fd /root
473*8ccd4a63SDavid du Colombier 	 *	bind -c /root /
474*8ccd4a63SDavid du Colombier 	 *
475*8ccd4a63SDavid du Colombier 	 * This is far more complicated than it should be, but I don't
476*8ccd4a63SDavid du Colombier 	 * see an easier way at the moment.		-rsc
477*8ccd4a63SDavid du Colombier 	 */
478*8ccd4a63SDavid du Colombier 	if((flag&MCREATE) && mh && mh->mount
479*8ccd4a63SDavid du Colombier 	&& (mh->mount->next || !(mh->mount->mflag&MCREATE)))
480*8ccd4a63SDavid du Colombier 		error(Emount);
481*8ccd4a63SDavid du Colombier 
482*8ccd4a63SDavid du Colombier 	pg = up->pgrp;
483*8ccd4a63SDavid du Colombier 	wlock(&pg->ns);
484*8ccd4a63SDavid du Colombier 
485*8ccd4a63SDavid du Colombier 	l = &MOUNTH(pg, old->qid);
486*8ccd4a63SDavid du Colombier 	for(m = *l; m; m = m->hash) {
487*8ccd4a63SDavid du Colombier 		if(eqchan(m->from, old, 1))
488*8ccd4a63SDavid du Colombier 			break;
489*8ccd4a63SDavid du Colombier 		l = &m->hash;
490*8ccd4a63SDavid du Colombier 	}
491*8ccd4a63SDavid du Colombier 
492*8ccd4a63SDavid du Colombier 	if(m == nil) {
493*8ccd4a63SDavid du Colombier 		/*
494*8ccd4a63SDavid du Colombier 		 *  nothing mounted here yet.  create a mount
495*8ccd4a63SDavid du Colombier 		 *  head and add to the hash table.
496*8ccd4a63SDavid du Colombier 		 */
497*8ccd4a63SDavid du Colombier 		m = newmhead(old);
498*8ccd4a63SDavid du Colombier 		*l = m;
499*8ccd4a63SDavid du Colombier 
500*8ccd4a63SDavid du Colombier 		/*
501*8ccd4a63SDavid du Colombier 		 *  if this is a union mount, add the old
502*8ccd4a63SDavid du Colombier 		 *  node to the mount chain.
503*8ccd4a63SDavid du Colombier 		 */
504*8ccd4a63SDavid du Colombier 		if(order != MREPL)
505*8ccd4a63SDavid du Colombier 			m->mount = newmount(m, old, 0, 0);
506*8ccd4a63SDavid du Colombier 	}
507*8ccd4a63SDavid du Colombier 	wlock(&m->lock);
508*8ccd4a63SDavid du Colombier 	if(waserror()){
509*8ccd4a63SDavid du Colombier 		wunlock(&m->lock);
510*8ccd4a63SDavid du Colombier 		nexterror();
511*8ccd4a63SDavid du Colombier 	}
512*8ccd4a63SDavid du Colombier 	wunlock(&pg->ns);
513*8ccd4a63SDavid du Colombier 
514*8ccd4a63SDavid du Colombier 	nm = newmount(m, new, flag, spec);
515*8ccd4a63SDavid du Colombier 	if(mh != nil && mh->mount != nil) {
516*8ccd4a63SDavid du Colombier 		/*
517*8ccd4a63SDavid du Colombier 		 *  copy a union when binding it onto a directory
518*8ccd4a63SDavid du Colombier 		 */
519*8ccd4a63SDavid du Colombier 		flg = order;
520*8ccd4a63SDavid du Colombier 		if(order == MREPL)
521*8ccd4a63SDavid du Colombier 			flg = MAFTER;
522*8ccd4a63SDavid du Colombier 		h = &nm->next;
523*8ccd4a63SDavid du Colombier 		um = mh->mount;
524*8ccd4a63SDavid du Colombier 		for(um = um->next; um; um = um->next) {
525*8ccd4a63SDavid du Colombier 			f = newmount(m, um->to, flg, um->spec);
526*8ccd4a63SDavid du Colombier 			*h = f;
527*8ccd4a63SDavid du Colombier 			h = &f->next;
528*8ccd4a63SDavid du Colombier 		}
529*8ccd4a63SDavid du Colombier 	}
530*8ccd4a63SDavid du Colombier 
531*8ccd4a63SDavid du Colombier 	if(m->mount && order == MREPL) {
532*8ccd4a63SDavid du Colombier 		mountfree(m->mount);
533*8ccd4a63SDavid du Colombier 		m->mount = 0;
534*8ccd4a63SDavid du Colombier 	}
535*8ccd4a63SDavid du Colombier 
536*8ccd4a63SDavid du Colombier 	if(flag & MCREATE)
537*8ccd4a63SDavid du Colombier 		nm->mflag |= MCREATE;
538*8ccd4a63SDavid du Colombier 
539*8ccd4a63SDavid du Colombier 	if(m->mount && order == MAFTER) {
540*8ccd4a63SDavid du Colombier 		for(f = m->mount; f->next; f = f->next)
541*8ccd4a63SDavid du Colombier 			;
542*8ccd4a63SDavid du Colombier 		f->next = nm;
543*8ccd4a63SDavid du Colombier 	}
544*8ccd4a63SDavid du Colombier 	else {
545*8ccd4a63SDavid du Colombier 		for(f = nm; f->next; f = f->next)
546*8ccd4a63SDavid du Colombier 			;
547*8ccd4a63SDavid du Colombier 		f->next = m->mount;
548*8ccd4a63SDavid du Colombier 		m->mount = nm;
549*8ccd4a63SDavid du Colombier 	}
550*8ccd4a63SDavid du Colombier 
551*8ccd4a63SDavid du Colombier 	wunlock(&m->lock);
552*8ccd4a63SDavid du Colombier 	poperror();
553*8ccd4a63SDavid du Colombier 	return nm->mountid;
554*8ccd4a63SDavid du Colombier }
555*8ccd4a63SDavid du Colombier 
556*8ccd4a63SDavid du Colombier void
557*8ccd4a63SDavid du Colombier cunmount(Chan *mnt, Chan *mounted)
558*8ccd4a63SDavid du Colombier {
559*8ccd4a63SDavid du Colombier 	Pgrp *pg;
560*8ccd4a63SDavid du Colombier 	Mhead *m, **l;
561*8ccd4a63SDavid du Colombier 	Mount *f, **p;
562*8ccd4a63SDavid du Colombier 
563*8ccd4a63SDavid du Colombier 	if(mnt->umh)	/* should not happen */
564*8ccd4a63SDavid du Colombier 		print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
565*8ccd4a63SDavid du Colombier 
566*8ccd4a63SDavid du Colombier 	/*
567*8ccd4a63SDavid du Colombier 	 * It _can_ happen that mounted->umh is non-nil,
568*8ccd4a63SDavid du Colombier 	 * because mounted is the result of namec(Aopen)
569*8ccd4a63SDavid du Colombier 	 * (see sysfile.c:/^sysunmount).
570*8ccd4a63SDavid du Colombier 	 * If we open a union directory, it will have a umh.
571*8ccd4a63SDavid du Colombier 	 * Although surprising, this is okay, since the
572*8ccd4a63SDavid du Colombier 	 * cclose will take care of freeing the umh.
573*8ccd4a63SDavid du Colombier 	 */
574*8ccd4a63SDavid du Colombier 
575*8ccd4a63SDavid du Colombier 	pg = up->pgrp;
576*8ccd4a63SDavid du Colombier 	wlock(&pg->ns);
577*8ccd4a63SDavid du Colombier 
578*8ccd4a63SDavid du Colombier 	l = &MOUNTH(pg, mnt->qid);
579*8ccd4a63SDavid du Colombier 	for(m = *l; m; m = m->hash) {
580*8ccd4a63SDavid du Colombier 		if(eqchan(m->from, mnt, 1))
581*8ccd4a63SDavid du Colombier 			break;
582*8ccd4a63SDavid du Colombier 		l = &m->hash;
583*8ccd4a63SDavid du Colombier 	}
584*8ccd4a63SDavid du Colombier 
585*8ccd4a63SDavid du Colombier 	if(m == 0) {
586*8ccd4a63SDavid du Colombier 		wunlock(&pg->ns);
587*8ccd4a63SDavid du Colombier 		error(Eunmount);
588*8ccd4a63SDavid du Colombier 	}
589*8ccd4a63SDavid du Colombier 
590*8ccd4a63SDavid du Colombier 	wlock(&m->lock);
591*8ccd4a63SDavid du Colombier 	if(mounted == 0) {
592*8ccd4a63SDavid du Colombier 		*l = m->hash;
593*8ccd4a63SDavid du Colombier 		wunlock(&pg->ns);
594*8ccd4a63SDavid du Colombier 		mountfree(m->mount);
595*8ccd4a63SDavid du Colombier 		m->mount = nil;
596*8ccd4a63SDavid du Colombier 		cclose(m->from);
597*8ccd4a63SDavid du Colombier 		wunlock(&m->lock);
598*8ccd4a63SDavid du Colombier 		putmhead(m);
599*8ccd4a63SDavid du Colombier 		return;
600*8ccd4a63SDavid du Colombier 	}
601*8ccd4a63SDavid du Colombier 
602*8ccd4a63SDavid du Colombier 	p = &m->mount;
603*8ccd4a63SDavid du Colombier 	for(f = *p; f; f = f->next) {
604*8ccd4a63SDavid du Colombier 		/* BUG: Needs to be 2 pass */
605*8ccd4a63SDavid du Colombier 		if(eqchan(f->to, mounted, 1) ||
606*8ccd4a63SDavid du Colombier 		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) {
607*8ccd4a63SDavid du Colombier 			*p = f->next;
608*8ccd4a63SDavid du Colombier 			f->next = 0;
609*8ccd4a63SDavid du Colombier 			mountfree(f);
610*8ccd4a63SDavid du Colombier 			if(m->mount == nil) {
611*8ccd4a63SDavid du Colombier 				*l = m->hash;
612*8ccd4a63SDavid du Colombier 				cclose(m->from);
613*8ccd4a63SDavid du Colombier 				wunlock(&m->lock);
614*8ccd4a63SDavid du Colombier 				wunlock(&pg->ns);
615*8ccd4a63SDavid du Colombier 				putmhead(m);
616*8ccd4a63SDavid du Colombier 				return;
617*8ccd4a63SDavid du Colombier 			}
618*8ccd4a63SDavid du Colombier 			wunlock(&m->lock);
619*8ccd4a63SDavid du Colombier 			wunlock(&pg->ns);
620*8ccd4a63SDavid du Colombier 			return;
621*8ccd4a63SDavid du Colombier 		}
622*8ccd4a63SDavid du Colombier 		p = &f->next;
623*8ccd4a63SDavid du Colombier 	}
624*8ccd4a63SDavid du Colombier 	wunlock(&m->lock);
625*8ccd4a63SDavid du Colombier 	wunlock(&pg->ns);
626*8ccd4a63SDavid du Colombier 	error(Eunion);
627*8ccd4a63SDavid du Colombier }
628*8ccd4a63SDavid du Colombier 
629*8ccd4a63SDavid du Colombier Chan*
630*8ccd4a63SDavid du Colombier cclone(Chan *c)
631*8ccd4a63SDavid du Colombier {
632*8ccd4a63SDavid du Colombier 	Chan *nc;
633*8ccd4a63SDavid du Colombier 	Walkqid *wq;
634*8ccd4a63SDavid du Colombier 
635*8ccd4a63SDavid du Colombier 	wq = devtab[c->type]->walk(c, nil, nil, 0);
636*8ccd4a63SDavid du Colombier 	if(wq == nil)
637*8ccd4a63SDavid du Colombier 		error("clone failed");
638*8ccd4a63SDavid du Colombier 	nc = wq->clone;
639*8ccd4a63SDavid du Colombier 	free(wq);
640*8ccd4a63SDavid du Colombier 	nc->name = c->name;
641*8ccd4a63SDavid du Colombier 	if(c->name)
642*8ccd4a63SDavid du Colombier 		incref(&c->name->ref);
643*8ccd4a63SDavid du Colombier 	return nc;
644*8ccd4a63SDavid du Colombier }
645*8ccd4a63SDavid du Colombier 
646*8ccd4a63SDavid du Colombier int
647*8ccd4a63SDavid du Colombier findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
648*8ccd4a63SDavid du Colombier {
649*8ccd4a63SDavid du Colombier 	Pgrp *pg;
650*8ccd4a63SDavid du Colombier 	Mhead *m;
651*8ccd4a63SDavid du Colombier 
652*8ccd4a63SDavid du Colombier 	pg = up->pgrp;
653*8ccd4a63SDavid du Colombier 	rlock(&pg->ns);
654*8ccd4a63SDavid du Colombier 	for(m = MOUNTH(pg, qid); m; m = m->hash){
655*8ccd4a63SDavid du Colombier 		rlock(&m->lock);
656*8ccd4a63SDavid du Colombier if(m->from == nil){
657*8ccd4a63SDavid du Colombier 	print("m %p m->from 0\n", m);
658*8ccd4a63SDavid du Colombier 	runlock(&m->lock);
659*8ccd4a63SDavid du Colombier 	continue;
660*8ccd4a63SDavid du Colombier }
661*8ccd4a63SDavid du Colombier 		if(eqchantdqid(m->from, type, dev, qid, 1)) {
662*8ccd4a63SDavid du Colombier 			runlock(&pg->ns);
663*8ccd4a63SDavid du Colombier 			if(mp != nil){
664*8ccd4a63SDavid du Colombier 				incref(&m->ref);
665*8ccd4a63SDavid du Colombier 				if(*mp != nil)
666*8ccd4a63SDavid du Colombier 					putmhead(*mp);
667*8ccd4a63SDavid du Colombier 				*mp = m;
668*8ccd4a63SDavid du Colombier 			}
669*8ccd4a63SDavid du Colombier 			if(*cp != nil)
670*8ccd4a63SDavid du Colombier 				cclose(*cp);
671*8ccd4a63SDavid du Colombier 			incref(&m->mount->to->ref);
672*8ccd4a63SDavid du Colombier 			*cp = m->mount->to;
673*8ccd4a63SDavid du Colombier 			runlock(&m->lock);
674*8ccd4a63SDavid du Colombier 			return 1;
675*8ccd4a63SDavid du Colombier 		}
676*8ccd4a63SDavid du Colombier 		runlock(&m->lock);
677*8ccd4a63SDavid du Colombier 	}
678*8ccd4a63SDavid du Colombier 
679*8ccd4a63SDavid du Colombier 	runlock(&pg->ns);
680*8ccd4a63SDavid du Colombier 	return 0;
681*8ccd4a63SDavid du Colombier }
682*8ccd4a63SDavid du Colombier 
683*8ccd4a63SDavid du Colombier int
684*8ccd4a63SDavid du Colombier domount(Chan **cp, Mhead **mp)
685*8ccd4a63SDavid du Colombier {
686*8ccd4a63SDavid du Colombier 	return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);
687*8ccd4a63SDavid du Colombier }
688*8ccd4a63SDavid du Colombier 
689*8ccd4a63SDavid du Colombier Chan*
690*8ccd4a63SDavid du Colombier undomount(Chan *c, Cname *name)
691*8ccd4a63SDavid du Colombier {
692*8ccd4a63SDavid du Colombier 	Chan *nc;
693*8ccd4a63SDavid du Colombier 	Pgrp *pg;
694*8ccd4a63SDavid du Colombier 	Mount *t;
695*8ccd4a63SDavid du Colombier 	Mhead **h, **he, *f;
696*8ccd4a63SDavid du Colombier 
697*8ccd4a63SDavid du Colombier 	pg = up->pgrp;
698*8ccd4a63SDavid du Colombier 	rlock(&pg->ns);
699*8ccd4a63SDavid du Colombier 	if(waserror()) {
700*8ccd4a63SDavid du Colombier 		runlock(&pg->ns);
701*8ccd4a63SDavid du Colombier 		nexterror();
702*8ccd4a63SDavid du Colombier 	}
703*8ccd4a63SDavid du Colombier 
704*8ccd4a63SDavid du Colombier 	he = &pg->mnthash[MNTHASH];
705*8ccd4a63SDavid du Colombier 	for(h = pg->mnthash; h < he; h++) {
706*8ccd4a63SDavid du Colombier 		for(f = *h; f; f = f->hash) {
707*8ccd4a63SDavid du Colombier 			if(strcmp(f->from->name->s, name->s) != 0)
708*8ccd4a63SDavid du Colombier 				continue;
709*8ccd4a63SDavid du Colombier 			for(t = f->mount; t; t = t->next) {
710*8ccd4a63SDavid du Colombier 				if(eqchan(c, t->to, 1)) {
711*8ccd4a63SDavid du Colombier 					/*
712*8ccd4a63SDavid du Colombier 					 * We want to come out on the left hand side of the mount
713*8ccd4a63SDavid du Colombier 					 * point using the element of the union that we entered on.
714*8ccd4a63SDavid du Colombier 					 * To do this, find the element that has a from name of
715*8ccd4a63SDavid du Colombier 					 * c->name->s.
716*8ccd4a63SDavid du Colombier 					 */
717*8ccd4a63SDavid du Colombier 					if(strcmp(t->head->from->name->s, name->s) != 0)
718*8ccd4a63SDavid du Colombier 						continue;
719*8ccd4a63SDavid du Colombier 					nc = t->head->from;
720*8ccd4a63SDavid du Colombier 					incref(&nc->ref);
721*8ccd4a63SDavid du Colombier 					cclose(c);
722*8ccd4a63SDavid du Colombier 					c = nc;
723*8ccd4a63SDavid du Colombier 					break;
724*8ccd4a63SDavid du Colombier 				}
725*8ccd4a63SDavid du Colombier 			}
726*8ccd4a63SDavid du Colombier 		}
727*8ccd4a63SDavid du Colombier 	}
728*8ccd4a63SDavid du Colombier 	poperror();
729*8ccd4a63SDavid du Colombier 	runlock(&pg->ns);
730*8ccd4a63SDavid du Colombier 	return c;
731*8ccd4a63SDavid du Colombier }
732*8ccd4a63SDavid du Colombier 
733*8ccd4a63SDavid du Colombier /*
734*8ccd4a63SDavid du Colombier  * Either walks all the way or not at all.  No partial results in *cp.
735*8ccd4a63SDavid du Colombier  * *nerror is the number of names to display in an error message.
736*8ccd4a63SDavid du Colombier  */
737*8ccd4a63SDavid du Colombier static char Edoesnotexist[] = "does not exist";
738*8ccd4a63SDavid du Colombier int
739*8ccd4a63SDavid du Colombier walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
740*8ccd4a63SDavid du Colombier {
741*8ccd4a63SDavid du Colombier 	int dev, dotdot, i, n, nhave, ntry, type;
742*8ccd4a63SDavid du Colombier 	Chan *c, *nc;
743*8ccd4a63SDavid du Colombier 	Cname *cname;
744*8ccd4a63SDavid du Colombier 	Mount *f;
745*8ccd4a63SDavid du Colombier 	Mhead *mh, *nmh;
746*8ccd4a63SDavid du Colombier 	Walkqid *wq;
747*8ccd4a63SDavid du Colombier 
748*8ccd4a63SDavid du Colombier 	c = *cp;
749*8ccd4a63SDavid du Colombier 	incref(&c->ref);
750*8ccd4a63SDavid du Colombier 	cname = c->name;
751*8ccd4a63SDavid du Colombier 	incref(&cname->ref);
752*8ccd4a63SDavid du Colombier 	mh = nil;
753*8ccd4a63SDavid du Colombier 
754*8ccd4a63SDavid du Colombier 	/*
755*8ccd4a63SDavid du Colombier 	 * While we haven't gotten all the way down the path:
756*8ccd4a63SDavid du Colombier 	 *    1. step through a mount point, if any
757*8ccd4a63SDavid du Colombier 	 *    2. send a walk request for initial dotdot or initial prefix without dotdot
758*8ccd4a63SDavid du Colombier 	 *    3. move to the first mountpoint along the way.
759*8ccd4a63SDavid du Colombier 	 *    4. repeat.
760*8ccd4a63SDavid du Colombier 	 *
761*8ccd4a63SDavid du Colombier 	 * An invariant is that each time through the loop, c is on the undomount
762*8ccd4a63SDavid du Colombier 	 * side of the mount point, and c's name is cname.
763*8ccd4a63SDavid du Colombier 	 */
764*8ccd4a63SDavid du Colombier 	for(nhave=0; nhave<nnames; nhave+=n){
765*8ccd4a63SDavid du Colombier 		if((c->qid.type&QTDIR)==0){
766*8ccd4a63SDavid du Colombier 			if(nerror)
767*8ccd4a63SDavid du Colombier 				*nerror = nhave;
768*8ccd4a63SDavid du Colombier 			cnameclose(cname);
769*8ccd4a63SDavid du Colombier 			cclose(c);
770*8ccd4a63SDavid du Colombier 			strcpy(up->errstr, Enotdir);
771*8ccd4a63SDavid du Colombier 			if(mh != nil)
772*8ccd4a63SDavid du Colombier {print("walk 1\n");
773*8ccd4a63SDavid du Colombier 				putmhead(mh);
774*8ccd4a63SDavid du Colombier }
775*8ccd4a63SDavid du Colombier 			return -1;
776*8ccd4a63SDavid du Colombier 		}
777*8ccd4a63SDavid du Colombier 		ntry = nnames - nhave;
778*8ccd4a63SDavid du Colombier 		if(ntry > MAXWELEM)
779*8ccd4a63SDavid du Colombier 			ntry = MAXWELEM;
780*8ccd4a63SDavid du Colombier 		dotdot = 0;
781*8ccd4a63SDavid du Colombier 		for(i=0; i<ntry; i++){
782*8ccd4a63SDavid du Colombier 			if(isdotdot(names[nhave+i])){
783*8ccd4a63SDavid du Colombier 				if(i==0) {
784*8ccd4a63SDavid du Colombier 					dotdot = 1;
785*8ccd4a63SDavid du Colombier 					ntry = 1;
786*8ccd4a63SDavid du Colombier 				} else
787*8ccd4a63SDavid du Colombier 					ntry = i;
788*8ccd4a63SDavid du Colombier 				break;
789*8ccd4a63SDavid du Colombier 			}
790*8ccd4a63SDavid du Colombier 		}
791*8ccd4a63SDavid du Colombier 
792*8ccd4a63SDavid du Colombier 		if(!dotdot && !nomount)
793*8ccd4a63SDavid du Colombier 			domount(&c, &mh);
794*8ccd4a63SDavid du Colombier 
795*8ccd4a63SDavid du Colombier 		type = c->type;
796*8ccd4a63SDavid du Colombier 		dev = c->dev;
797*8ccd4a63SDavid du Colombier 
798*8ccd4a63SDavid du Colombier 		if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){
799*8ccd4a63SDavid du Colombier 			/* try a union mount, if any */
800*8ccd4a63SDavid du Colombier 			if(mh && !nomount){
801*8ccd4a63SDavid du Colombier 				/*
802*8ccd4a63SDavid du Colombier 				 * mh->mount == c, so start at mh->mount->next
803*8ccd4a63SDavid du Colombier 				 */
804*8ccd4a63SDavid du Colombier 				rlock(&mh->lock);
805*8ccd4a63SDavid du Colombier 				for(f = mh->mount->next; f; f = f->next)
806*8ccd4a63SDavid du Colombier 					if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil)
807*8ccd4a63SDavid du Colombier 						break;
808*8ccd4a63SDavid du Colombier 				runlock(&mh->lock);
809*8ccd4a63SDavid du Colombier 				if(f != nil){
810*8ccd4a63SDavid du Colombier 					type = f->to->type;
811*8ccd4a63SDavid du Colombier 					dev = f->to->dev;
812*8ccd4a63SDavid du Colombier 				}
813*8ccd4a63SDavid du Colombier 			}
814*8ccd4a63SDavid du Colombier 			if(wq == nil){
815*8ccd4a63SDavid du Colombier 				cclose(c);
816*8ccd4a63SDavid du Colombier 				cnameclose(cname);
817*8ccd4a63SDavid du Colombier 				if(nerror)
818*8ccd4a63SDavid du Colombier 					*nerror = nhave+1;
819*8ccd4a63SDavid du Colombier 				if(mh != nil)
820*8ccd4a63SDavid du Colombier 					putmhead(mh);
821*8ccd4a63SDavid du Colombier 				return -1;
822*8ccd4a63SDavid du Colombier 			}
823*8ccd4a63SDavid du Colombier 		}
824*8ccd4a63SDavid du Colombier 
825*8ccd4a63SDavid du Colombier 		nmh = nil;
826*8ccd4a63SDavid du Colombier 		if(dotdot) {
827*8ccd4a63SDavid du Colombier 			assert(wq->nqid == 1);
828*8ccd4a63SDavid du Colombier 			assert(wq->clone != nil);
829*8ccd4a63SDavid du Colombier 
830*8ccd4a63SDavid du Colombier 			cname = addelem(cname, "..");
831*8ccd4a63SDavid du Colombier 			nc = undomount(wq->clone, cname);
832*8ccd4a63SDavid du Colombier 			n = 1;
833*8ccd4a63SDavid du Colombier 		} else {
834*8ccd4a63SDavid du Colombier 			nc = nil;
835*8ccd4a63SDavid du Colombier 			if(!nomount)
836*8ccd4a63SDavid du Colombier 				for(i=0; i<wq->nqid && i<ntry-1; i++)
837*8ccd4a63SDavid du Colombier 					if(findmount(&nc, &nmh, type, dev, wq->qid[i]))
838*8ccd4a63SDavid du Colombier 						break;
839*8ccd4a63SDavid du Colombier 			if(nc == nil){	/* no mount points along path */
840*8ccd4a63SDavid du Colombier 				if(wq->clone == nil){
841*8ccd4a63SDavid du Colombier 					cclose(c);
842*8ccd4a63SDavid du Colombier 					cnameclose(cname);
843*8ccd4a63SDavid du Colombier 					if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
844*8ccd4a63SDavid du Colombier 						if(nerror)
845*8ccd4a63SDavid du Colombier 							*nerror = nhave+wq->nqid+1;
846*8ccd4a63SDavid du Colombier 						strcpy(up->errstr, Edoesnotexist);
847*8ccd4a63SDavid du Colombier 					}else{
848*8ccd4a63SDavid du Colombier 						if(nerror)
849*8ccd4a63SDavid du Colombier 							*nerror = nhave+wq->nqid;
850*8ccd4a63SDavid du Colombier 						strcpy(up->errstr, Enotdir);
851*8ccd4a63SDavid du Colombier 					}
852*8ccd4a63SDavid du Colombier 					free(wq);
853*8ccd4a63SDavid du Colombier 					if(mh != nil)
854*8ccd4a63SDavid du Colombier 						putmhead(mh);
855*8ccd4a63SDavid du Colombier 					return -1;
856*8ccd4a63SDavid du Colombier 				}
857*8ccd4a63SDavid du Colombier 				n = wq->nqid;
858*8ccd4a63SDavid du Colombier 				nc = wq->clone;
859*8ccd4a63SDavid du Colombier 			}else{		/* stopped early, at a mount point */
860*8ccd4a63SDavid du Colombier 				if(wq->clone != nil){
861*8ccd4a63SDavid du Colombier 					cclose(wq->clone);
862*8ccd4a63SDavid du Colombier 					wq->clone = nil;
863*8ccd4a63SDavid du Colombier 				}
864*8ccd4a63SDavid du Colombier 				n = i+1;
865*8ccd4a63SDavid du Colombier 			}
866*8ccd4a63SDavid du Colombier 			for(i=0; i<n; i++)
867*8ccd4a63SDavid du Colombier 				cname = addelem(cname, names[nhave+i]);
868*8ccd4a63SDavid du Colombier 		}
869*8ccd4a63SDavid du Colombier 		cclose(c);
870*8ccd4a63SDavid du Colombier 		c = nc;
871*8ccd4a63SDavid du Colombier 		putmhead(mh);
872*8ccd4a63SDavid du Colombier 		mh = nmh;
873*8ccd4a63SDavid du Colombier 		free(wq);
874*8ccd4a63SDavid du Colombier 	}
875*8ccd4a63SDavid du Colombier 
876*8ccd4a63SDavid du Colombier 	putmhead(mh);
877*8ccd4a63SDavid du Colombier 
878*8ccd4a63SDavid du Colombier 	c = cunique(c);
879*8ccd4a63SDavid du Colombier 
880*8ccd4a63SDavid du Colombier 	if(c->umh != nil){	//BUG
881*8ccd4a63SDavid du Colombier 		print("walk umh\n");
882*8ccd4a63SDavid du Colombier 		putmhead(c->umh);
883*8ccd4a63SDavid du Colombier 		c->umh = nil;
884*8ccd4a63SDavid du Colombier 	}
885*8ccd4a63SDavid du Colombier 
886*8ccd4a63SDavid du Colombier 	cnameclose(c->name);
887*8ccd4a63SDavid du Colombier 	c->name = cname;
888*8ccd4a63SDavid du Colombier 
889*8ccd4a63SDavid du Colombier 	cclose(*cp);
890*8ccd4a63SDavid du Colombier 	*cp = c;
891*8ccd4a63SDavid du Colombier 	if(nerror)
892*8ccd4a63SDavid du Colombier 		*nerror = 0;
893*8ccd4a63SDavid du Colombier 	return 0;
894*8ccd4a63SDavid du Colombier }
895*8ccd4a63SDavid du Colombier 
896*8ccd4a63SDavid du Colombier /*
897*8ccd4a63SDavid du Colombier  * c is a mounted non-creatable directory.  find a creatable one.
898*8ccd4a63SDavid du Colombier  */
899*8ccd4a63SDavid du Colombier Chan*
900*8ccd4a63SDavid du Colombier createdir(Chan *c, Mhead *m)
901*8ccd4a63SDavid du Colombier {
902*8ccd4a63SDavid du Colombier 	Chan *nc;
903*8ccd4a63SDavid du Colombier 	Mount *f;
904*8ccd4a63SDavid du Colombier 
905*8ccd4a63SDavid du Colombier 	rlock(&m->lock);
906*8ccd4a63SDavid du Colombier 	if(waserror()) {
907*8ccd4a63SDavid du Colombier 		runlock(&m->lock);
908*8ccd4a63SDavid du Colombier 		nexterror();
909*8ccd4a63SDavid du Colombier 	}
910*8ccd4a63SDavid du Colombier 	for(f = m->mount; f; f = f->next) {
911*8ccd4a63SDavid du Colombier 		if(f->mflag&MCREATE) {
912*8ccd4a63SDavid du Colombier 			nc = cclone(f->to);
913*8ccd4a63SDavid du Colombier 			runlock(&m->lock);
914*8ccd4a63SDavid du Colombier 			poperror();
915*8ccd4a63SDavid du Colombier 			cclose(c);
916*8ccd4a63SDavid du Colombier 			return nc;
917*8ccd4a63SDavid du Colombier 		}
918*8ccd4a63SDavid du Colombier 	}
919*8ccd4a63SDavid du Colombier 	error(Enocreate);
920*8ccd4a63SDavid du Colombier 	return 0;
921*8ccd4a63SDavid du Colombier }
922*8ccd4a63SDavid du Colombier 
923*8ccd4a63SDavid du Colombier void
924*8ccd4a63SDavid du Colombier saveregisters(void)
925*8ccd4a63SDavid du Colombier {
926*8ccd4a63SDavid du Colombier }
927*8ccd4a63SDavid du Colombier 
928*8ccd4a63SDavid du Colombier /*
929*8ccd4a63SDavid du Colombier  * In place, rewrite name to compress multiple /, eliminate ., and process ..
930*8ccd4a63SDavid du Colombier  */
931*8ccd4a63SDavid du Colombier void
932*8ccd4a63SDavid du Colombier cleancname(Cname *n)
933*8ccd4a63SDavid du Colombier {
934*8ccd4a63SDavid du Colombier 	char *p;
935*8ccd4a63SDavid du Colombier 
936*8ccd4a63SDavid du Colombier 	if(n->s[0] == '#'){
937*8ccd4a63SDavid du Colombier 		p = strchr(n->s, '/');
938*8ccd4a63SDavid du Colombier 		if(p == nil)
939*8ccd4a63SDavid du Colombier 			return;
940*8ccd4a63SDavid du Colombier 		cleanname(p);
941*8ccd4a63SDavid du Colombier 
942*8ccd4a63SDavid du Colombier 		/*
943*8ccd4a63SDavid du Colombier 		 * The correct name is #i rather than #i/,
944*8ccd4a63SDavid du Colombier 		 * but the correct name of #/ is #/.
945*8ccd4a63SDavid du Colombier 		 */
946*8ccd4a63SDavid du Colombier 		if(strcmp(p, "/")==0 && n->s[1] != '/')
947*8ccd4a63SDavid du Colombier 			*p = '\0';
948*8ccd4a63SDavid du Colombier 	}else
949*8ccd4a63SDavid du Colombier 		cleanname(n->s);
950*8ccd4a63SDavid du Colombier 	n->len = strlen(n->s);
951*8ccd4a63SDavid du Colombier }
952*8ccd4a63SDavid du Colombier 
953*8ccd4a63SDavid du Colombier static void
954*8ccd4a63SDavid du Colombier growparse(Elemlist *e)
955*8ccd4a63SDavid du Colombier {
956*8ccd4a63SDavid du Colombier 	char **new;
957*8ccd4a63SDavid du Colombier 	int *inew;
958*8ccd4a63SDavid du Colombier 	enum { Delta = 8 };
959*8ccd4a63SDavid du Colombier 
960*8ccd4a63SDavid du Colombier 	if(e->nelems % Delta == 0){
961*8ccd4a63SDavid du Colombier 		new = smalloc((e->nelems+Delta) * sizeof(char*));
962*8ccd4a63SDavid du Colombier 		memmove(new, e->elems, e->nelems*sizeof(char*));
963*8ccd4a63SDavid du Colombier 		free(e->elems);
964*8ccd4a63SDavid du Colombier 		e->elems = new;
965*8ccd4a63SDavid du Colombier 		inew = smalloc((e->nelems+Delta+1) * sizeof(int));
966*8ccd4a63SDavid du Colombier 		memmove(inew, e->off, e->nelems*sizeof(int));
967*8ccd4a63SDavid du Colombier 		free(e->off);
968*8ccd4a63SDavid du Colombier 		e->off = inew;
969*8ccd4a63SDavid du Colombier 	}
970*8ccd4a63SDavid du Colombier }
971*8ccd4a63SDavid du Colombier 
972*8ccd4a63SDavid du Colombier /*
973*8ccd4a63SDavid du Colombier  * The name is known to be valid.
974*8ccd4a63SDavid du Colombier  * Copy the name so slashes can be overwritten.
975*8ccd4a63SDavid du Colombier  * An empty string will set nelem=0.
976*8ccd4a63SDavid du Colombier  * A path ending in / or /. or /.//./ etc. will have
977*8ccd4a63SDavid du Colombier  * e.mustbedir = 1, so that we correctly
978*8ccd4a63SDavid du Colombier  * reject, e.g., "/adm/users/." when /adm/users is a file
979*8ccd4a63SDavid du Colombier  * rather than a directory.
980*8ccd4a63SDavid du Colombier  */
981*8ccd4a63SDavid du Colombier static void
982*8ccd4a63SDavid du Colombier parsename(char *name, Elemlist *e)
983*8ccd4a63SDavid du Colombier {
984*8ccd4a63SDavid du Colombier 	char *slash;
985*8ccd4a63SDavid du Colombier 
986*8ccd4a63SDavid du Colombier 	kstrdup(&e->name, name);
987*8ccd4a63SDavid du Colombier 	name = e->name;
988*8ccd4a63SDavid du Colombier 	e->nelems = 0;
989*8ccd4a63SDavid du Colombier 	e->elems = nil;
990*8ccd4a63SDavid du Colombier 	e->off = smalloc(sizeof(int));
991*8ccd4a63SDavid du Colombier 	e->off[0] = skipslash(name) - name;
992*8ccd4a63SDavid du Colombier 	for(;;){
993*8ccd4a63SDavid du Colombier 		name = skipslash(name);
994*8ccd4a63SDavid du Colombier 		if(*name=='\0'){
995*8ccd4a63SDavid du Colombier 			e->mustbedir = 1;
996*8ccd4a63SDavid du Colombier 			break;
997*8ccd4a63SDavid du Colombier 		}
998*8ccd4a63SDavid du Colombier 		growparse(e);
999*8ccd4a63SDavid du Colombier 		e->elems[e->nelems++] = name;
1000*8ccd4a63SDavid du Colombier 		slash = utfrune(name, '/');
1001*8ccd4a63SDavid du Colombier 		if(slash == nil){
1002*8ccd4a63SDavid du Colombier 			e->off[e->nelems] = name+strlen(name) - e->name;
1003*8ccd4a63SDavid du Colombier 			e->mustbedir = 0;
1004*8ccd4a63SDavid du Colombier 			break;
1005*8ccd4a63SDavid du Colombier 		}
1006*8ccd4a63SDavid du Colombier 		e->off[e->nelems] = slash - e->name;
1007*8ccd4a63SDavid du Colombier 		*slash++ = '\0';
1008*8ccd4a63SDavid du Colombier 		name = slash;
1009*8ccd4a63SDavid du Colombier 	}
1010*8ccd4a63SDavid du Colombier }
1011*8ccd4a63SDavid du Colombier 
1012*8ccd4a63SDavid du Colombier void*
1013*8ccd4a63SDavid du Colombier memrchr(void *va, int c, long n)
1014*8ccd4a63SDavid du Colombier {
1015*8ccd4a63SDavid du Colombier 	uchar *a, *e;
1016*8ccd4a63SDavid du Colombier 
1017*8ccd4a63SDavid du Colombier 	a = va;
1018*8ccd4a63SDavid du Colombier 	for(e=a+n-1; e>a; e--)
1019*8ccd4a63SDavid du Colombier 		if(*e == c)
1020*8ccd4a63SDavid du Colombier 			return e;
1021*8ccd4a63SDavid du Colombier 	return nil;
1022*8ccd4a63SDavid du Colombier }
1023*8ccd4a63SDavid du Colombier 
1024*8ccd4a63SDavid du Colombier /*
1025*8ccd4a63SDavid du Colombier  * Turn a name into a channel.
1026*8ccd4a63SDavid du Colombier  * &name[0] is known to be a valid address.  It may be a kernel address.
1027*8ccd4a63SDavid du Colombier  *
1028*8ccd4a63SDavid du Colombier  * Opening with amode Aopen, Acreate, or Aremove guarantees
1029*8ccd4a63SDavid du Colombier  * that the result will be the only reference to that particular fid.
1030*8ccd4a63SDavid du Colombier  * This is necessary since we might pass the result to
1031*8ccd4a63SDavid du Colombier  * devtab[]->remove().
1032*8ccd4a63SDavid du Colombier  *
1033*8ccd4a63SDavid du Colombier  * Opening Atodir, Amount, or Aaccess does not guarantee this.
1034*8ccd4a63SDavid du Colombier  *
1035*8ccd4a63SDavid du Colombier  * Opening Aaccess can, under certain conditions, return a
1036*8ccd4a63SDavid du Colombier  * correct Chan* but with an incorrect Cname attached.
1037*8ccd4a63SDavid du Colombier  * Since the functions that open Aaccess (sysstat, syswstat, sys_stat)
1038*8ccd4a63SDavid du Colombier  * do not use the Cname*, this avoids an unnecessary clone.
1039*8ccd4a63SDavid du Colombier  */
1040*8ccd4a63SDavid du Colombier Chan*
1041*8ccd4a63SDavid du Colombier namec(char *aname, int amode, int omode, ulong perm)
1042*8ccd4a63SDavid du Colombier {
1043*8ccd4a63SDavid du Colombier 	int n, prefix, len, t, nomount, npath;
1044*8ccd4a63SDavid du Colombier 	Chan *c, *cnew;
1045*8ccd4a63SDavid du Colombier 	Cname *cname;
1046*8ccd4a63SDavid du Colombier 	Elemlist e;
1047*8ccd4a63SDavid du Colombier 	Rune r;
1048*8ccd4a63SDavid du Colombier 	Mhead *m;
1049*8ccd4a63SDavid du Colombier 	char *createerr, tmperrbuf[ERRMAX];
1050*8ccd4a63SDavid du Colombier 	char *name;
1051*8ccd4a63SDavid du Colombier 
1052*8ccd4a63SDavid du Colombier 	name = aname;
1053*8ccd4a63SDavid du Colombier 	if(name[0] == '\0')
1054*8ccd4a63SDavid du Colombier 		error("empty file name");
1055*8ccd4a63SDavid du Colombier 	validname(name, 1);
1056*8ccd4a63SDavid du Colombier 
1057*8ccd4a63SDavid du Colombier 	/*
1058*8ccd4a63SDavid du Colombier 	 * Find the starting off point (the current slash, the root of
1059*8ccd4a63SDavid du Colombier 	 * a device tree, or the current dot) as well as the name to
1060*8ccd4a63SDavid du Colombier 	 * evaluate starting there.
1061*8ccd4a63SDavid du Colombier 	 */
1062*8ccd4a63SDavid du Colombier 	nomount = 0;
1063*8ccd4a63SDavid du Colombier 	switch(name[0]){
1064*8ccd4a63SDavid du Colombier 	case '/':
1065*8ccd4a63SDavid du Colombier 		c = up->slash;
1066*8ccd4a63SDavid du Colombier 		incref(&c->ref);
1067*8ccd4a63SDavid du Colombier 		break;
1068*8ccd4a63SDavid du Colombier 
1069*8ccd4a63SDavid du Colombier 	case '#':
1070*8ccd4a63SDavid du Colombier 		nomount = 1;
1071*8ccd4a63SDavid du Colombier 		up->genbuf[0] = '\0';
1072*8ccd4a63SDavid du Colombier 		n = 0;
1073*8ccd4a63SDavid du Colombier 		while(*name!='\0' && (*name != '/' || n < 2)){
1074*8ccd4a63SDavid du Colombier 			if(n >= sizeof(up->genbuf)-1)
1075*8ccd4a63SDavid du Colombier 				error(Efilename);
1076*8ccd4a63SDavid du Colombier 			up->genbuf[n++] = *name++;
1077*8ccd4a63SDavid du Colombier 		}
1078*8ccd4a63SDavid du Colombier 		up->genbuf[n] = '\0';
1079*8ccd4a63SDavid du Colombier 		/*
1080*8ccd4a63SDavid du Colombier 		 *  noattach is sandboxing.
1081*8ccd4a63SDavid du Colombier 		 *
1082*8ccd4a63SDavid du Colombier 		 *  the OK exceptions are:
1083*8ccd4a63SDavid du Colombier 		 *	|  it only gives access to pipes you create
1084*8ccd4a63SDavid du Colombier 		 *	d  this process's file descriptors
1085*8ccd4a63SDavid du Colombier 		 *	e  this process's environment
1086*8ccd4a63SDavid du Colombier 		 *  the iffy exceptions are:
1087*8ccd4a63SDavid du Colombier 		 *	c  time and pid, but also cons and consctl
1088*8ccd4a63SDavid du Colombier 		 *	p  control of your own processes (and unfortunately
1089*8ccd4a63SDavid du Colombier 		 *	   any others left unprotected)
1090*8ccd4a63SDavid du Colombier 		 */
1091*8ccd4a63SDavid du Colombier 		n = chartorune(&r, up->genbuf+1)+1;
1092*8ccd4a63SDavid du Colombier 		/* actually / is caught by parsing earlier */
1093*8ccd4a63SDavid du Colombier 		if(utfrune("M", r))
1094*8ccd4a63SDavid du Colombier 			error(Enoattach);
1095*8ccd4a63SDavid du Colombier 		if(up->pgrp->noattach && utfrune("|decp", r)==nil)
1096*8ccd4a63SDavid du Colombier 			error(Enoattach);
1097*8ccd4a63SDavid du Colombier 		t = devno(r, 1);
1098*8ccd4a63SDavid du Colombier 		if(t == -1)
1099*8ccd4a63SDavid du Colombier 			error(Ebadsharp);
1100*8ccd4a63SDavid du Colombier 		c = devtab[t]->attach(up->genbuf+n);
1101*8ccd4a63SDavid du Colombier 		break;
1102*8ccd4a63SDavid du Colombier 
1103*8ccd4a63SDavid du Colombier 	default:
1104*8ccd4a63SDavid du Colombier 		c = up->dot;
1105*8ccd4a63SDavid du Colombier 		incref(&c->ref);
1106*8ccd4a63SDavid du Colombier 		break;
1107*8ccd4a63SDavid du Colombier 	}
1108*8ccd4a63SDavid du Colombier 	prefix = name - aname;
1109*8ccd4a63SDavid du Colombier 
1110*8ccd4a63SDavid du Colombier 	e.name = nil;
1111*8ccd4a63SDavid du Colombier 	e.elems = nil;
1112*8ccd4a63SDavid du Colombier 	e.off = nil;
1113*8ccd4a63SDavid du Colombier 	e.nelems = 0;
1114*8ccd4a63SDavid du Colombier 	if(waserror()){
1115*8ccd4a63SDavid du Colombier 		cclose(c);
1116*8ccd4a63SDavid du Colombier 		free(e.name);
1117*8ccd4a63SDavid du Colombier 		free(e.elems);
1118*8ccd4a63SDavid du Colombier 		free(e.off);
1119*8ccd4a63SDavid du Colombier //dumpmount();
1120*8ccd4a63SDavid du Colombier 		nexterror();
1121*8ccd4a63SDavid du Colombier 	}
1122*8ccd4a63SDavid du Colombier 
1123*8ccd4a63SDavid du Colombier 	/*
1124*8ccd4a63SDavid du Colombier 	 * Build a list of elements in the path.
1125*8ccd4a63SDavid du Colombier 	 */
1126*8ccd4a63SDavid du Colombier 	parsename(name, &e);
1127*8ccd4a63SDavid du Colombier 
1128*8ccd4a63SDavid du Colombier 	/*
1129*8ccd4a63SDavid du Colombier 	 * On create, ....
1130*8ccd4a63SDavid du Colombier 	 */
1131*8ccd4a63SDavid du Colombier 	if(amode == Acreate){
1132*8ccd4a63SDavid du Colombier 		/* perm must have DMDIR if last element is / or /. */
1133*8ccd4a63SDavid du Colombier 		if(e.mustbedir && !(perm&DMDIR)){
1134*8ccd4a63SDavid du Colombier 			npath = e.nelems;
1135*8ccd4a63SDavid du Colombier 			strcpy(tmperrbuf, "create without DMDIR");
1136*8ccd4a63SDavid du Colombier 			goto NameError;
1137*8ccd4a63SDavid du Colombier 		}
1138*8ccd4a63SDavid du Colombier 
1139*8ccd4a63SDavid du Colombier 		/* don't try to walk the last path element just yet. */
1140*8ccd4a63SDavid du Colombier 		if(e.nelems == 0)
1141*8ccd4a63SDavid du Colombier 			error(Eexist);
1142*8ccd4a63SDavid du Colombier 		e.nelems--;
1143*8ccd4a63SDavid du Colombier 	}
1144*8ccd4a63SDavid du Colombier 
1145*8ccd4a63SDavid du Colombier 	if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){
1146*8ccd4a63SDavid du Colombier 		if(npath < 0 || npath > e.nelems){
1147*8ccd4a63SDavid du Colombier 			print("namec %s walk error npath=%d\n", aname, npath);
1148*8ccd4a63SDavid du Colombier 			nexterror();
1149*8ccd4a63SDavid du Colombier 		}
1150*8ccd4a63SDavid du Colombier 		strcpy(tmperrbuf, up->errstr);
1151*8ccd4a63SDavid du Colombier 	NameError:
1152*8ccd4a63SDavid du Colombier 		len = prefix+e.off[npath];
1153*8ccd4a63SDavid du Colombier 		if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname)
1154*8ccd4a63SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
1155*8ccd4a63SDavid du Colombier 		else
1156*8ccd4a63SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
1157*8ccd4a63SDavid du Colombier 		snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf);
1158*8ccd4a63SDavid du Colombier 		nexterror();
1159*8ccd4a63SDavid du Colombier 	}
1160*8ccd4a63SDavid du Colombier 
1161*8ccd4a63SDavid du Colombier 	if(e.mustbedir && !(c->qid.type&QTDIR)){
1162*8ccd4a63SDavid du Colombier 		npath = e.nelems;
1163*8ccd4a63SDavid du Colombier 		strcpy(tmperrbuf, "not a directory");
1164*8ccd4a63SDavid du Colombier 		goto NameError;
1165*8ccd4a63SDavid du Colombier 	}
1166*8ccd4a63SDavid du Colombier 
1167*8ccd4a63SDavid du Colombier 	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){
1168*8ccd4a63SDavid du Colombier 		npath = e.nelems;
1169*8ccd4a63SDavid du Colombier 		error("cannot exec directory");
1170*8ccd4a63SDavid du Colombier 	}
1171*8ccd4a63SDavid du Colombier 
1172*8ccd4a63SDavid du Colombier 	switch(amode){
1173*8ccd4a63SDavid du Colombier 	case Aaccess:
1174*8ccd4a63SDavid du Colombier 		if(!nomount)
1175*8ccd4a63SDavid du Colombier 			domount(&c, nil);
1176*8ccd4a63SDavid du Colombier 		break;
1177*8ccd4a63SDavid du Colombier 
1178*8ccd4a63SDavid du Colombier 	case Abind:
1179*8ccd4a63SDavid du Colombier 		m = nil;
1180*8ccd4a63SDavid du Colombier 		if(!nomount)
1181*8ccd4a63SDavid du Colombier 			domount(&c, &m);
1182*8ccd4a63SDavid du Colombier 		if(c->umh != nil)
1183*8ccd4a63SDavid du Colombier 			putmhead(c->umh);
1184*8ccd4a63SDavid du Colombier 		c->umh = m;
1185*8ccd4a63SDavid du Colombier 		break;
1186*8ccd4a63SDavid du Colombier 
1187*8ccd4a63SDavid du Colombier 	case Aremove:
1188*8ccd4a63SDavid du Colombier 	case Aopen:
1189*8ccd4a63SDavid du Colombier 	Open:
1190*8ccd4a63SDavid du Colombier 		/* save the name; domount might change c */
1191*8ccd4a63SDavid du Colombier 		cname = c->name;
1192*8ccd4a63SDavid du Colombier 		incref(&cname->ref);
1193*8ccd4a63SDavid du Colombier 		m = nil;
1194*8ccd4a63SDavid du Colombier 		if(!nomount)
1195*8ccd4a63SDavid du Colombier 			domount(&c, &m);
1196*8ccd4a63SDavid du Colombier 
1197*8ccd4a63SDavid du Colombier 		/* our own copy to open or remove */
1198*8ccd4a63SDavid du Colombier 		c = cunique(c);
1199*8ccd4a63SDavid du Colombier 
1200*8ccd4a63SDavid du Colombier 		/* now it's our copy anyway, we can put the name back */
1201*8ccd4a63SDavid du Colombier 		cnameclose(c->name);
1202*8ccd4a63SDavid du Colombier 		c->name = cname;
1203*8ccd4a63SDavid du Colombier 
1204*8ccd4a63SDavid du Colombier 		switch(amode){
1205*8ccd4a63SDavid du Colombier 		case Aremove:
1206*8ccd4a63SDavid du Colombier 			putmhead(m);
1207*8ccd4a63SDavid du Colombier 			break;
1208*8ccd4a63SDavid du Colombier 
1209*8ccd4a63SDavid du Colombier 		case Aopen:
1210*8ccd4a63SDavid du Colombier 		case Acreate:
1211*8ccd4a63SDavid du Colombier if(c->umh != nil){
1212*8ccd4a63SDavid du Colombier 	print("cunique umh Open\n");
1213*8ccd4a63SDavid du Colombier 	putmhead(c->umh);
1214*8ccd4a63SDavid du Colombier 	c->umh = nil;
1215*8ccd4a63SDavid du Colombier }
1216*8ccd4a63SDavid du Colombier 
1217*8ccd4a63SDavid du Colombier 			/* only save the mount head if it's a multiple element union */
1218*8ccd4a63SDavid du Colombier 			if(m && m->mount && m->mount->next)
1219*8ccd4a63SDavid du Colombier 				c->umh = m;
1220*8ccd4a63SDavid du Colombier 			else
1221*8ccd4a63SDavid du Colombier 				putmhead(m);
1222*8ccd4a63SDavid du Colombier 
1223*8ccd4a63SDavid du Colombier 			/* save registers else error() in open has wrong value of c saved */
1224*8ccd4a63SDavid du Colombier 			saveregisters();
1225*8ccd4a63SDavid du Colombier 
1226*8ccd4a63SDavid du Colombier 			if(omode == OEXEC)
1227*8ccd4a63SDavid du Colombier 				c->flag &= ~CCACHE;
1228*8ccd4a63SDavid du Colombier 
1229*8ccd4a63SDavid du Colombier 			c = devtab[c->type]->open(c, omode&~OCEXEC);
1230*8ccd4a63SDavid du Colombier 
1231*8ccd4a63SDavid du Colombier 			if(omode & OCEXEC)
1232*8ccd4a63SDavid du Colombier 				c->flag |= CCEXEC;
1233*8ccd4a63SDavid du Colombier 			if(omode & ORCLOSE)
1234*8ccd4a63SDavid du Colombier 				c->flag |= CRCLOSE;
1235*8ccd4a63SDavid du Colombier 			break;
1236*8ccd4a63SDavid du Colombier 		}
1237*8ccd4a63SDavid du Colombier 		break;
1238*8ccd4a63SDavid du Colombier 
1239*8ccd4a63SDavid du Colombier 	case Atodir:
1240*8ccd4a63SDavid du Colombier 		/*
1241*8ccd4a63SDavid du Colombier 		 * Directories (e.g. for cd) are left before the mount point,
1242*8ccd4a63SDavid du Colombier 		 * so one may mount on / or . and see the effect.
1243*8ccd4a63SDavid du Colombier 		 */
1244*8ccd4a63SDavid du Colombier 		if(!(c->qid.type & QTDIR))
1245*8ccd4a63SDavid du Colombier 			error(Enotdir);
1246*8ccd4a63SDavid du Colombier 		break;
1247*8ccd4a63SDavid du Colombier 
1248*8ccd4a63SDavid du Colombier 	case Amount:
1249*8ccd4a63SDavid du Colombier 		/*
1250*8ccd4a63SDavid du Colombier 		 * When mounting on an already mounted upon directory,
1251*8ccd4a63SDavid du Colombier 		 * one wants subsequent mounts to be attached to the
1252*8ccd4a63SDavid du Colombier 		 * original directory, not the replacement.  Don't domount.
1253*8ccd4a63SDavid du Colombier 		 */
1254*8ccd4a63SDavid du Colombier 		break;
1255*8ccd4a63SDavid du Colombier 
1256*8ccd4a63SDavid du Colombier 	case Acreate:
1257*8ccd4a63SDavid du Colombier 		/*
1258*8ccd4a63SDavid du Colombier 		 * We've already walked all but the last element.
1259*8ccd4a63SDavid du Colombier 		 * If the last exists, try to open it OTRUNC.
1260*8ccd4a63SDavid du Colombier 		 * If omode&OEXCL is set, just give up.
1261*8ccd4a63SDavid du Colombier 		 */
1262*8ccd4a63SDavid du Colombier 		e.nelems++;
1263*8ccd4a63SDavid du Colombier 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
1264*8ccd4a63SDavid du Colombier 			if(omode&OEXCL)
1265*8ccd4a63SDavid du Colombier 				error(Eexist);
1266*8ccd4a63SDavid du Colombier 			omode |= OTRUNC;
1267*8ccd4a63SDavid du Colombier 			goto Open;
1268*8ccd4a63SDavid du Colombier 		}
1269*8ccd4a63SDavid du Colombier 
1270*8ccd4a63SDavid du Colombier 		/*
1271*8ccd4a63SDavid du Colombier 		 * The semantics of the create(2) system call are that if the
1272*8ccd4a63SDavid du Colombier 		 * file exists and can be written, it is to be opened with truncation.
1273*8ccd4a63SDavid du Colombier 		 * On the other hand, the create(5) message fails if the file exists.
1274*8ccd4a63SDavid du Colombier 		 * If we get two create(2) calls happening simultaneously,
1275*8ccd4a63SDavid du Colombier 		 * they might both get here and send create(5) messages, but only
1276*8ccd4a63SDavid du Colombier 		 * one of the messages will succeed.  To provide the expected create(2)
1277*8ccd4a63SDavid du Colombier 		 * semantics, the call with the failed message needs to try the above
1278*8ccd4a63SDavid du Colombier 		 * walk again, opening for truncation.  This correctly solves the
1279*8ccd4a63SDavid du Colombier 		 * create/create race, in the sense that any observable outcome can
1280*8ccd4a63SDavid du Colombier 		 * be explained as one happening before the other.
1281*8ccd4a63SDavid du Colombier 		 * The create/create race is quite common.  For example, it happens
1282*8ccd4a63SDavid du Colombier 		 * when two rc subshells simultaneously update the same
1283*8ccd4a63SDavid du Colombier 		 * environment variable.
1284*8ccd4a63SDavid du Colombier 		 *
1285*8ccd4a63SDavid du Colombier 		 * The implementation still admits a create/create/remove race:
1286*8ccd4a63SDavid du Colombier 		 * (A) walk to file, fails
1287*8ccd4a63SDavid du Colombier 		 * (B) walk to file, fails
1288*8ccd4a63SDavid du Colombier 		 * (A) create file, succeeds, returns
1289*8ccd4a63SDavid du Colombier 		 * (B) create file, fails
1290*8ccd4a63SDavid du Colombier 		 * (A) remove file, succeeds, returns
1291*8ccd4a63SDavid du Colombier 		 * (B) walk to file, return failure.
1292*8ccd4a63SDavid du Colombier 		 *
1293*8ccd4a63SDavid du Colombier 		 * This is hardly as common as the create/create race, and is really
1294*8ccd4a63SDavid du Colombier 		 * not too much worse than what might happen if (B) got a hold of a
1295*8ccd4a63SDavid du Colombier 		 * file descriptor and then the file was removed -- either way (B) can't do
1296*8ccd4a63SDavid du Colombier 		 * anything with the result of the create call.  So we don't care about this race.
1297*8ccd4a63SDavid du Colombier 		 *
1298*8ccd4a63SDavid du Colombier 		 * Applications that care about more fine-grained decision of the races
1299*8ccd4a63SDavid du Colombier 		 * can use the OEXCL flag to get at the underlying create(5) semantics;
1300*8ccd4a63SDavid du Colombier 		 * by default we provide the common case.
1301*8ccd4a63SDavid du Colombier 		 *
1302*8ccd4a63SDavid du Colombier 		 * We need to stay behind the mount point in case we
1303*8ccd4a63SDavid du Colombier 		 * need to do the first walk again (should the create fail).
1304*8ccd4a63SDavid du Colombier 		 *
1305*8ccd4a63SDavid du Colombier 		 * We also need to cross the mount point and find the directory
1306*8ccd4a63SDavid du Colombier 		 * in the union in which we should be creating.
1307*8ccd4a63SDavid du Colombier 		 *
1308*8ccd4a63SDavid du Colombier 		 * The channel staying behind is c, the one moving forward is cnew.
1309*8ccd4a63SDavid du Colombier 		 */
1310*8ccd4a63SDavid du Colombier 		m = nil;
1311*8ccd4a63SDavid du Colombier 		cnew = nil;	/* is this assignment necessary? */
1312*8ccd4a63SDavid du Colombier 		if(!waserror()){	/* try create */
1313*8ccd4a63SDavid du Colombier 			if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))
1314*8ccd4a63SDavid du Colombier 				cnew = createdir(cnew, m);
1315*8ccd4a63SDavid du Colombier 			else{
1316*8ccd4a63SDavid du Colombier 				cnew = c;
1317*8ccd4a63SDavid du Colombier 				incref(&cnew->ref);
1318*8ccd4a63SDavid du Colombier 			}
1319*8ccd4a63SDavid du Colombier 
1320*8ccd4a63SDavid du Colombier 			/*
1321*8ccd4a63SDavid du Colombier 			 * We need our own copy of the Chan because we're
1322*8ccd4a63SDavid du Colombier 			 * about to send a create, which will move it.  Once we have
1323*8ccd4a63SDavid du Colombier 			 * our own copy, we can fix the name, which might be wrong
1324*8ccd4a63SDavid du Colombier 			 * if findmount gave us a new Chan.
1325*8ccd4a63SDavid du Colombier 			 */
1326*8ccd4a63SDavid du Colombier 			cnew = cunique(cnew);
1327*8ccd4a63SDavid du Colombier 			cnameclose(cnew->name);
1328*8ccd4a63SDavid du Colombier 			cnew->name = c->name;
1329*8ccd4a63SDavid du Colombier 			incref(&cnew->name->ref);
1330*8ccd4a63SDavid du Colombier 
1331*8ccd4a63SDavid du Colombier 			devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
1332*8ccd4a63SDavid du Colombier 			poperror();
1333*8ccd4a63SDavid du Colombier 			if(omode & OCEXEC)
1334*8ccd4a63SDavid du Colombier 				cnew->flag |= CCEXEC;
1335*8ccd4a63SDavid du Colombier 			if(omode & ORCLOSE)
1336*8ccd4a63SDavid du Colombier 				cnew->flag |= CRCLOSE;
1337*8ccd4a63SDavid du Colombier 			if(m)
1338*8ccd4a63SDavid du Colombier 				putmhead(m);
1339*8ccd4a63SDavid du Colombier 			cclose(c);
1340*8ccd4a63SDavid du Colombier 			c = cnew;
1341*8ccd4a63SDavid du Colombier 			c->name = addelem(c->name, e.elems[e.nelems-1]);
1342*8ccd4a63SDavid du Colombier 			break;
1343*8ccd4a63SDavid du Colombier 		}else{		/* create failed */
1344*8ccd4a63SDavid du Colombier 			cclose(cnew);
1345*8ccd4a63SDavid du Colombier 			if(m)
1346*8ccd4a63SDavid du Colombier 				putmhead(m);
1347*8ccd4a63SDavid du Colombier 			if(omode & OEXCL)
1348*8ccd4a63SDavid du Colombier 				nexterror();
1349*8ccd4a63SDavid du Colombier 			/* save error */
1350*8ccd4a63SDavid du Colombier 			createerr = up->errstr;
1351*8ccd4a63SDavid du Colombier 			up->errstr = tmperrbuf;
1352*8ccd4a63SDavid du Colombier 			/* note: we depend that walk does not error */
1353*8ccd4a63SDavid du Colombier 			if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
1354*8ccd4a63SDavid du Colombier 				up->errstr = createerr;
1355*8ccd4a63SDavid du Colombier 				error(createerr);	/* report true error */
1356*8ccd4a63SDavid du Colombier 			}
1357*8ccd4a63SDavid du Colombier 			up->errstr = createerr;
1358*8ccd4a63SDavid du Colombier 			omode |= OTRUNC;
1359*8ccd4a63SDavid du Colombier 			goto Open;
1360*8ccd4a63SDavid du Colombier 		}
1361*8ccd4a63SDavid du Colombier 		panic("namec: not reached");
1362*8ccd4a63SDavid du Colombier 
1363*8ccd4a63SDavid du Colombier 	default:
1364*8ccd4a63SDavid du Colombier 		panic("unknown namec access %d\n", amode);
1365*8ccd4a63SDavid du Colombier 	}
1366*8ccd4a63SDavid du Colombier 
1367*8ccd4a63SDavid du Colombier 	poperror();
1368*8ccd4a63SDavid du Colombier 
1369*8ccd4a63SDavid du Colombier 	/* place final element in genbuf for e.g. exec */
1370*8ccd4a63SDavid du Colombier 	if(e.nelems > 0)
1371*8ccd4a63SDavid du Colombier 		kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
1372*8ccd4a63SDavid du Colombier 	else
1373*8ccd4a63SDavid du Colombier 		kstrcpy(up->genbuf, ".", sizeof up->genbuf);
1374*8ccd4a63SDavid du Colombier 	free(e.name);
1375*8ccd4a63SDavid du Colombier 	free(e.elems);
1376*8ccd4a63SDavid du Colombier 	free(e.off);
1377*8ccd4a63SDavid du Colombier 
1378*8ccd4a63SDavid du Colombier 	return c;
1379*8ccd4a63SDavid du Colombier }
1380*8ccd4a63SDavid du Colombier 
1381*8ccd4a63SDavid du Colombier /*
1382*8ccd4a63SDavid du Colombier  * name is valid. skip leading / and ./ as much as possible
1383*8ccd4a63SDavid du Colombier  */
1384*8ccd4a63SDavid du Colombier char*
1385*8ccd4a63SDavid du Colombier skipslash(char *name)
1386*8ccd4a63SDavid du Colombier {
1387*8ccd4a63SDavid du Colombier 	while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
1388*8ccd4a63SDavid du Colombier 		name++;
1389*8ccd4a63SDavid du Colombier 	return name;
1390*8ccd4a63SDavid du Colombier }
1391*8ccd4a63SDavid du Colombier 
1392*8ccd4a63SDavid du Colombier char isfrog[256]={
1393*8ccd4a63SDavid du Colombier 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,	/* 0 */
1394*8ccd4a63SDavid du Colombier 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */
1395*8ccd4a63SDavid du Colombier 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */
1396*8ccd4a63SDavid du Colombier 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */
1397*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1398*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */
1399*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */
1400*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */
1401*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1402*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */
1403*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1404*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */
1405*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
1406*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */
1407*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
1408*8ccd4a63SDavid du Colombier 		0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */
1409*8ccd4a63SDavid du Colombier };
1410*8ccd4a63SDavid du Colombier 
1411*8ccd4a63SDavid du Colombier /*
1412*8ccd4a63SDavid du Colombier  * Check that the name
1413*8ccd4a63SDavid du Colombier  *  a) is in valid memory.
1414*8ccd4a63SDavid du Colombier  *  b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
1415*8ccd4a63SDavid du Colombier  *  c) contains no frogs.
1416*8ccd4a63SDavid du Colombier  * The first byte is known to be addressible by the requester, so the
1417*8ccd4a63SDavid du Colombier  * routine works for kernel and user memory both.
1418*8ccd4a63SDavid du Colombier  * The parameter slashok flags whether a slash character is an error
1419*8ccd4a63SDavid du Colombier  * or a valid character.
1420*8ccd4a63SDavid du Colombier  */
1421*8ccd4a63SDavid du Colombier void
1422*8ccd4a63SDavid du Colombier validname(char *aname, int slashok)
1423*8ccd4a63SDavid du Colombier {
1424*8ccd4a63SDavid du Colombier 	char *ename, *name;
1425*8ccd4a63SDavid du Colombier 	int c;
1426*8ccd4a63SDavid du Colombier 	Rune r;
1427*8ccd4a63SDavid du Colombier 
1428*8ccd4a63SDavid du Colombier 	name = aname;
1429*8ccd4a63SDavid du Colombier /*
1430*8ccd4a63SDavid du Colombier 	if(((ulong)name & KZERO) != KZERO) {
1431*8ccd4a63SDavid du Colombier 		p = name;
1432*8ccd4a63SDavid du Colombier 		t = BY2PG-((ulong)p&(BY2PG-1));
1433*8ccd4a63SDavid du Colombier 		while((ename=vmemchr(p, 0, t)) == nil) {
1434*8ccd4a63SDavid du Colombier 			p += t;
1435*8ccd4a63SDavid du Colombier 			t = BY2PG;
1436*8ccd4a63SDavid du Colombier 		}
1437*8ccd4a63SDavid du Colombier 	}else
1438*8ccd4a63SDavid du Colombier */
1439*8ccd4a63SDavid du Colombier 		ename = memchr(name, 0, (1<<16));
1440*8ccd4a63SDavid du Colombier 
1441*8ccd4a63SDavid du Colombier 	if(ename==nil || ename-name>=(1<<16))
1442*8ccd4a63SDavid du Colombier 		error("name too long");
1443*8ccd4a63SDavid du Colombier 
1444*8ccd4a63SDavid du Colombier 	while(*name){
1445*8ccd4a63SDavid du Colombier 		/* all characters above '~' are ok */
1446*8ccd4a63SDavid du Colombier 		c = *(uchar*)name;
1447*8ccd4a63SDavid du Colombier 		if(c >= Runeself)
1448*8ccd4a63SDavid du Colombier 			name += chartorune(&r, name);
1449*8ccd4a63SDavid du Colombier 		else{
1450*8ccd4a63SDavid du Colombier 			if(isfrog[c])
1451*8ccd4a63SDavid du Colombier 				if(!slashok || c!='/'){
1452*8ccd4a63SDavid du Colombier 					snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
1453*8ccd4a63SDavid du Colombier 					error(up->genbuf);
1454*8ccd4a63SDavid du Colombier 			}
1455*8ccd4a63SDavid du Colombier 			name++;
1456*8ccd4a63SDavid du Colombier 		}
1457*8ccd4a63SDavid du Colombier 	}
1458*8ccd4a63SDavid du Colombier }
1459*8ccd4a63SDavid du Colombier 
1460*8ccd4a63SDavid du Colombier void
1461*8ccd4a63SDavid du Colombier isdir(Chan *c)
1462*8ccd4a63SDavid du Colombier {
1463*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
1464*8ccd4a63SDavid du Colombier 		return;
1465*8ccd4a63SDavid du Colombier 	error(Enotdir);
1466*8ccd4a63SDavid du Colombier }
1467*8ccd4a63SDavid du Colombier 
1468*8ccd4a63SDavid du Colombier /*
1469*8ccd4a63SDavid du Colombier  * This is necessary because there are many
1470*8ccd4a63SDavid du Colombier  * pointers to the top of a given mount list:
1471*8ccd4a63SDavid du Colombier  *
1472*8ccd4a63SDavid du Colombier  *	- the mhead in the namespace hash table
1473*8ccd4a63SDavid du Colombier  *	- the mhead in chans returned from findmount:
1474*8ccd4a63SDavid du Colombier  *	  used in namec and then by unionread.
1475*8ccd4a63SDavid du Colombier  *	- the mhead in chans returned from createdir:
1476*8ccd4a63SDavid du Colombier  *	  used in the open/create race protect, which is gone.
1477*8ccd4a63SDavid du Colombier  *
1478*8ccd4a63SDavid du Colombier  * The RWlock in the Mhead protects the mount list it contains.
1479*8ccd4a63SDavid du Colombier  * The mount list is deleted when we cunmount.
1480*8ccd4a63SDavid du Colombier  * The RWlock ensures that nothing is using the mount list at that time.
1481*8ccd4a63SDavid du Colombier  *
1482*8ccd4a63SDavid du Colombier  * It is okay to replace c->mh with whatever you want as
1483*8ccd4a63SDavid du Colombier  * long as you are sure you have a unique reference to it.
1484*8ccd4a63SDavid du Colombier  *
1485*8ccd4a63SDavid du Colombier  * This comment might belong somewhere else.
1486*8ccd4a63SDavid du Colombier  */
1487*8ccd4a63SDavid du Colombier void
1488*8ccd4a63SDavid du Colombier putmhead(Mhead *m)
1489*8ccd4a63SDavid du Colombier {
1490*8ccd4a63SDavid du Colombier 	if(m && decref(&m->ref) == 0){
1491*8ccd4a63SDavid du Colombier 		m->mount = (Mount*)0xCafeBeef;
1492*8ccd4a63SDavid du Colombier 		free(m);
1493*8ccd4a63SDavid du Colombier 	}
1494*8ccd4a63SDavid du Colombier }
1495