Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/ratfs/proto.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "ratfs.h"
2
 
3
/*
4
 *	9P protocol interface
5
 */
6
 
7
enum {
8
	RELOAD = 0,		/* commands written to ctl file */
9
	RDEBUG,
10
	RNODEBUG,
11
	RNONE,
12
};
13
 
14
static void	rflush(Fcall*),		rnop(Fcall*),
15
		rauth(Fcall*),	rattach(Fcall*),
16
		rclone(Fcall*),		rwalk(Fcall*),
17
		rclwalk(Fcall*),	ropen(Fcall*),
18
		rcreate(Fcall*),	rread(Fcall*),
19
		rwrite(Fcall*),		rclunk(Fcall*),
20
		rremove(Fcall*),	rstat(Fcall*),
21
		rwstat(Fcall*),	rversion(Fcall*);
22
 
23
static	Fid*	newfid(int);
24
static	void	reply(Fcall*, char*);
25
 
26
static	void 	(*fcalls[])(Fcall*) = {
27
	[Tversion]	rversion,
28
	[Tflush]	rflush,
29
	[Tauth]	rauth,
30
	[Tattach]	rattach,
31
	[Twalk]		rwalk,
32
	[Topen]		ropen,
33
	[Tcreate]	rcreate,
34
	[Tread]		rread,
35
	[Twrite]	rwrite,
36
	[Tclunk]	rclunk,
37
	[Tremove]	rremove,
38
	[Tstat]		rstat,
39
	[Twstat]	rwstat,
40
};
41
 
42
 
43
static	Keyword cmds[] = {
44
	"reload",		RELOAD,
45
	"debug",		RDEBUG,
46
	"nodebug",		RNODEBUG,
47
	0,			RNONE,
48
};
49
 
50
/*
51
 *	Main protocol loop
52
 */
53
void
54
io(void)
55
{
56
	Fcall	rhdr;
57
	int n;
58
 
59
	for(;;){
60
		n = read9pmsg(srvfd, rbuf, sizeof rbuf-1);
61
		if(n <= 0)
62
			fatal("mount read");
63
		if(convM2S(rbuf, n, &rhdr) == 0){
64
			if(debugfd >= 0)
65
				fprint(2, "%s: malformed message\n", argv0);
66
			continue;
67
		}
68
 
69
		if(debugfd >= 0)
70
			fprint(debugfd, "<-%F\n", &rhdr);/**/
71
 
72
		if(!fcalls[rhdr.type])
73
			reply(&rhdr, "bad fcall type");
74
		else
75
			(*fcalls[rhdr.type])(&rhdr);
76
	}
77
}
78
 
79
/*
80
 *	write a protocol reply to the client
81
 */
82
static void
83
reply(Fcall *r, char *error)
84
{
85
	int n;
86
 
87
	if(error == nil)
88
		r->type++;
89
	else {
90
		r->type = Rerror;
91
		r->ename = error;
92
	}
93
	if(debugfd >= 0)
94
		fprint(debugfd, "->%F\n", r);/**/
95
	n = convS2M(r, rbuf, sizeof rbuf);
96
	if(n == 0)
97
		sysfatal("convS2M: %r");
98
	if(write(srvfd, rbuf, n) < 0)
99
		sysfatal("reply: %r");
100
}
101
 
102
 
103
/*
104
 *  lookup a fid. if not found, create a new one.
105
 */
106
 
107
static Fid*
108
newfid(int fid)
109
{
110
	Fid *f, *ff;
111
 
112
	static Fid *fids;
113
 
114
	ff = 0;
115
	for(f = fids; f; f = f->next){
116
		if(f->fid == fid){
117
			if(!f->busy)
118
				f->node = 0;
119
			return f;
120
		} else if(!ff && !f->busy)
121
			ff = f;
122
	}
123
	if(ff == 0){
124
		ff = mallocz(sizeof(*f), 1);
125
		ff->next = fids;
126
		fids = ff;
127
	}
128
	ff->node = 0;
129
	ff->fid = fid;
130
	return ff;
131
}
132
 
133
static void
134
rversion(Fcall *f)
135
{
136
	f->version = "9P2000";
137
	if(f->msize > MAXRPC)
138
		f->msize = MAXRPC;
139
	reply(f, 0);
140
}
141
 
142
static void
143
rauth(Fcall *f)
144
{
145
	reply(f, "ratfs: authentication not required");
146
}
147
 
148
static void
149
rflush(Fcall *f)
150
{
151
	reply(f, 0);
152
}
153
 
154
static void
155
rattach(Fcall *f)
156
{
157
	Fid *fidp;
158
	Dir *d;
159
 
160
	if((d=dirstat(conffile)) != nil && d->mtime > lastconftime)
161
		getconf();
162
	free(d);
163
	if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime)
164
		reload();
165
	free(d);
166
	cleantrusted();
167
 
168
	fidp = newfid(f->fid);
169
	fidp->busy = 1;
170
	fidp->node = root;
