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 <draw.h>
4
#include <thread.h>
5
#include <cursor.h>
6
#include <mouse.h>
7
#include <keyboard.h>
8
#include <frame.h>
9
#include <fcall.h>
10
#include "dat.h"
11
#include "fns.h"
12
 
13
char Eperm[] = "permission denied";
14
char Eexist[] = "file does not exist";
15
char Enotdir[] = "not a directory";
16
char	Ebadfcall[] = "bad fcall type";
17
char	Eoffset[] = "illegal offset";
18
 
19
int	messagesize = 8192+IOHDRSZ;	/* good start */
20
 
21
enum{
22
	DEBUG = 0
23
};
24
 
25
Dirtab dirtab[]=
26
{
27
	{ ".",			QTDIR,	Qdir,			0500|DMDIR },
28
	{ "cons",		QTFILE,	Qcons,		0600 },
29
	{ "cursor",		QTFILE,	Qcursor,		0600 },
30
	{ "consctl",	QTFILE,	Qconsctl,		0200 },
31
	{ "winid",		QTFILE,	Qwinid,		0400 },
32
	{ "winname",	QTFILE,	Qwinname,	0400 },
33
	{ "kbdin",		QTFILE,	Qkbdin,		0200 },
34
	{ "label",		QTFILE,	Qlabel,		0600 },
35
	{ "mouse",	QTFILE,	Qmouse,		0600 },
36
	{ "screen",		QTFILE,	Qscreen,		0400 },
37
	{ "snarf",		QTFILE,	Qsnarf,		0600 },
38
	{ "text",		QTFILE,	Qtext,		0400 },
39
	{ "wdir",		QTFILE,	Qwdir,		0600 },
40
	{ "wctl",		QTFILE,	Qwctl,		0600 },
41
	{ "window",	QTFILE,	Qwindow,		0400 },
42
	{ "wsys",		QTDIR,	Qwsys,		0500|DMDIR },
43
	{ nil, }
44
};
45
 
46
static uint		getclock(void);
47
static void		filsysproc(void*);
48
static Fid*		newfid(Filsys*, int);
49
static int		dostat(Filsys*, int, Dirtab*, uchar*, int, uint);
50
 
51
int	clockfd;
52
int	firstmessage = 1;
53
 
54
char	srvpipe[64];
55
char	srvwctl[64];
56
 
57
static	Xfid*	filsysflush(Filsys*, Xfid*, Fid*);
58
static	Xfid*	filsysversion(Filsys*, Xfid*, Fid*);
59
static	Xfid*	filsysauth(Filsys*, Xfid*, Fid*);
60
static	Xfid*	filsysnop(Filsys*, Xfid*, Fid*);
61
static	Xfid*	filsysattach(Filsys*, Xfid*, Fid*);
62
static	Xfid*	filsyswalk(Filsys*, Xfid*, Fid*);
63
static	Xfid*	filsysopen(Filsys*, Xfid*, Fid*);
64
static	Xfid*	filsyscreate(Filsys*, Xfid*, Fid*);
65
static	Xfid*	filsysread(Filsys*, Xfid*, Fid*);
66
static	Xfid*	filsyswrite(Filsys*, Xfid*, Fid*);
67
static	Xfid*	filsysclunk(Filsys*, Xfid*, Fid*);
68
static	Xfid*	filsysremove(Filsys*, Xfid*, Fid*);
69
static	Xfid*	filsysstat(Filsys*, Xfid*, Fid*);
70
static	Xfid*	filsyswstat(Filsys*, Xfid*, Fid*);
71
 
72
Xfid* 	(*fcall[Tmax])(Filsys*, Xfid*, Fid*) =
73
{
74
	[Tflush]	= filsysflush,
75
	[Tversion]	= filsysversion,
76
	[Tauth]	= filsysauth,
77
	[Tattach]	= filsysattach,
78
	[Twalk]	= filsyswalk,
79
	[Topen]	= filsysopen,
80
	[Tcreate]	= filsyscreate,
81
	[Tread]	= filsysread,
82
	[Twrite]	= filsyswrite,
83
	[Tclunk]	= filsysclunk,
84
	[Tremove]= filsysremove,
85
	[Tstat]	= filsysstat,
86
	[Twstat]	= filsyswstat,
87
};
88
 
89
void
90
post(char *name, char *envname, int srvfd)
91
{
92
	int fd;
93
	char buf[32];
94
 
95
	fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);
96
	if(fd < 0)
97
		error(name);
