1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <bio.h>
6
7 uint messagesize = 65536; /* just a buffer size */
8
9 void
usage(void)10 usage(void)
11 {
12 fprint(2, "usage: aux/9pcon [-m messagesize] /srv/service | -c command | -n networkaddress\n");
13 exits("usage");
14 }
15
16 int
connectcmd(char * cmd)17 connectcmd(char *cmd)
18 {
19 int p[2];
20
21 if(pipe(p) < 0)
22 return -1;
23 switch(fork()){
24 case -1:
25 fprint(2, "fork failed: %r\n");
26 _exits("exec");
27 case 0:
28 dup(p[0], 0);
29 dup(p[0], 1);
30 close(p[1]);
31 execl("/bin/rc", "rc", "-c", cmd, nil);
32 fprint(2, "exec failed: %r\n");
33 _exits("exec");
34 default:
35 close(p[0]);
36 return p[1];
37 }
38 }
39
40 void
watch(int fd)41 watch(int fd)
42 {
43 int n;
44 uchar *buf;
45 Fcall f;
46
47 buf = malloc(messagesize);
48 if(buf == nil)
49 sysfatal("out of memory");
50
51 while((n = read9pmsg(fd, buf, messagesize)) > 0){
52 if(convM2S(buf, n, &f) == 0){
53 print("convM2S: %r\n");
54 continue;
55 }
56 print("\t<- %F\n", &f);
57 }
58 if(n == 0)
59 print("server eof\n");
60 else
61 print("read9pmsg from server: %r\n");
62 }
63
64 char*
tversion(Fcall * f,int,char ** argv)65 tversion(Fcall *f, int, char **argv)
66 {
67 f->msize = atoi(argv[0]);
68 if(f->msize > messagesize)
69 return "message size too big; use -m option on command line";
70 f->version = argv[1];
71 return nil;
72 }
73
74 char*
tauth(Fcall * f,int,char ** argv)75 tauth(Fcall *f, int, char **argv)
76 {
77 f->afid = atoi(argv[0]);
78 f->uname = argv[1];
79 f->aname = argv[2];
80 return nil;
81 }
82
83 char*
tflush(Fcall * f,int,char ** argv)84 tflush(Fcall *f, int, char **argv)
85 {
86 f->oldtag = atoi(argv[0]);
87 return nil;
88 }
89
90 char*
tattach(Fcall * f,int,char ** argv)91 tattach(Fcall *f, int, char **argv)
92 {
93 f->fid = atoi(argv[0]);
94 f->afid = atoi(argv[1]);
95 f->uname = argv[2];
96 f->aname = argv[3];
97 return nil;
98 }
99
100 char*
twalk(Fcall * f,int argc,char ** argv)101 twalk(Fcall *f, int argc, char **argv)
102 {
103 int i;
104
105 if(argc < 2)
106 return "usage: Twalk tag fid newfid [name...]";
107 f->fid = atoi(argv[0]);
108 f->newfid = atoi(argv[1]);
109 f->nwname = argc-2;
110 if(f->nwname > MAXWELEM)
111 return "too many names";
112 for(i=0; i<argc-2; i++)
113 f->wname[i] = argv[2+i];
114 return nil;
115 }
116
117 char*
topen(Fcall * f,int,char ** argv)118 topen(Fcall *f, int, char **argv)
119 {
120 f->fid = atoi(argv[0]);
121 f->mode = atoi(argv[1]);
122 return nil;
123 }
124
125 char*
tcreate(Fcall * f,int,char ** argv)126 tcreate(Fcall *f, int, char **argv)
127 {
128 f->fid = atoi(argv[0]);
129 f->name = argv[1];
130 f->perm = strtoul(argv[2], 0, 8);
131 f->mode = atoi(argv[3]);
132 return nil;
133 }
134
135 char*
tread(Fcall * f,int,char ** argv)136 tread(Fcall *f, int, char **argv)
137 {
138 f->fid = atoi(argv[0]);
139 f->offset = strtoll(argv[1], 0, 0);
140 f->count = strtol(argv[2], 0, 0);
141 return nil;
142 }
143
144 char*
twrite(Fcall * f,int,char ** argv)145 twrite(Fcall *f, int, char **argv)
146 {
147 f->fid = atoi(argv[0]);
148 f->offset = strtoll(argv[1], 0, 0);
149 f->data = argv[2];
150 f->count = strlen(argv[2]);
151 return nil;
152 }
153
154 char*
tclunk(Fcall * f,int,char ** argv)155 tclunk(Fcall *f, int, char **argv)
156 {
157 f->fid = atoi(argv[0]);
158 return nil;
159 }
160
161 char*
tremove(Fcall * f,int,char ** argv)162 tremove(Fcall *f, int, char **argv)
163 {
164 f->fid = atoi(argv[0]);
165 return nil;
166 }
167
168 char*
tstat(Fcall * f,int,char ** argv)169 tstat(Fcall *f, int, char **argv)
170 {
171 f->fid = atoi(argv[0]);
172 return nil;
173 }
174
175 ulong
xstrtoul(char * s)176 xstrtoul(char *s)
177 {
178 if(strcmp(s, "~0") == 0)
179 return ~0UL;
180 return strtoul(s, 0, 0);
181 }
182
183 uvlong
xstrtoull(char * s)184 xstrtoull(char *s)
185 {
186 if(strcmp(s, "~0") == 0)
187 return ~0ULL;
188 return strtoull(s, 0, 0);
189 }
190
191 char*
twstat(Fcall * f,int,char ** argv)192 twstat(Fcall *f, int, char **argv)
193 {
194 static uchar buf[DIRMAX];
195 Dir d;
196
197 memset(&d, 0, sizeof d);
198 nulldir(&d);
199 d.name = argv[1];
200 d.uid = argv[2];
201 d.gid = argv[3];
202 d.mode = xstrtoul(argv[4]);
203 d.mtime = xstrtoul(argv[5]);
204 d.length = xstrtoull(argv[6]);
205
206 f->fid = atoi(argv[0]);
207 f->stat = buf;
208 f->nstat = convD2M(&d, buf, sizeof buf);
209 if(f->nstat < BIT16SZ)
210 return "convD2M failed (internal error)";
211
212 return nil;
213 }
214
215 int taggen;
216
217 char*
settag(Fcall *,int,char ** argv)218 settag(Fcall*, int, char **argv)
219 {
220 static char buf[120];
221
222 taggen = atoi(argv[0])-1;
223 snprint(buf, sizeof buf, "next tag is %d", taggen+1);
224 return buf;
225 }
226
227 typedef struct Cmd Cmd;
228 struct Cmd {
229 char *name;
230 int type;
231 int argc;
232 char *usage;
233 char *(*fn)(Fcall *f, int, char**);
234 };
235
236 Cmd msg9p[] = {
237 "Tversion", Tversion, 2, "messagesize version", tversion,
238 "Tauth", Tauth, 3, "afid uname aname", tauth,
239 "Tflush", Tflush, 1, "oldtag", tflush,
240 "Tattach", Tattach, 4, "fid afid uname aname", tattach,
241 "Twalk", Twalk, 0, "fid newfid [name...]", twalk,
242 "Topen", Topen, 2, "fid mode", topen,
243 "Tcreate", Tcreate, 4, "fid name perm mode", tcreate,
244 "Tread", Tread, 3, "fid offset count", tread,
245 "Twrite", Twrite, 3, "fid offset data", twrite,
246 "Tclunk", Tclunk, 1, "fid", tclunk,
247 "Tremove", Tremove, 1, "fid", tremove,
248 "Tstat", Tstat, 1, "fid", tstat,
249 "Twstat", Twstat, 7, "fid name uid gid mode mtime length", twstat,
250 "nexttag", 0, 0, "", settag,
251 };
252
253 void
shell9p(int fd)254 shell9p(int fd)
255 {
256 char *e, *f[10], *p;
257 uchar *buf;
258 int i, n, nf;
259 Biobuf b;
260 Fcall t;
261
262 buf = malloc(messagesize);
263 if(buf == nil){
264 fprint(2, "out of memory\n");
265 return;
266 }
267
268 taggen = 0;
269 Binit(&b, 0, OREAD);
270 while(p = Brdline(&b, '\n')){
271 p[Blinelen(&b)-1] = '\0';
272 if(p[0] == '#')
273 continue;
274 if((nf = tokenize(p, f, nelem(f))) == 0)
275 continue;
276 for(i=0; i<nelem(msg9p); i++)
277 if(strcmp(f[0], msg9p[i].name) == 0)
278 break;
279 if(i == nelem(msg9p)){
280 fprint(2, "?unknown message\n");
281 continue;
282 }
283 memset(&t, 0, sizeof t);
284 t.type = msg9p[i].type;
285 if(t.type == Tversion)
286 t.tag = NOTAG;
287 else
288 t.tag = ++taggen;
289 if(nf < 1 || (msg9p[i].argc && nf != 1+msg9p[i].argc)){
290 fprint(2, "?usage: %s %s\n", msg9p[i].name, msg9p[i].usage);
291 continue;
292 }
293 if(e = msg9p[i].fn(&t, nf-1, f+1)){
294 fprint(2, "?%s\n", e);
295 continue;
296 }
297 n = convS2M(&t, buf, messagesize);
298 if(n <= BIT16SZ){
299 fprint(2, "?message too large for buffer\n");
300 continue;
301 }
302 if(write(fd, buf, n) != n){
303 fprint(2, "?write fails: %r\n");
304 break;
305 }
306 print("\t-> %F\n", &t);
307 }
308 }
309
310 void
main(int argc,char ** argv)311 main(int argc, char **argv)
312 {
313 int fd, pid, cmd, net;
314
315 cmd = 0;
316 net = 0;
317 ARGBEGIN{
318 case 'c':
319 cmd = 1;
320 break;
321 case 'm':
322 messagesize = atoi(EARGF(usage()));
323 break;
324 case 'n':
325 net = 1;
326 break;
327 default:
328 usage();
329 }ARGEND
330
331 fmtinstall('F', fcallfmt);
332 fmtinstall('D', dirfmt);
333 fmtinstall('M', dirmodefmt);
334
335 if(argc != 1)
336 usage();
337
338 if(cmd && net)
339 usage();
340
341 if(cmd)
342 fd = connectcmd(argv[0]);
343 else if(net){
344 fd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0);
345 if(fd < 0)
346 sysfatal("dial: %r");
347 }else{
348 fd = open(argv[0], ORDWR);
349 if(fd < 0)
350 sysfatal("open: %r");
351 }
352
353 switch(pid = rfork(RFPROC|RFMEM)){
354 case -1:
355 sysfatal("rfork: %r");
356 break;
357 case 0:
358 watch(fd);
359 postnote(PNPROC, getppid(), "kill");
360 break;
361 default:
362 shell9p(fd);
363 postnote(PNPROC, pid, "kill");
364 break;
365 }
366 exits(nil);
367 }
368