171
	fidp->name = root->d.name;
172
	fidp->uid = atom(f->uname);
173
	f->qid = root->d.qid;
174
	reply(f,0);
175
}
176
 
177
static void
178
rclone(Fcall *f)
179
{
180
	Fid *fidp, *nf;
181
 
182
	fidp = newfid(f->fid);
183
	if(fidp->node && fidp->node->d.type == Dummynode){
184
		reply(f, "can't clone an address");
185
		return;
186
	}
187
	nf = newfid(f->newfid);
188
	nf->busy = 1;
189
	nf->node = fidp->node;
190
	nf->uid = fidp->uid;
191
	nf->name = fidp->name;
192
	if(debugfd >= 0)
193
		printfid(nf);
194
	reply(f,0);
195
}
196
 
197
static void
198
rwalk(Fcall *f)
199
{
200
	int i, j;
201
	Fcall r;
202
	Fid *fidp, *nf;
203
	char *err;
204
 
205
	fidp = newfid(f->fid);
206
	if(fidp->node && fidp->node->d.type == Dummynode){
207
		reply(f, "can't walk an address node");
208
		return;
209
	}
210
	if(f->fid == f->newfid)
211
		nf = fidp;
212
	else{
213
		nf = newfid(f->newfid);
214
		nf->busy = 1;
215
		nf->node = fidp->node;
216
		nf->uid = fidp->uid;
217
		nf->name = fidp->name;
218
		if(debugfd >= 0)
219
			printfid(nf);
220
	}
221
 
222
	err = nil;
223
	for(i=0; i<f->nwname; i++){
224
		err = walk(f->wname[i], nf);
225
		if(err)
226
			break;
227
		r.wqid[i] = nf->node->d.qid;
228
	}
229
 
230
 
231
	if(i < f->nwname && f->fid != f->newfid){
232
		nf->busy = 0;
233
		nf->node = 0;
234
		nf->name = 0;
235
		nf->uid = 0;
236
	}
237
	if(i > 0 && i < f->nwname && f->fid == f->newfid){
238
		/*
239
		 * try to put things back;
240
		 * we never get this sort of call from the kernel
241
		 */
242
		for(j=0; j<i; j++)
243
			walk("..", nf);
244
	}
245
	memmove(f->wqid, r.wqid, sizeof f->wqid);
246
	f->nwqid = i;
247
	if(err && i==0)
248
		reply(f, err);
249
	else
250
		reply(f, 0);
251
}
252
 
253
/*
254
 *	We don't have to do full permission checking because most files
255
 *	have restricted semantics:
256
 *		The ctl file is only writable
257
 *		All others, including directories, are only readable
258
 */
259
static void
260
ropen(Fcall *f)
261
{
262
	Fid *fidp;
263
	int mode;
264
 
265
	fidp = newfid(f->fid);
266
 
267
	if(debugfd >= 0)
268
		printfid(fidp);
269
 
270
	mode = f->mode&(OREAD|OWRITE|ORDWR);
271
	if(fidp->node->d.type == Ctlfile) {
272
		if(mode != OWRITE) {	
273
			reply(f, "permission denied");
274
			return;
275
		}
276
	} else
277
	if (mode != OREAD) {
278
		reply(f, "permission denied or operation not supported");
279
		return;
280
	}
281
 
282
	f->qid = fidp->node->d.qid;
283
	fidp->open = 1;
284
	reply(f, 0);
285
}
286
 
287
static int
288
permitted(Fid *fp, Node *np, int mask)
289
{
290
	int mode;
291
 
292
	mode = np->d.mode;
293
	return (fp->uid==np->d.uid && (mode&(mask<<6)))
294
		|| (fp->uid==np->d.gid && (mode&(mask<<3)))
295
		|| (mode&mask);
296
}
297
 
298
/*
299
 *	creates are only allowed in the "trusted" subdirectory
300
 *	we also assume that the groupid == the uid
301
 */
302
static void
303
rcreate(Fcall *f)
304
{
305
	Fid *fidp;
306
	Node *np;
307
 
308
	fidp = newfid(f->fid);
309
	np = fidp->node;
310
	if((np->d.mode&DMDIR) == 0){
311
		reply(f, "not a directory");
312
		return;
313
	}
314
 
315
	if(!permitted(fidp, np, AWRITE)) {
316
		reply(f, "permission denied");
317
		return;
318
	}
319
 
320
	/* Ignore the supplied mode and force it to be non-writable */
321
 
322
	np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++);
323
	if(trustedqid >= Qaddrfile)			/* wrap QIDs */
324
		trustedqid = Qtrustedfile;
325
	cidrparse(&np->ip, f->name);
326
	f->qid = np->d.qid;
327
	np->d.uid = fidp->uid;
328
	np->d.gid = np->d.uid;
329
	np->d.muid = np->d.muid;
330
	fidp->node = np;
331
	fidp->open = 1;
332
	reply(f, 0);
333
	return;
334
}
335
 