98
	sprint(buf, "%d",srvfd);
99
	if(write(fd, buf, strlen(buf)) != strlen(buf))
100
		error("srv write");
101
	putenv(envname, name);
102
}
103
 
104
/*
105
 * Build pipe with OCEXEC set on second fd.
106
 * Can't put it on both because we want to post one in /srv.
107
 */
108
int
109
cexecpipe(int *p0, int *p1)
110
{
111
	/* pipe the hard way to get close on exec */
112
	if(bind("#|", "/mnt/temp", MREPL) < 0)
113
		return -1;
114
	*p0 = open("/mnt/temp/data", ORDWR);
115
	*p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);
116
	unmount(nil, "/mnt/temp");
117
	if(*p0<0 || *p1<0)
118
		return -1;
119
	return 0;
120
}
121
 
122
Filsys*
123
filsysinit(Channel *cxfidalloc)
124
{
125
	int n, fd, pid, p0;
126
	Filsys *fs;
127
	Channel *c;
128
	char buf[128];
129
 
130
	fs = emalloc(sizeof(Filsys));
131
	if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
132
		goto Rescue;
133
	fmtinstall('F', fcallfmt);
134
	clockfd = open("/dev/time", OREAD|OCEXEC);
135
	fd = open("/dev/user", OREAD);
136
	strcpy(buf, "Jean-Paul_Belmondo");
137
	if(fd >= 0){
138
		n = read(fd, buf, sizeof buf-1);
139
		if(n > 0)
140
			buf[n] = 0;
141
		close(fd);
142
	}
143
	fs->user = estrdup(buf);
144
	fs->cxfidalloc = cxfidalloc;
145
	pid = getpid();
146
 
147
	/*
148
	 * Create and post wctl pipe
149
	 */
150
	if(cexecpipe(&p0, &wctlfd) < 0)
151
		goto Rescue;
152
	sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);
153
	post(srvwctl, "wctl", p0);
154
	close(p0);
155
 
156
	/*
157
	 * Start server processes
158
	 */
159
	c = chancreate(sizeof(char*), 0);
160
	if(c == nil)
161
		error("wctl channel");
162
	proccreate(wctlproc, c, 4096);
163
	threadcreate(wctlthread, c, 4096);
164
	proccreate(filsysproc, fs, 10000);
165
 
166
	/*
167
	 * Post srv pipe
168
	 */
169
	sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);
170
	post(srvpipe, "wsys", fs->cfd);
171
 
172
	return fs;
173
 
174
Rescue:
175
	free(fs);
176
	return nil;
177
}
178
 
179
static
180
void
181
filsysproc(void *arg)
182
{
183
	int n;
184
	Xfid *x;
185
	Fid *f;
186
	Fcall t;
187
	uchar *buf;
188
	Filsys *fs;
189
 
190
	threadsetname("FILSYSPROC");
191
	fs = arg;
192
	fs->pid = getpid();
193
	x = nil;
194
	for(;;){
195
		buf = emalloc(messagesize+UTFmax);	/* UTFmax for appending partial rune in xfidwrite */
196
		n = read9pmsg(fs->sfd, buf, messagesize);
197
		if(n <= 0){
198
			yield();	/* if threadexitsall'ing, will not return */
199
			fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
200
			errorshouldabort = 0;
201
			error("eof or i/o error on server channel");
202
		}
203
		if(x == nil){
204
			send(fs->cxfidalloc, nil);
205
			recv(fs->cxfidalloc, &x);
206
			x->fs = fs;
207
		}
208
		x->buf = buf;
209
		if(convM2S(buf, n, x) != n)
210
			error("convert error in convM2S");
211
		if(DEBUG)
212
			fprint(2, "rio:<-%F\n", &x->Fcall);
213
		if(fcall[x->type] == nil)
214
			x = filsysrespond(fs, x, &t, Ebadfcall);
215
		else{
216
			if(x->type==Tversion || x->type==Tauth)
217
				f = nil;
218
			else
219
				f = newfid(fs, x->fid);
220
			x->f = f;
221
			x  = (*fcall[x->type])(fs, x, f);
222
		}
223
		firstmessage = 0;
224
	}
225
}
226
 
227
/*
228
 * Called only from a different FD group
229
 */
230
int
231
filsysmount(Filsys *fs, int id)
232
{
233
	char buf[32];
234
 
235
	close(fs->sfd);	/* close server end so mount won't hang if exiting */
236
	sprint(buf, "%d", id);
237
	if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){
238
		fprint(2, "mount failed: %r\n");
239
		return -1;
240
	}
