xref: /plan9/sys/src/cmd/disk/kfs/9p12.c (revision 12fd1c83b21b4d1deeab2b58fe2c202d2038c714)
1 #include "all.h"
2 
3 static int
readmsg(Chan * c,void * abuf,int n,int * ninep)4 readmsg(Chan *c, void *abuf, int n, int *ninep)
5 {
6 	int fd, len;
7 	uchar *buf;
8 
9 	buf = abuf;
10 	fd = c->chan;
11 	qlock(&c->rlock);
12 	if(readn(fd, buf, 3) != 3){
13 		qunlock(&c->rlock);
14 		print("readn(3) fails: %r\n");
15 		return -1;
16 	}
17 	if((50 <= buf[0] && buf[0] <= 87 && (buf[0]&1)==0 && GBIT16(buf+1) == 0xFFFF)
18 	|| buf[0] == 86	/* Tattach */){
19 		*ninep = 1;
20 		/* assume message boundaries */
21 		n = read(fd, buf+3, n-3);
22 		if(n < 0){
23 			qunlock(&c->rlock);
24 			return -1;
25 		}
26 		return n+3;
27 	}
28 
29 	*ninep = 2;
30 	if(read(fd, buf+3, 1) != 1){
31 		qunlock(&c->rlock);
32 		print("read(1) fails: %r\n");
33 		return -1;
34 	}
35 	len = GBIT32(buf);
36 	if(len > n){
37 		print("msg too large\n");
38 		qunlock(&c->rlock);
39 		return -1;
40 	}
41 	if(readn(fd, buf+4, len-4) != len-4){
42 		print("readn(%d) fails: %r\n", len-4);
43 		qunlock(&c->rlock);
44 		return -1;
45 	}
46 	qunlock(&c->rlock);
47 	return len;
48 }
49 
50 int
startserveproc(void (* f)(Chan *,uchar *,int),char * name,Chan * c,uchar * b,int nb)51 startserveproc(void (*f)(Chan*, uchar*, int), char *name, Chan *c, uchar *b, int nb)
52 {
53 	int pid;
54 
55 	switch(pid = rfork(RFMEM|RFPROC)){
56 	case -1:
57 		panic("can't fork");
58 	case 0:
59 		break;
60 	default:
61 		return pid;
62 	}
63 	procname = name;
64 	f(c, b, nb);
65 	_exits(nil);
66 	return -1;	/* can't happen */
67 }
68 
69 void
serve(Chan * chan)70 serve(Chan *chan)
71 {
72 	int i, nin, p9, npid;
73 	uchar inbuf[1024];
74 	void (*s)(Chan*, uchar*, int);
75 	int *pid;
76 	Waitmsg *w;
77 
78 	p9 = 0;
79 	if((nin = readmsg(chan, inbuf, sizeof inbuf, &p9)) < 0)
80 		return;
81 
82 	switch(p9){
83 	default:
84 		print("unknown 9P type\n");
85 		return;
86 	case 1:
87 		s = serve9p1;
88 		break;
89 	case 2:
90 		s = serve9p2;
91 		break;
92 	}
93 
94 	pid = malloc(sizeof(pid)*(conf.nserve-1));
95 	if(pid == nil)
96 		return;
97 	for(i=1; i<conf.nserve; i++)
98 		pid[i-1] = startserveproc(s, "srv", chan, nil, 0);
99 
100 	(*s)(chan, inbuf, nin);
101 
102 	/* wait till all other servers for this chan are done */
103 	for(npid = conf.nserve-1; npid > 0;){
104 		w = wait();
105 		if(w == 0)
106 			break;
107 		for(i = 0; i < conf.nserve-1; i++)
108 			if(pid[i] == w->pid)
109 				npid--;
110 		free(w);
111 	}
112 	free(pid);
113 }
114 
115