xref: /inferno-os/emu/Plan9/devsrv9.c (revision 80146ec649f45bdf6575689b673bc11acaacb920)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 
5 typedef struct Srv Srv;
6 struct Srv
7 {
8 	Ref;
9 	int	fd;	/* fd for opened /srv or /srv/X, or -1 */
10 	int	sfd;	/* fd for created /srv entry or -1 */
11 	uvlong	path;
12 	Srv	*next;
13 };
14 
15 static QLock	srv9lk;
16 static Srv	*srv9;
17 static Srv	*srvroot;
18 
19 static char*
srvname(Chan * c)20 srvname(Chan *c)
21 {
22 	char *p;
23 
24 	p = strrchr(c->name->s, '/');
25 	if(p == nil)
26 		return "";
27 	return p+1;
28 }
29 
30 static Srv*
srvget(uvlong path)31 srvget(uvlong path)
32 {
33 	Srv *sv;
34 
35 	qlock(&srv9lk);
36 	for(sv = srv9; sv != nil; sv = sv->next)
37 		if(sv->path == path){
38 			incref(sv);
39 			qunlock(&srv9lk);
40 			return sv;
41 		}
42 	sv = smalloc(sizeof(*sv));
43 	sv->path = path;
44 	sv->fd = -1;
45 	sv->sfd = -1;
46 	sv->ref = 1;
47 	sv->next = srv9;
48 	srv9 = sv;
49 	qunlock(&srv9lk);
50 	return sv;
51 }
52 
53 static void
srvput(Srv * sv)54 srvput(Srv *sv)
55 {
56 	Srv **l;
57 	int fd, sfd;
58 
59 	if(sv != nil && decref(sv) == 0){
60 		qlock(&srv9lk);
61 		for(l = &srv9; *l != nil; l = &(*l)->next)
62 			if(*l == sv){
63 				*l = sv->next;
64 				break;
65 			}
66 		qunlock(&srv9lk);
67 		fd = sv->fd;
68 		sfd = sv->sfd;
69 		free(sv);
70 		if(sfd >= 0){
71 			osenter();
72 			close(sfd);
73 			osleave();
74 		}
75 		if(fd >= 0){
76 			osenter();
77 			close(fd);
78 			osleave();
79 		}
80 	}
81 }
82 
83 static void
srv9init(void)84 srv9init(void)
85 {
86 	Srv *sv;
87 
88 	sv = mallocz(sizeof(*srvroot), 1);
89 	sv->path = 0;
90 	sv->fd = -1;
91 	sv->ref = 1;	/* subsequently never reaches zero */
92 	srvroot = srv9 = sv;
93 }
94 
95 static Chan*
srv9attach(char * spec)96 srv9attach(char *spec)
97 {
98 	Chan *c;
99 
100 	if(*spec)
101 		error(Ebadspec);
102 	c = devattach(L'₪', spec);
103 	if(c != nil){
104 		incref(srvroot);
105 		c->aux = srvroot;
106 	}
107 	return c;
108 }
109 
110 static Walkqid*
srv9walk(Chan * c,Chan * nc,char ** name,int nname)111 srv9walk(Chan *c, Chan *nc, char **name, int nname)
112 {
113 	int j, alloc;
114 	Walkqid *wq;
115 	char *n;
116 	Dir *d;
117 
118 	if(nname > 0)
119 		isdir(c);
120 
121 	alloc = 0;
122 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
123 	if(waserror()){
124 		if(alloc)
125 			cclose(wq->clone);
126 		free(wq);
127 		return nil;
128 	}
129 	if(nc == nil){
130 		nc = devclone(c);
131 		nc->type = 0;	/* device doesn't know about this channel yet */
132 		alloc = 1;
133 	}
134 	wq->clone = nc;
135 
136 	for(j=0; j<nname; j++){
137 		if(!(nc->qid.type&QTDIR)){
138 			if(j==0)
139 				error(Enotdir);
140 			break;
141 		}
142 		n = name[j];
143 		if(strcmp(n, ".") != 0 && strcmp(n, "..") != 0){
144 			snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", n);
145 			d = dirstat(up->genbuf);
146 			if(d == nil){
147 				if(j == 0)
148 					error(Enonexist);
149 				kstrcpy(up->env->errstr, Enonexist, ERRMAX);
150 				break;
151 			}
152 			nc->qid = d->qid;
153 			free(d);
154 		}
155 		wq->qid[wq->nqid++] = nc->qid;
156 	}
157 	poperror();
158 	if(wq->nqid < nname){
159 		if(alloc)
160 			cclose(wq->clone);
161 		wq->clone = nil;
162 	}else{
163 		/* attach cloned channel to device */
164 		wq->clone->type = c->type;
165 		if(wq->clone != c)
166 			nc->aux = srvget(nc->qid.path);
167 	}
168 	return wq;
169 }
170 
171 static int
srv9stat(Chan * c,uchar * db,int n)172 srv9stat(Chan *c, uchar *db, int n)
173 {
174 	Srv *sv;
175 	Dir d;
176 
177 	if(c->qid.type & QTDIR){
178 		devdir(c, c->qid, "#₪", 0, eve, 0775, &d);
179 		n = convD2M(&d, db, n);
180 		if(n == 0)
181 			error(Eshortstat);
182 		return n;
183 	}
184 	sv = c->aux;
185 	if(sv->fd >= 0){
186 		osenter();
187 		n = fstat(sv->fd, db, n);
188 		osleave();
189 	}else{
190 		osenter();
191 		n = stat(srvname(c), db, n);
192 		osleave();
193 	}
194 	return n;
195 }
196 
197 static Chan*
srv9open(Chan * c,int omode)198 srv9open(Chan *c, int omode)
199 {
200 	Srv *sv;
201 	char *args[10];
202 	int fd[2], i, ifd, is9p;
203 	Dir *d;
204 
205 	sv = c->aux;
206 	if(c->qid.type == QTDIR){
207 		osenter();
208 		sv->fd = open("/srv", omode);
209 		osleave();
210 		if(sv->fd < 0)
211 			oserror();
212 		c->mode = omode;
213 		c->flag |= COPEN;
214 		c->offset = 0;
215 		return c;
216 	}
217 
218 	if(omode&OTRUNC || openmode(omode) != ORDWR)
219 		error(Eperm);
220 	if(sv->fd < 0){
221 		snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", srvname(c));
222 
223 		/* check permission */
224 		osenter();
225 		ifd = open(up->genbuf, omode);
226 		osleave();
227 		if(ifd < 0)
228 			oserror();
229 		osenter();
230 		d = dirfstat(ifd);
231 		is9p = d != nil && d->qid.type & QTMOUNT;
232 		free(d);
233 		osleave();
234 
235 		if(is9p){
236 			close(ifd);
237 
238 			/* spawn exportfs */
239 			args[0] = "exportfs";
240 			args[1] = "-S";
241 			args[2] = up->genbuf;
242 			args[3] = nil;
243 			if(pipe(fd) < 0)
244 				oserror();
245 			/* TO DO: without RFMEM there's a copy made of each page touched by any kproc until the exec */
246 			switch(rfork(RFPROC|RFNOWAIT|RFREND|RFFDG|RFNAMEG|RFENVG)){	/* no sharing except NOTEG */
247 			case -1:
248 				oserrstr(up->genbuf, sizeof(up->genbuf));
249 				close(fd[0]);
250 				close(fd[1]);
251 				error(up->genbuf);
252 			case 0:
253 				for(i=3; i<MAXNFD; i++)
254 					if(i != fd[1])
255 						close(i);
256 				dup(fd[1], 0);
257 				if(fd[0] != 0)
258 					close(fd[0]);
259 				dup(0, 1);
260 				exec("/bin/exportfs", args);
261 				exits("exportfs failed");
262 			default:
263 				sv->fd = fd[0];
264 				close(fd[1]);
265 				break;
266 			}
267 		}else
268 			sv->fd = ifd;
269 	}
270 
271 	c->mode = ORDWR;
272 	c->offset = 0;
273 	c->flag |= COPEN;
274 	return c;
275 }
276 
277 static void
srv9close(Chan * c)278 srv9close(Chan *c)
279 {
280 	srvput(c->aux);
281 }
282 
283 static long
srv9read(Chan * c,void * va,long n,vlong off)284 srv9read(Chan *c, void *va, long n, vlong off)
285 {
286 	Srv *sv;
287 
288 	sv = c->aux;
289 	osenter();
290 	n = pread(sv->fd, va, n, off);
291 	osleave();
292 	if(n < 0)
293 		oserror();
294 	return n;
295 }
296 
297 static long
srv9write(Chan * c,void * va,long n,vlong off)298 srv9write(Chan *c, void *va, long n, vlong off)
299 {
300 	Srv *sv;
301 
302 	sv = c->aux;
303 	osenter();
304 	n = pwrite(sv->fd, va, n, off);
305 	osleave();
306 	if(n == 0)
307 		error(Ehungup);
308 	if(n < 0)
309 		oserror();
310 	return n;
311 }
312 
313 static void
srv9create(Chan * c,char * name,int omode,ulong perm)314 srv9create(Chan *c, char *name, int omode, ulong perm)
315 {
316 	Srv *sv;
317 	int sfd, fd[2];
318 	vlong path;
319 	Dir *d;
320 
321 	if(openmode(omode) != ORDWR)
322 		error(Eperm);
323 
324 	if(pipe(fd) < 0)
325 		oserror();
326 	if(waserror()){
327 		close(fd[0]);
328 		close(fd[1]);
329 		nexterror();
330 	}
331 
332 	snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", name);
333 	osenter();
334 	sfd = create(up->genbuf, OWRITE|ORCLOSE, perm);
335 	osleave();
336 	if(sfd < 0)
337 		oserror();
338 	if(waserror()){
339 		close(sfd);
340 		nexterror();
341 	}
342 	osenter();
343 	if(fprint(sfd, "%d", fd[1]) < 0){
344 		osleave();
345 		oserror();
346 	}
347 	d = dirfstat(sfd);
348 	osleave();
349 	if(d != nil){
350 		path = d->qid.path;
351 		free(d);
352 	}else
353 		oserror();
354 
355 	poperror();
356 	poperror();
357 	close(fd[1]);
358 
359 	if(waserror()){
360 		close(sfd);
361 		close(fd[0]);
362 		nexterror();
363 	}
364 	sv = srvget(path);
365 	sv->fd = fd[0];
366 	sv->sfd = sfd;
367 	poperror();
368 
369 	srvput((Srv*)c->aux);
370 	c->qid.type = QTFILE;
371 	c->qid.path = path;
372 	c->aux = sv;
373 	c->flag |= COPEN;
374 	c->mode = ORDWR;
375 	c->offset = 0;
376 }
377 
378 Dev srv9devtab = {
379 	L'₪',
380 	"srv9",
381 
382 	srv9init,
383 	srv9attach,
384 	srv9walk,
385 	srv9stat,
386 	srv9open,
387 	srv9create,	/* TO DO */
388 	srv9close,
389 	srv9read,
390 	devbread,
391 	srv9write,
392 	devbwrite,
393 	devremove,	/* TO DO */
394 	devwstat,	/* TO DO */
395 };
396