241
	if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
242
		fprint(2, "bind failed: %r\n");
243
		return -1;
244
	}
245
	return 0;
246
}
247
 
248
Xfid*
249
filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err)
250
{
251
	int n;
252
 
253
	if(err){
254
		t->type = Rerror;
255
		t->ename = err;
256
	}else
257
		t->type = x->type+1;
258
	t->fid = x->fid;
259
	t->tag = x->tag;
260
	if(x->buf == nil)
261
		x->buf = malloc(messagesize);
262
	n = convS2M(t, x->buf, messagesize);
263
	if(n <= 0)
264
		error("convert error in convS2M");
265
	if(write(fs->sfd, x->buf, n) != n)
266
		error("write error in respond");
267
	if(DEBUG)
268
		fprint(2, "rio:->%F\n", t);
269
	free(x->buf);
270
	x->buf = nil;
271
	return x;
272
}
273
 
274
void
275
filsyscancel(Xfid *x)
276
{
277
	if(x->buf){
278
		free(x->buf);
279
		x->buf = nil;
280
	}
281
}
282
 
283
static
284
Xfid*
285
filsysversion(Filsys *fs, Xfid *x, Fid*)
286
{
287
	Fcall t;
288
 
289
	if(!firstmessage)
290
		return filsysrespond(x->fs, x, &t, "version request not first message");
291
	if(x->msize < 256)
292
		return filsysrespond(x->fs, x, &t, "version: message size too small");
293
	messagesize = x->msize;
294
	t.msize = messagesize;
295
	if(strncmp(x->version, "9P2000", 6) != 0)
296
		return filsysrespond(x->fs, x, &t, "unrecognized 9P version");
297
	t.version = "9P2000";
298
	return filsysrespond(fs, x, &t, nil);
299
}
300
 
301
static
302
Xfid*
303
filsysauth(Filsys *fs, Xfid *x, Fid*)
304
{
305
	Fcall t;
306
 
307
		return filsysrespond(fs, x, &t, "rio: authentication not required");
308
}
309
 
310
static
311
Xfid*
312
filsysflush(Filsys*, Xfid *x, Fid*)
313
{
314
	sendp(x->c, xfidflush);
315
	return nil;
316
}
317
 
318
static
319
Xfid*
320
filsysattach(Filsys *, Xfid *x, Fid *f)
321
{
322
	Fcall t;
323
 
324
	if(strcmp(x->uname, x->fs->user) != 0)
325
		return filsysrespond(x->fs, x, &t, Eperm);
326
	f->busy = TRUE;
327
	f->open = FALSE;
328
	f->qid.path = Qdir;
329
	f->qid.type = QTDIR;
330
	f->qid.vers = 0;
331
	f->dir = dirtab;
332
	f->nrpart = 0;
333
	sendp(x->c, xfidattach);
334
	return nil;
335
}
336
 
337
static
338
int
339
numeric(char *s)
340
{
341
	for(; *s!='\0'; s++)
342
		if(*s<'0' || '9'<*s)
343
			return 0;
344
	return 1;
345
}
346
 
