xref: /plan9/sys/src/cmd/aux/9pcon.c (revision ab3dc52f122c98aa4bc2bd64bd2292bb7b80fba2)
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