1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "9p1.h"
6
7 #define MAXFDATA (8*1024)
8 #define MAXRPC (MAXFDATA+160)
9
10 /*
11 * reassemble 9P messages for stream based protocols
12 * interposed between devmnt and the network by srv for tcp connections
13 * fcall expects devmnt on fd0, network fd1
14 */
15 uchar msglen[256] =
16 {
17 [Tnop9p1] 3,
18 [Rnop9p1] 3,
19 [Tsession9p1] 3+CHALLEN,
20 [Rsession9p1] 3+NAMEREC+DOMLEN+CHALLEN,
21 [Terror9p1] 0,
22 [Rerror9p1] 67,
23 [Tflush9p1] 5,
24 [Rflush9p1] 3,
25 [Tattach9p1] 5+2*NAMEREC+TICKETLEN+AUTHENTLEN,
26 [Rattach9p1] 13+AUTHENTLEN,
27 [Tclone9p1] 7,
28 [Rclone9p1] 5,
29 [Twalk9p1] 33,
30 [Rwalk9p1] 13,
31 [Topen9p1] 6,
32 [Ropen9p1] 13,
33 [Tcreate9p1] 38,
34 [Rcreate9p1] 13,
35 [Tread9p1] 15,
36 [Rread9p1] 8,
37 [Twrite9p1] 16,
38 [Rwrite9p1] 7,
39 [Tclunk9p1] 5,
40 [Rclunk9p1] 5,
41 [Tremove9p1] 5,
42 [Rremove9p1] 5,
43 [Tstat9p1] 5,
44 [Rstat9p1] 121,
45 [Twstat9p1] 121,
46 [Rwstat9p1] 5,
47 [Tclwalk9p1] 35,
48 [Rclwalk9p1] 13,
49 };
50
51 enum
52 {
53 Twritehdr = 16, /* Min bytes for Twrite */
54 Rreadhdr = 8, /* Min bytes for Rread */
55 Twritecnt = 13, /* Offset in byte stream of write count */
56 Rreadcnt = 5, /* Offset for Readcnt */
57 };
58
59 int
mntrpclen(uchar * d,int n)60 mntrpclen(uchar *d, int n)
61 {
62 uchar t;
63 int len, off;
64
65 if(n < 1)
66 return 0;
67
68 t = d[0];
69 switch(t) { /* This is the type */
70 default:
71 len = msglen[t];
72 if(len == 0) /* Illegal type so consume */
73 return n;
74 if(n < len)
75 return 0;
76 return len;
77 case Twrite9p1: /* Fmt: TGGFFOOOOOOOOCC */
78 len = Twritehdr; /* T = type, G = tag, F = fid */
79 off = Twritecnt; /* O = offset, C = count */
80 break;
81 case Rread9p1: /* Fmt: TGGFFCC */
82 len = Rreadhdr;
83 off = Rreadcnt;
84 break;
85 }
86 if(n < off+2)
87 return 0;
88
89 len += d[off]|(d[off+1]<<8);
90 if(n < len)
91 return 0;
92
93 return len;
94 }
95
96 int
fcall(int fd)97 fcall(int fd)
98 {
99 int i, r, n, l;
100 uchar *p, *buf;
101 int pipefd[2];
102
103 if(pipe(pipefd) < 0)
104 fatal("fcall pipe: %r");
105
106 buf = malloc(MAXRPC);
107 if(buf == nil)
108 fatal("fcall malloc");
109
110 switch(rfork(RFPROC|RFMEM|RFFDG|RFCNAMEG)){
111 default:
112 return pipefd[0]; /* parent returns fd */
113 case 0:
114 break; /* child builds buffers */
115 case -1:
116 fatal("fcall fork: %r");
117 }
118
119 /* close file descriptors */
120 for(i=0; i<20; i++)
121 if(i!=fd && i!=pipefd[1])
122 close(i);
123
124 l = MAXRPC;
125 p = buf;
126 for(;;) {
127 n = read(fd, p, l);
128 if(n < 0)
129 break;
130 p += n;
131 l -= n;
132
133 for(;;) {
134 r = mntrpclen(buf, p - buf);
135 if(r == 0)
136 break;
137
138 if(write(pipefd[1], buf, r) < 0)
139 break;
140
141 n = (p - buf) - r;
142 memmove(buf, buf+r, n);
143 p = buf+n;
144 l = MAXRPC - n;
145 }
146 }
147 close(pipefd[1]);
148 fatal(nil);
149 return -1;
150 }
151