347
static
348
Xfid*
349
filsyswalk(Filsys *fs, Xfid *x, Fid *f)
350
{
351
	Fcall t;
352
	Fid *nf;
353
	int i, id;
354
	uchar type;
355
	ulong path;
356
	Dirtab *d, *dir;
357
	Window *w;
358
	char *err;
359
	Qid qid;
360
 
361
	if(f->open)
362
		return filsysrespond(fs, x, &t, "walk of open file");
363
	nf = nil;
364
	if(x->fid  != x->newfid){
365
		/* BUG: check exists */
366
		nf = newfid(fs, x->newfid);
367
		if(nf->busy)
368
			return filsysrespond(fs, x, &t, "clone to busy fid");
369
		nf->busy = TRUE;
370
		nf->open = FALSE;
371
		nf->dir = f->dir;
372
		nf->qid = f->qid;
373
		nf->w = f->w;
374
		incref(f->w);
375
		nf->nrpart = 0;	/* not open, so must be zero */
376
		f = nf;	/* walk f */
377
	}
378
 
379
	t.nwqid = 0;
380
	err = nil;
381
 
382
	/* update f->qid, f->dir only if walk completes */
383
	qid = f->qid;
384
	dir = f->dir;
385
 
386
	if(x->nwname > 0){
387
		for(i=0; i<x->nwname; i++){
388
			if((qid.type & QTDIR) == 0){
389
				err = Enotdir;
390
				break;
391
			}
392
			if(strcmp(x->wname[i], "..") == 0){
393
				type = QTDIR;
394
				path = Qdir;
395
				dir = dirtab;
396
				if(FILE(qid) == Qwsysdir)
397
					path = Qwsys;
398
				id = 0;
399
    Accept:
400
				if(i == MAXWELEM){
401
					err = "name too long";
402
					break;
403
				}
404
				qid.type = type;
405
				qid.vers = 0;
406
				qid.path = QID(id, path);
407
				t.wqid[t.nwqid++] = qid;
408
				continue;
409
			}
410
 
411
			if(qid.path == Qwsys){
412
				/* is it a numeric name? */
413
				if(!numeric(x->wname[i]))
414
					break;
415
				/* yes: it's a directory */
416
				id = atoi(x->wname[i]);
417
				qlock(&all);
418
				w = wlookid(id);
419
				if(w == nil){
420
					qunlock(&all);
421
					break;
422
				}
423
				path = Qwsysdir;
424
				type = QTDIR;
425
				qunlock(&all);
426
				incref(w);
427
				sendp(winclosechan, f->w);
428
				f->w = w;
429
				dir = dirtab;
430
				goto Accept;
431
			}
432
 
433
			if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0)
434
				break;	/* don't serve /dev/snarf if it's provided in the environment */
435
			id = WIN(f->qid);
436
			d = dirtab;
437
			d++;	/* skip '.' */
438
			for(; d->name; d++)
439
				if(strcmp(x->wname[i], d->name) == 0){
440
					path = d->qid;
441
					type = d->type;
442
					dir = d;
443
					goto Accept;
444
				}
445
 
446
			break;	/* file not found */
447
		}
448
 
449
		if(i==0 && err==nil)
450
			err = Eexist;
451
	}
452
 
453
	if(err!=nil || t.nwqid<x->nwname){
454
		if(nf){
455
			if(nf->w)
456
				sendp(winclosechan, nf->w);
457
			nf->open = FALSE;
458
			nf->busy = FALSE;
459
		}
460
	}else if(t.nwqid == x->nwname){
461
		f->dir = dir;
462
		f->qid = qid;
463
	}
464
 
465
	return filsysrespond(fs, x, &t, err);
466
}
467
 
468
static
469
Xfid*
470
filsysopen(Filsys *fs, Xfid *x, Fid *f)
471
{
472
	Fcall t;
473
	int m;
474
 
475
	/* can't truncate anything, so just disregard */
476
	x->mode &= ~(OTRUNC|OCEXEC);
477
	/* can't execute or remove anything */
478
	if(x->mode==OEXEC || (x->mode&ORCLOSE))
479
		goto Deny;
480
	switch(x->mode){
481
	default:
482
		goto Deny;
483
	case OREAD:
484
		m = 0400;
485
		break;
486
	case OWRITE:
487
		m = 0200;
488
		break;
489
	case ORDWR:
490
		m = 0600;
491
		break;
492
	}
493
	if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
494
		goto Deny;
495
 
496
	sendp(x->c, xfidopen);
497
	return nil;
498
 
499
    Deny:
500
	return filsysrespond(fs, x, &t, Eperm);
501
}
502
 
503
static
504
Xfid*
505
filsyscreate(Filsys *fs, Xfid *x, Fid*)
506
{
507
	Fcall t;
508
 
509
	return filsysrespond(fs, x, &t, Eperm);
510
}
511
 
512
static
513
int
514
idcmp(void *a, void *b)
515
{
516
	return *(int*)a - *(int*)b;
517
}
518
 