336
/*
337
 *	only directories can be read.  everthing else returns EOF.
338
 */
339
static void
340
rread(Fcall *f)
341
{
342
	long cnt;
343
	Fid *fidp;
344
 
345
	cnt = f->count;
346
	f->count = 0;
347
	fidp = newfid(f->fid);
348
	f->data = (char*)rbuf+IOHDRSZ;
349
	if(fidp->open == 0) {
350
		reply(f, "file not open");
351
		return;
352
	}
353
	if ((fidp->node->d.mode&DMDIR) == 0){
354
		reply(f, 0);				/*EOF*/
355
		return;
356
	}
357
	if(cnt > MAXRPC)
358
		cnt = MAXRPC;
359
 
360
	if(f->offset == 0)
361
		fidp->dirindex = 0;
362
 
363
	switch(fidp->node->d.type) {
364
	case Directory:
365
	case Addrdir:
366
	case Trusted:
367
		f->count = dread(fidp, cnt);
368
		break;
369
	case IPaddr:
370
	case Acctaddr:
371
		f->count = hread(fidp, cnt);
372
		break;
373
	default:
374
		reply(f, "can't read this type of file");
375
		return;
376
	}
377
	reply(f, 0);
378
}
379
 
380
 
381
/*
382
 * 	only the 'ctl' file in the top level directory is writable
383
 */
384
 
385
static void
386
rwrite(Fcall *f)
387
{
388
	Fid *fidp;
389
	int n;
390
	char *err, *argv[10];
391
 
392
	fidp = newfid(f->fid);
393
	if(fidp->node->d.mode & DMDIR){
394
		reply(f, "directories are not writable");
395
		return;
396
	}
397
	if(fidp->open == 0) {
398
		reply(f, "file not open");
399
		return;
400
	}
401
 
402
	if (!permitted(fidp, fidp->node, AWRITE)) {
403
		reply(f, "permission denied");
404
		return;
405
	}
406
 
407
	f->data[f->count] = 0;			/* the extra byte in rbuf leaves room */
408
	n = tokenize(f->data, argv, 10);
409
	err = 0;
410
	switch(findkey(argv[0], cmds)){
411
	case RELOAD:
412
		getconf();
413
		reload();
414
		break;
415
	case RDEBUG:
416
		if(n > 1){
417
			debugfd = create(argv[1], OWRITE, 0666);
418
			if(debugfd < 0)
419
				err = "create failed";
420
		} else
421
			debugfd = 2;
422
		break;
423
	case RNODEBUG:
424
		if(debugfd >= 0)
425
			close(debugfd);
426
		debugfd = -1;
427
		break;
428
	default:
429
		err = "unknown command";
430
		break;
431
	}
432
	reply(f, err);
433
}
434
 
435
static void
436
rclunk(Fcall *f)
437
{
438
	Fid *fidp;
439
 
440
	fidp = newfid(f->fid);
441
	fidp->open = 0;
442
	fidp->busy = 0;
443
	fidp->node = 0;
444
	fidp->name = 0;
445
	fidp->uid = 0;
446
	reply(f, 0);
447
}
448
 
449
/*
450
 *  no files or directories are removable; this becomes clunk;
451
 */
452
static void
453
rremove(Fcall *f)
454
{
455
	Fid *fidp;
456
	Node *dir, *np;
457
 
458
	fidp = newfid(f->fid);
459
 
460
	/*
461
	 * only trusted temporary files can be removed
462
	 * and only by their owner.
463
	 */
464
	if(fidp->node->d.type != Trustedtemp){
465
		reply(f, "can't be removed");
466
		return;
467
	}
468
	if(fidp->uid != fidp->node->d.uid){
469
		reply(f, "permission denied");
470
		return;
471
	}
472
	dir = fidp->node->parent;
473
	for(np = dir->children; np; np = np->sibs)
474
		if(np->sibs == fidp->node)
475
			break;
476
	if(np)
477
		np->sibs = fidp->node->sibs;
478
	else
479
		dir->children = fidp->node->sibs;
480
	dir->count--;
481
	free(fidp->node);
482
	fidp->node = 0;
483
	fidp->open = 0;
484
	fidp->busy = 0;
485
	fidp->name = 0;
486
	fidp->uid = 0;
487
	reply(f, 0);
488
}
489
 
490
static void
491
rstat(Fcall *f)
492
{
493
	Fid *fidp;
494
 
495
	fidp = newfid(f->fid);
496
	if (fidp->node->d.type == Dummynode)
497
		dummy.d.name = fidp->name;
498
	f->stat = (uchar*)rbuf+4+1+2+2;	/* knows about stat(5) */
499
	f->nstat = convD2M(&fidp->node->d, f->stat, MAXRPC);
500
	if(f->nstat <= BIT16SZ)
501
		reply(f, "ratfs: convD2M");
502
	else
503
		reply(f, 0);
504
	return;
505
}
506
 
507
static void
508
rwstat(Fcall *f)
509
{
510
	reply(f, "wstat not implemented");
511
}
512