Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * ``Exec'' network device.  Mounted on net, provides /net/exec.
3
 *
4
 *	exec				protocol directory
5
 *		n 				connection directory
6
 *			ctl				control messages (like connect)
7
 *			data				data
8
 *			err				errors
9
 *			local				local address (pid of command)
10
 *			remote			remote address (command)
11
 *			status			status
12
 */
13
 
14
#include <u.h>
15
#include <libc.h>
16
#include <fcall.h>
17
#include <thread.h>
18
#include <9p.h>
19
#include "dat.h"
20
 
21
int fsdebug;
22
 
23
enum
24
{
25
	Qroot,
26
	Qexec,
27
	Qclone,
28
	Qn,
29
	Qctl,
30
	Qdata,
31
	Qlocal,
32
	Qremote,
33
	Qstatus,
34
};
35
 
36
#define PATH(type, n)	((type)|((n)<<8))
37
#define TYPE(path)		((int)(path) & 0xFF)
38
#define NUM(path)		((uint)(path)>>8)
39
 
40
typedef struct Tab Tab;
41
struct Tab
42
{
43
	char *name;
44
	ulong mode;
45
};
46
 
47
Tab tab[] =
48
{
49
	"/",		DMDIR|0555,
50
	"exec",	DMDIR|0555,
51
	"clone",	0666,
52
	nil,		DMDIR|0555,
53
	"ctl",		0666,
54
	"data",	0666,
55
	"local",	0444,
56
	"remote",	0444,
57
	"status",	0444,
58
};
59
 
60
void
61
setexecname(char *s)
62
{
63
	tab[Qexec].name = s;
64
}
65
 
66
ulong time0;
67
 
68
static void
69
fillstat(Dir *d, ulong path)
70
{
71
	Tab *t;
72
	int type;
73
	char buf[32];
74
 
75
	memset(d, 0, sizeof(*d));
76
	d->uid = estrdup("exec");
77
	d->gid = estrdup("exec");
78
	d->qid.path = path;
79
	d->atime = d->mtime = time0;
80
	d->length = 0;
81
 
82
	type = TYPE(path);
83
	t = &tab[type];
84
	if(t->name)
85
		d->name = estrdup(t->name);
86
	else{
87
		snprint(buf, sizeof buf, "%ud", NUM(path));
88
		d->name = estrdup(buf);
89
	}
90
	d->qid.type = t->mode>>24;
91
	d->mode = t->mode;
92
}
93
 
94
static void
95
fsstat(Req *r)
96
{
97
	fillstat(&r->d, r->fid->qid.path);
98
	respond(r, nil);
99
}
100
 
101
static int
102
rootgen(int i, Dir *d, void*)
103
{
104
	if(i < 1){
105
		fillstat(d, PATH(Qexec, 0));
106
		return 0;
107
	}
108
	return -1;
109
}
110
 
111
static int
112
execgen(int i, Dir *d, void*)
113
{
114
	if(i < 1){
115
		fillstat(d, PATH(Qclone, 0));
116
		return 0;
117
	}
118
	i -= 1;
119
 
120
	if(i < nclient){
121
		fillstat(d, PATH(Qn, i));
122
		return 0;
123
	}
124
	return -1;
125
}
126
 
127
static int
128
conngen(int i, Dir *d, void *aux)
129
{
130
	Client *c;
131
 
132
	c = aux;
133
	i += Qn+1;
134
	if(i <= Qstatus){
135
		fillstat(d, PATH(i, c->num));
136
		return 0;
137
	}
138
	return -1;
139
}
140
 
141
char *statusstr[] = 
142
{
143
	"Closed",
144
	"Exec",
145
	"Established",
146
	"Hangup",
147
};
148
 