519
static
520
Xfid*
521
filsysread(Filsys *fs, Xfid *x, Fid *f)
522
{
523
	Fcall t;
524
	uchar *b;
525
	int i, n, o, e, len, j, k, *ids;
526
	Dirtab *d, dt;
527
	uint clock;
528
	char buf[16];
529
 
530
	if((f->qid.type & QTDIR) == 0){
531
		sendp(x->c, xfidread);
532
		return nil;
533
	}
534
	o = x->offset;
535
	e = x->offset+x->count;
536
	clock = getclock();
537
	b = malloc(messagesize-IOHDRSZ);	/* avoid memset of emalloc */
538
	if(b == nil)
539
		return filsysrespond(fs, x, &t, "out of memory");
540
	n = 0;
541
	switch(FILE(f->qid)){
542
	case Qdir:
543
	case Qwsysdir:
544
		d = dirtab;
545
		d++;	/* first entry is '.' */
546
		for(i=0; d->name!=nil && i<e; i+=len){
547
			len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);
548
			if(len <= BIT16SZ)
549
				break;
550
			if(i >= o)
551
				n += len;
552
			d++;
553
		}
554
		break;
555
	case Qwsys:
556
		qlock(&all);
557
		ids = emalloc(nwindow*sizeof(int));
558
		for(j=0; j<nwindow; j++)
559
			ids[j] = window[j]->id;
560
		qunlock(&all);
561
		qsort(ids, nwindow, sizeof ids[0], idcmp);
562
		dt.name = buf;
563
		for(i=0, j=0; j<nwindow && i<e; i+=len){
564
			k = ids[j];
565
			sprint(dt.name, "%d", k);
566
			dt.qid = QID(k, Qdir);
567
			dt.type = QTDIR;
568
			dt.perm = DMDIR|0700;
569
			len = dostat(fs, k, &dt, b+n, x->count-n, clock);
570
			if(len == 0)
571
				break;
572
			if(i >= o)
573
				n += len;
574
			j++;
575
		}
576
		free(ids);
577
		break;
578
	}
579
	t.data = (char*)b;
580
	t.count = n;
581
	filsysrespond(fs, x, &t, nil);
582
	free(b);
583
	return x;
584
}
585
 
586
static
587
Xfid*
588
filsyswrite(Filsys*, Xfid *x, Fid*)
589
{
590
	sendp(x->c, xfidwrite);
591
	return nil;
592
}
593
 
594
static
595
Xfid*
596
filsysclunk(Filsys *fs, Xfid *x, Fid *f)
597
{
598
	Fcall t;
599
 
600
	if(f->open){
601
		f->busy = FALSE;
602
		f->open = FALSE;
603
		sendp(x->c, xfidclose);
604
		return nil;
605
	}
606
	if(f->w)
607
		sendp(winclosechan, f->w);
608
	f->busy = FALSE;
609
	f->open = FALSE;
610
	return filsysrespond(fs, x, &t, nil);
611
}
612
 
613
static
614
Xfid*
615
filsysremove(Filsys *fs, Xfid *x, Fid*)
616
{
617
	Fcall t;
618
 
619
	return filsysrespond(fs, x, &t, Eperm);
620
}
621
 
622
static
623
Xfid*
624
filsysstat(Filsys *fs, Xfid *x, Fid *f)
625
{
626
	Fcall t;
627
 
628
	t.stat = emalloc(messagesize-IOHDRSZ);
629
	t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
630
	x = filsysrespond(fs, x, &t, nil);
631
	free(t.stat);
632
	return x;
633
}
634
 
635
static
636
Xfid*
637
filsyswstat(Filsys *fs, Xfid *x, Fid*)
638
{
639
	Fcall t;
640
 
641
	return filsysrespond(fs, x, &t, Eperm);
642
}
643
 
644
static
645
Fid*
646
newfid(Filsys *fs, int fid)
647
{
648
	Fid *f, *ff, **fh;
649
 
650
	ff = nil;
651
	fh = &fs->fids[fid&(Nhash-1)];
652
	for(f=*fh; f; f=f->next)
653
		if(f->fid == fid)
654
			return f;
655
		else if(ff==nil && f->busy==FALSE)
656
			ff = f;
657
	if(ff){
658
		ff->fid = fid;
659
		return ff;
660
	}
661
	f = emalloc(sizeof *f);
662
	f->fid = fid;
663
	f->next = *fh;
664
	*fh = f;
665
	return f;
666
}
667
 
668
static
669
uint
670
getclock(void)
671
{
672
	char buf[32];
673
 
674
	seek(clockfd, 0, 0);
675
	read(clockfd, buf, sizeof buf);
676
	return atoi(buf);
677
}
678
 
679
static
680
int
681
dostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
682
{
683
	Dir d;
684
 
685
	d.qid.path = QID(id, dir->qid);
686
	if(dir->qid == Qsnarf)
687
		d.qid.vers = snarfversion;
688
	else
689
		d.qid.vers = 0;
690
	d.qid.type = dir->type;
691
	d.mode = dir->perm;
692
	d.length = 0;	/* would be nice to do better */
693
	d.name = dir->name;
694
	d.uid = fs->user;
695
	d.gid = fs->user;
696
	d.muid = fs->user;
697
	d.atime = clock;
698
	d.mtime = clock;
699
	return convD2M(&d, buf, nbuf);
700
}