Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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*
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*
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*
84
tflush(Fcall *f, int, char **argv)
85
{
86
	f->oldtag = atoi(argv[0]);
87
	return nil;
88
}
89
 
90
char*
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*
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*
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*
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*
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*
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*
155
tclunk(Fcall *f, int, char **argv)
156
{
157
	f->fid = atoi(argv[0]);
158
	return nil;
159
}
160
 
161
char*
162
tremove(Fcall *f, int, char **argv)
163
{
164
	f->fid = atoi(argv[0]);
165
	return nil;
166
}
167
 
168
char*
169
tstat(Fcall *f, int, char **argv)
170
{
171
	f->fid = atoi(argv[0]);
172
	return nil;
173
}
174
 
175
ulong
176
xstrtoul(char *s)
177
{
178
	if(strcmp(s, "~0") == 0)
179
		return ~0UL;
180
	return strtoul(s, 0, 0);
181
}
182
 
183
uvlong
184
xstrtoull(char *s)
185
{
186
	if(strcmp(s, "~0") == 0)
187
		return ~0ULL;
188
	return strtoull(s, 0, 0);
189
}
190
 
191
char*
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*
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
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
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
}