149
static void
150
fsread(Req *r)
151
{
152
	char e[ERRMAX], *s;
153
	ulong path;
154
 
155
	path = r->fid->qid.path;
156
	switch(TYPE(path)){
157
	default:
158
		snprint(e, sizeof e, "bug in execnet path=%lux", path);
159
		respond(r, e);
160
		break;
161
 
162
	case Qroot:
163
		dirread9p(r, rootgen, nil);
164
		respond(r, nil);
165
		break;
166
 
167
	case Qexec:
168
		dirread9p(r, execgen, nil);
169
		respond(r, nil);
170
		break;
171
 
172
	case Qn:
173
		dirread9p(r, conngen, client[NUM(path)]);
174
		respond(r, nil);
175
		break;
176
 
177
	case Qctl:
178
		snprint(e, sizeof e, "%ud", NUM(path));
179
		readstr(r, e);
180
		respond(r, nil);
181
		break;
182
 
183
	case Qdata:
184
		dataread(r, client[NUM(path)]);
185
		break;
186
 
187
	case Qlocal:
188
		snprint(e, sizeof e, "%d", client[NUM(path)]->pid);
189
		readstr(r, e);
190
		respond(r, nil);
191
		break;
192
 
193
	case Qremote:
194
		s = client[NUM(path)]->cmd;
195
		if(strlen(s) >= 5)	/* "exec " */
196
			readstr(r, s+5);
197
		else
198
			readstr(r, s);
199
		respond(r, nil);
200
		break;
201
 
202
	case Qstatus:
203
		readstr(r, statusstr[client[NUM(path)]->status]);
204
		respond(r, nil);
205
		break;
206
	}
207
}
208
 
209
static void
210
fswrite(Req *r)
211
{
212
	char e[ERRMAX];
213
	ulong path;
214
 
215
	path = r->fid->qid.path;
216
	switch(TYPE(path)){
217
	default:
218
		snprint(e, sizeof e, "bug in execnet path=%lux", path);
219
		respond(r, e);
220
		break;
221
 
222
	case Qctl:
223
		ctlwrite(r, client[NUM(path)]);
224
		break;
225
 
226
	case Qdata:
227
		datawrite(r, client[NUM(path)]);
228
		break;
229
	}
230
}
231
 
232
 
233
static void
234
fsflush(Req *r)
235
{
236
	ulong path;
237
	Req *or;
238
 
239
	for(or=r; or->ifcall.type==Tflush; or=or->oldreq)
240
		;
241
 
242
	if(or->ifcall.type != Tread && or->ifcall.type != Twrite)
243
		abort();
244
 
245
	path = or->fid->qid.path;
246
	if(TYPE(path) != Qdata)
247
		abort();
248
 
249
	clientflush(or, client[NUM(path)]);
250
	respond(r, nil);
251
}
252
 
253
static void
254
fsattach(Req *r)
255
{
256
	if(r->ifcall.aname && r->ifcall.aname[0]){
257
		respond(r, "invalid attach specifier");
258
		return;
259
	}
260
	r->fid->qid.path = PATH(Qroot, 0);
261
	r->fid->qid.type = QTDIR;
262
	r->fid->qid.vers = 0;
263
	r->ofcall.qid = r->fid->qid;
264
	respond(r, nil);
265
}
266
 
267
static char*
268
fswalk1(Fid *fid, char *name, Qid *qid)
269
{
270
	char buf[32];
271
	int i, n;
272
	ulong path;
273
 
274
	if(!(fid->qid.type&QTDIR))
275
		return "walk in non-directory";
276
 
277
	path = fid->qid.path;
278
	if(strcmp(name, "..") == 0){
279
		switch(TYPE(path)){
280
		case Qn:
281
			qid->path = PATH(Qexec, 0);
282
			qid->type = QTDIR;
283
			return nil;
284
		case Qroot:
285
		case Qexec:
286
			qid->path = PATH(Qroot, 0);
287
			qid->type = QTDIR;
288
			return nil;
289
		default:
290
			return "bug in fswalk1";
291
		}
292
	}
293
 
294
	i = TYPE(path)+1;
295
	for(; i<nelem(tab); i++){
296
		if(i==Qn){
297
			n = atoi(name);
298
			snprint(buf, sizeof buf, "%d", n);
299
			if(n < nclient && strcmp(buf, name) == 0){
300
				qid->path = PATH(Qn, n);
301
				qid->type = QTDIR;
302
				return nil;
303
			}
304
			break;
305
		}
306
		if(strcmp(tab[i].name, name) == 0){
307
			qid->path = PATH(i, NUM(path));
308
			qid->type = tab[i].mode>>24;
309
			return nil;
310
		}
311
		if(tab[i].mode&DMDIR)
312
			break;
313
	}
314
	return "directory entry not found";
315
}
316
 
