xref: /plan9/sys/src/cmd/unix/drawterm/exportfs/exportsrv.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #define Extern	extern
5 #include "exportfs.h"
6 
7 char Ebadfid[] = "Bad fid";
8 char Enotdir[] = "Not a directory";
9 char Edupfid[] = "Fid already in use";
10 char Eopen[] = "Fid already opened";
11 char Exmnt[] = "Cannot .. past mount point";
12 char Emip[] = "Mount in progress";
13 char Enopsmt[] = "Out of pseudo mount points";
14 char Enomem[] = "No memory";
15 char Eversion[] = "Bad 9P2000 version";
16 
iounit(int x)17 int iounit(int x)
18 {
19 	return 8*8192+IOHDRSZ;
20 }
21 
22 void*
emallocz(ulong n)23 emallocz(ulong n)
24 {
25 	void *v;
26 
27 	v = mallocz(n, 1);
28 	if(v == nil)
29 		panic("out of memory");
30 	return v;
31 }
32 
33 
34 void
Xversion(Fsrpc * t)35 Xversion(Fsrpc *t)
36 {
37 	Fcall rhdr;
38 
39 	if(t->work.msize > messagesize)
40 		t->work.msize = messagesize;
41 	messagesize = t->work.msize;
42 	if(strncmp(t->work.version, "9P2000", 6) != 0){
43 		reply(&t->work, &rhdr, Eversion);
44 		return;
45 	}
46 	rhdr.version = "9P2000";
47 	rhdr.msize = t->work.msize;
48 	reply(&t->work, &rhdr, 0);
49 	t->busy = 0;
50 }
51 
52 void
Xauth(Fsrpc * t)53 Xauth(Fsrpc *t)
54 {
55 	Fcall rhdr;
56 
57 	reply(&t->work, &rhdr, "exportfs: authentication not required");
58 	t->busy = 0;
59 }
60 
61 void
Xflush(Fsrpc * t)62 Xflush(Fsrpc *t)
63 {
64 	Fsrpc *w, *e;
65 	Fcall rhdr;
66 
67 	e = &Workq[Nr_workbufs];
68 
69 	for(w = Workq; w < e; w++) {
70 		if(w->work.tag == t->work.oldtag) {
71 			DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
72 			if(w->busy && w->pid) {
73 				w->flushtag = t->work.tag;
74 				DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
75 			//	if(w->canint)
76 			//		postnote(PNPROC, w->pid, "flush");
77 				t->busy = 0;
78 				return;
79 			}
80 		}
81 	}
82 
83 	reply(&t->work, &rhdr, 0);
84 	DEBUG(DFD, "\tflush reply\n");
85 	t->busy = 0;
86 }
87 
88 void
Xattach(Fsrpc * t)89 Xattach(Fsrpc *t)
90 {
91 	Fcall rhdr;
92 	Fid *f;
93 
94 	f = newfid(t->work.fid);
95 	if(f == 0) {
96 		reply(&t->work, &rhdr, Ebadfid);
97 		t->busy = 0;
98 		return;
99 	}
100 
101 	if(srvfd >= 0){
102 /*
103 		if(psmpt == 0){
104 		Nomount:
105 			reply(&t->work, &rhdr, Enopsmt);
106 			t->busy = 0;
107 			freefid(t->work.fid);
108 			return;
109 		}
110 		for(i=0; i<Npsmpt; i++)
111 			if(psmap[i] == 0)
112 				break;
113 		if(i >= Npsmpt)
114 			goto Nomount;
115 		sprint(buf, "%d", i);
116 		f->f = file(psmpt, buf);
117 		if(f->f == nil)
118 			goto Nomount;
119 		sprint(buf, "/mnt/exportfs/%d", i);
120 		nfd = dup(srvfd, -1);
121 		if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
122 			errstr(buf, sizeof buf);
123 			reply(&t->work, &rhdr, buf);
124 			t->busy = 0;
125 			freefid(t->work.fid);
126 			close(nfd);
127 			return;
128 		}
129 		psmap[i] = 1;
130 		f->mid = i;
131 */
132 	}else{
133 		f->f = root;
134 		f->f->ref++;
135 	}
136 
137 	rhdr.qid = f->f->qid;
138 	reply(&t->work, &rhdr, 0);
139 	t->busy = 0;
140 }
141 
142 Fid*
clonefid(Fid * f,int new)143 clonefid(Fid *f, int new)
144 {
145 	Fid *n;
146 
147 	n = newfid(new);
148 	if(n == 0) {
149 		n = getfid(new);
150 		if(n == 0)
151 			fatal("inconsistent fids");
152 		if(n->fid >= 0)
153 			close(n->fid);
154 		freefid(new);
155 		n = newfid(new);
156 		if(n == 0)
157 			fatal("inconsistent fids2");
158 	}
159 	n->f = f->f;
160 	n->f->ref++;
161 	return n;
162 }
163 
164 void
Xwalk(Fsrpc * t)165 Xwalk(Fsrpc *t)
166 {
167 	char err[ERRMAX], *e;
168 	Fcall rhdr;
169 	Fid *f, *nf;
170 	File *wf;
171 	int i;
172 
173 	f = getfid(t->work.fid);
174 	if(f == 0) {
175 		reply(&t->work, &rhdr, Ebadfid);
176 		t->busy = 0;
177 		return;
178 	}
179 
180 	nf = nil;
181 	if(t->work.newfid != t->work.fid){
182 		nf = clonefid(f, t->work.newfid);
183 		f = nf;
184 	}
185 
186 	rhdr.nwqid = 0;
187 	e = nil;
188 	for(i=0; i<t->work.nwname; i++){
189 		if(i == MAXWELEM){
190 			e = "Too many path elements";
191 			break;
192 		}
193 
194 		if(strcmp(t->work.wname[i], "..") == 0) {
195 			if(f->f->parent == nil) {
196 				e = Exmnt;
197 				break;
198 			}
199 			wf = f->f->parent;
200 			wf->ref++;
201 			goto Accept;
202 		}
203 
204 		wf = file(f->f, t->work.wname[i]);
205 		if(wf == 0){
206 			errstr(err, sizeof err);
207 			e = err;
208 			break;
209 		}
210     Accept:
211 		freefile(f->f);
212 		rhdr.wqid[rhdr.nwqid++] = wf->qid;
213 		f->f = wf;
214 		continue;
215 	}
216 
217 	if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
218 		freefid(t->work.newfid);
219 	if(rhdr.nwqid > 0)
220 		e = nil;
221 	reply(&t->work, &rhdr, e);
222 	t->busy = 0;
223 }
224 
225 void
Xclunk(Fsrpc * t)226 Xclunk(Fsrpc *t)
227 {
228 	Fcall rhdr;
229 	Fid *f;
230 
231 	f = getfid(t->work.fid);
232 	if(f == 0) {
233 		reply(&t->work, &rhdr, Ebadfid);
234 		t->busy = 0;
235 		return;
236 	}
237 
238 	if(f->fid >= 0)
239 		close(f->fid);
240 
241 	freefid(t->work.fid);
242 	reply(&t->work, &rhdr, 0);
243 	t->busy = 0;
244 }
245 
246 void
Xstat(Fsrpc * t)247 Xstat(Fsrpc *t)
248 {
249 	char err[ERRMAX], *path;
250 	Fcall rhdr;
251 	Fid *f;
252 	Dir *d;
253 	int s;
254 	uchar *statbuf;
255 
256 	f = getfid(t->work.fid);
257 	if(f == 0) {
258 		reply(&t->work, &rhdr, Ebadfid);
259 		t->busy = 0;
260 		return;
261 	}
262 	if(f->fid >= 0)
263 		d = dirfstat(f->fid);
264 	else {
265 		path = makepath(f->f, "");
266 		d = dirstat(path);
267 		free(path);
268 	}
269 
270 	if(d == nil) {
271 		errstr(err, sizeof err);
272 		reply(&t->work, &rhdr, err);
273 		t->busy = 0;
274 		return;
275 	}
276 
277 	d->qid.path = f->f->qidt->uniqpath;
278 	s = sizeD2M(d);
279 	statbuf = emallocz(s);
280 	s = convD2M(d, statbuf, s);
281 	free(d);
282 	rhdr.nstat = s;
283 	rhdr.stat = statbuf;
284 	reply(&t->work, &rhdr, 0);
285 	free(statbuf);
286 	t->busy = 0;
287 }
288 
289 static int
getiounit(int fd)290 getiounit(int fd)
291 {
292 	int n;
293 
294 	n = iounit(fd);
295 	if(n > messagesize-IOHDRSZ)
296 		n = messagesize-IOHDRSZ;
297 	return n;
298 }
299 
300 void
Xcreate(Fsrpc * t)301 Xcreate(Fsrpc *t)
302 {
303 	char err[ERRMAX], *path;
304 	Fcall rhdr;
305 	Fid *f;
306 	File *nf;
307 
308 	f = getfid(t->work.fid);
309 	if(f == 0) {
310 		reply(&t->work, &rhdr, Ebadfid);
311 		t->busy = 0;
312 		return;
313 	}
314 
315 
316 	path = makepath(f->f, t->work.name);
317 	f->fid = create(path, t->work.mode, t->work.perm);
318 	free(path);
319 	if(f->fid < 0) {
320 		errstr(err, sizeof err);
321 		reply(&t->work, &rhdr, err);
322 		t->busy = 0;
323 		return;
324 	}
325 
326 	nf = file(f->f, t->work.name);
327 	if(nf == 0) {
328 		errstr(err, sizeof err);
329 		reply(&t->work, &rhdr, err);
330 		t->busy = 0;
331 		return;
332 	}
333 
334 	f->mode = t->work.mode;
335 	freefile(f->f);
336 	f->f = nf;
337 	rhdr.qid = f->f->qid;
338 	rhdr.iounit = getiounit(f->fid);
339 	reply(&t->work, &rhdr, 0);
340 	t->busy = 0;
341 }
342 
343 void
Xremove(Fsrpc * t)344 Xremove(Fsrpc *t)
345 {
346 	char err[ERRMAX], *path;
347 	Fcall rhdr;
348 	Fid *f;
349 
350 	f = getfid(t->work.fid);
351 	if(f == 0) {
352 		reply(&t->work, &rhdr, Ebadfid);
353 		t->busy = 0;
354 		return;
355 	}
356 
357 	path = makepath(f->f, "");
358 	DEBUG(DFD, "\tremove: %s\n", path);
359 	if(remove(path) < 0) {
360 		free(path);
361 		errstr(err, sizeof err);
362 		reply(&t->work, &rhdr, err);
363 		t->busy = 0;
364 		return;
365 	}
366 	free(path);
367 
368 	f->f->inval = 1;
369 	if(f->fid >= 0)
370 		close(f->fid);
371 	freefid(t->work.fid);
372 
373 	reply(&t->work, &rhdr, 0);
374 	t->busy = 0;
375 }
376 
377 void
Xwstat(Fsrpc * t)378 Xwstat(Fsrpc *t)
379 {
380 	char err[ERRMAX], *path;
381 	Fcall rhdr;
382 	Fid *f;
383 	int s;
384 	char *strings;
385 	Dir d;
386 
387 	f = getfid(t->work.fid);
388 	if(f == 0) {
389 		reply(&t->work, &rhdr, Ebadfid);
390 		t->busy = 0;
391 		return;
392 	}
393 	strings = emallocz(t->work.nstat);	/* ample */
394 	if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
395 		rerrstr(err, sizeof err);
396 		reply(&t->work, &rhdr, err);
397 		t->busy = 0;
398 		free(strings);
399 		return;
400 	}
401 
402 	if(f->fid >= 0)
403 		s = dirfwstat(f->fid, &d);
404 	else {
405 		path = makepath(f->f, "");
406 		s = dirwstat(path, &d);
407 		free(path);
408 	}
409 	if(s < 0) {
410 		rerrstr(err, sizeof err);
411 		reply(&t->work, &rhdr, err);
412 	}
413 	else {
414 		/* wstat may really be rename */
415 		if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
416 			free(f->f->name);
417 			f->f->name = estrdup(d.name);
418 		}
419 		reply(&t->work, &rhdr, 0);
420 	}
421 	free(strings);
422 	t->busy = 0;
423 }
424 
425 void
slave(Fsrpc * f)426 slave(Fsrpc *f)
427 {
428 	Proc *p;
429 	int pid;
430 	static int nproc;
431 
432 	for(;;) {
433 		for(p = Proclist; p; p = p->next) {
434 			if(p->busy == 0) {
435 				f->pid = p->pid;
436 				p->busy = 1;
437 				pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f);
438 				if(pid != p->pid)
439 					fatal("rendezvous sync fail");
440 				return;
441 			}
442 		}
443 
444 		if(++nproc > MAXPROC)
445 			fatal("too many procs");
446 
447 		pid = kproc("slave", blockingslave, nil);
448 		DEBUG(DFD, "slave pid %d\n", pid);
449 		if(pid == -1)
450 			fatal("kproc");
451 
452 		p = malloc(sizeof(Proc));
453 		if(p == 0)
454 			fatal("out of memory");
455 
456 		p->busy = 0;
457 		p->pid = pid;
458 		p->next = Proclist;
459 		Proclist = p;
460 
461 DEBUG(DFD, "parent %d rendez\n", pid);
462 		rendezvous((void*)(uintptr)pid, p);
463 DEBUG(DFD, "parent %d went\n", pid);
464 	}
465 }
466 
467 void
blockingslave(void * x)468 blockingslave(void *x)
469 {
470 	Fsrpc *p;
471 	Fcall rhdr;
472 	Proc *m;
473 	int pid;
474 
475 	USED(x);
476 
477 	notify(flushaction);
478 
479 	pid = getpid();
480 
481 DEBUG(DFD, "blockingslave %d rendez\n", pid);
482 	m = (Proc*)rendezvous((void*)(uintptr)pid, 0);
483 DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
484 
485 	for(;;) {
486 		p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid);
487 		if((uintptr)p == ~(uintptr)0)			/* Interrupted */
488 			continue;
489 
490 		DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
491 		if(p->flushtag != NOTAG)
492 			goto flushme;
493 
494 		switch(p->work.type) {
495 		case Tread:
496 			slaveread(p);
497 			break;
498 
499 		case Twrite:
500 			slavewrite(p);
501 			break;
502 
503 		case Topen:
504 			slaveopen(p);
505 			break;
506 
507 		default:
508 			reply(&p->work, &rhdr, "exportfs: slave type error");
509 		}
510 		if(p->flushtag != NOTAG) {
511 flushme:
512 			p->work.type = Tflush;
513 			p->work.tag = p->flushtag;
514 			reply(&p->work, &rhdr, 0);
515 		}
516 		p->busy = 0;
517 		m->busy = 0;
518 	}
519 }
520 
521 int
openmount(int sfd)522 openmount(int sfd)
523 {
524 	werrstr("openmount not implemented");
525 	return -1;
526 }
527 
528 void
slaveopen(Fsrpc * p)529 slaveopen(Fsrpc *p)
530 {
531 	char err[ERRMAX], *path;
532 	Fcall *work, rhdr;
533 	Fid *f;
534 	Dir *d;
535 
536 	work = &p->work;
537 
538 	f = getfid(work->fid);
539 	if(f == 0) {
540 		reply(work, &rhdr, Ebadfid);
541 		return;
542 	}
543 	if(f->fid >= 0) {
544 		close(f->fid);
545 		f->fid = -1;
546 	}
547 
548 	path = makepath(f->f, "");
549 	DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
550 
551 	p->canint = 1;
552 	if(p->flushtag != NOTAG){
553 		free(path);
554 		return;
555 	}
556 	/* There is a race here I ignore because there are no locks */
557 	f->fid = open(path, work->mode);
558 	free(path);
559 	p->canint = 0;
560 	if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
561 	Error:
562 		errstr(err, sizeof err);
563 		reply(work, &rhdr, err);
564 		return;
565 	}
566 	f->f->qid = d->qid;
567 	free(d);
568 	if(f->f->qid.type & QTMOUNT){	/* fork new exportfs for this */
569 		f->fid = openmount(f->fid);
570 		if(f->fid < 0)
571 			goto Error;
572 	}
573 
574 	DEBUG(DFD, "\topen: fd %d\n", f->fid);
575 	f->mode = work->mode;
576 	rhdr.iounit = getiounit(f->fid);
577 	rhdr.qid = f->f->qid;
578 	reply(work, &rhdr, 0);
579 }
580 
581 void
slaveread(Fsrpc * p)582 slaveread(Fsrpc *p)
583 {
584 	Fid *f;
585 	int n, r;
586 	Fcall *work, rhdr;
587 	char *data, err[ERRMAX];
588 
589 	work = &p->work;
590 
591 	f = getfid(work->fid);
592 	if(f == 0) {
593 		reply(work, &rhdr, Ebadfid);
594 		return;
595 	}
596 
597 	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
598 	p->canint = 1;
599 	if(p->flushtag != NOTAG)
600 		return;
601 	data = malloc(n);
602 	if(data == nil)
603 		fatal(Enomem);
604 
605 	/* can't just call pread, since directories must update the offset */
606 	r = pread(f->fid, data, n, work->offset);
607 	p->canint = 0;
608 	if(r < 0) {
609 		free(data);
610 		errstr(err, sizeof err);
611 		reply(work, &rhdr, err);
612 		return;
613 	}
614 
615 	DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
616 
617 	rhdr.data = data;
618 	rhdr.count = r;
619 	reply(work, &rhdr, 0);
620 	free(data);
621 }
622 
623 void
slavewrite(Fsrpc * p)624 slavewrite(Fsrpc *p)
625 {
626 	char err[ERRMAX];
627 	Fcall *work, rhdr;
628 	Fid *f;
629 	int n;
630 
631 	work = &p->work;
632 
633 	f = getfid(work->fid);
634 	if(f == 0) {
635 		reply(work, &rhdr, Ebadfid);
636 		return;
637 	}
638 
639 	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
640 	p->canint = 1;
641 	if(p->flushtag != NOTAG)
642 		return;
643 	n = pwrite(f->fid, work->data, n, work->offset);
644 	p->canint = 0;
645 	if(n < 0) {
646 		errstr(err, sizeof err);
647 		reply(work, &rhdr, err);
648 		return;
649 	}
650 
651 	DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
652 
653 	rhdr.count = n;
654 	reply(work, &rhdr, 0);
655 }
656 
657 void
reopen(Fid * f)658 reopen(Fid *f)
659 {
660 	USED(f);
661 	fatal("reopen");
662 }
663 
664 void
flushaction(void * a,char * cause)665 flushaction(void *a, char *cause)
666 {
667 	USED(a);
668 	if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
669 		fprint(2, "exportsrv: note: %s\n", cause);
670 		exits("noted");
671 	}
672 	if(strncmp(cause, "kill", 4) == 0)
673 		noted(NDFLT);
674 
675 	noted(NCONT);
676 }
677