317
static void
318
fsopen(Req *r)
319
{
320
	static int need[4] = { 4, 2, 6, 1 };
321
	ulong path;
322
	int n;
323
	Tab *t;
324
 
325
	/*
326
	 * lib9p already handles the blatantly obvious.
327
	 * we just have to enforce the permissions we have set.
328
	 */
329
	path = r->fid->qid.path;
330
	t = &tab[TYPE(path)];
331
	n = need[r->ifcall.mode&3];
332
	if((n&t->mode) != n){
333
		respond(r, "permission denied");
334
		return;
335
	}
336
 
337
	switch(TYPE(path)){
338
	case Qclone:
339
		n = newclient();
340
		path = PATH(Qctl, n);
341
		r->fid->qid.path = path;
342
		r->ofcall.qid.path = path;
343
		if(fsdebug)
344
			fprint(2, "open clone => path=%lux\n", path);
345
		t = &tab[Qctl];
346
		/* fall through */
347
	default:
348
		if(t-tab >= Qn)
349
			client[NUM(path)]->ref++;
350
		respond(r, nil);
351
		break;
352
	}
353
}
354
 
355
Channel *cclunk;
356
Channel *cclunkwait;
357
Channel *creq;
358
Channel *creqwait;
359
 
360
static void
361
fsthread(void*)
362
{
363
	ulong path;
364
	Alt a[3];
365
	Fid *fid;
366
	Req *r;
367
 
368
	threadsetname("fsthread");
369
 
370
	a[0].op = CHANRCV;
371
	a[0].c = cclunk;
372
	a[0].v = &fid;
373
	a[1].op = CHANRCV;
374
	a[1].c = creq;
375
	a[1].v = &r;
376
	a[2].op = CHANEND;
377
 
378
	for(;;){
379
		switch(alt(a)){
380
		case 0:
381
			path = fid->qid.path;
382
			if(fid->omode != -1 && TYPE(path) >= Qn)
383
				closeclient(client[NUM(path)]);
384
			sendp(cclunkwait, nil);
385
			break;
386
		case 1:
387
			switch(r->ifcall.type){
388
			case Tattach:
389
				fsattach(r);
390
				break;
391
			case Topen:
392
				fsopen(r);
393
				break;
394
			case Tread:
395
				fsread(r);
396
				break;
397
			case Twrite:
398
				fswrite(r);
399
				break;
400
			case Tstat:
401
				fsstat(r);
402
				break;
403
			case Tflush:
404
				fsflush(r);
405
				break;
406
			default:
407
				respond(r, "bug in fsthread");
408
				break;
409
			}
410
			sendp(creqwait, 0);
411
			break;
412
		}
413
	}
414
}
415
 
416
static void
417
fsdestroyfid(Fid *fid)
418
{
419
	sendp(cclunk, fid);
420
	recvp(cclunkwait);
421
}
422
 
423
static void
424
fssend(Req *r)
425
{
426
	sendp(creq, r);
427
	recvp(creqwait);	/* avoids need to deal with spurious flushes */
428
}
429
 
430
void
431
initfs(void)
432
{
433
	time0 = time(0);
434
	creq = chancreate(sizeof(void*), 0);
435
	creqwait = chancreate(sizeof(void*), 0);
436
	cclunk = chancreate(sizeof(void*), 0);
437
	cclunkwait = chancreate(sizeof(void*), 0);
438
	procrfork(fsthread, nil, STACK, RFNAMEG);
439
}
440
 
441
Srv fs = 
442
{
443
.attach=		fssend,
444
.destroyfid=	fsdestroyfid,
445
.walk1=		fswalk1,
446
.open=		fssend,
447
.read=		fssend,
448
.write=		fssend,
449
.stat=		fssend,
450
.flush=		fssend,
451
};