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 <plumb.h>
11
#include "dat.h"
12
#include "fns.h"
13
 
14
static	int	cfd;
15
static	int	sfd;
16
 
17
enum
18
{
19
	Nhash	= 16,
20
	DEBUG	= 0
21
};
22
 
23
static	Fid	*fids[Nhash];
24
 
25
Fid	*newfid(int);
26
 
27
static	Xfid*	fsysflush(Xfid*, Fid*);
28
static	Xfid*	fsysauth(Xfid*, Fid*);
29
static	Xfid*	fsysversion(Xfid*, Fid*);
30
static	Xfid*	fsysattach(Xfid*, Fid*);
31
static	Xfid*	fsyswalk(Xfid*, Fid*);
32
static	Xfid*	fsysopen(Xfid*, Fid*);
33
static	Xfid*	fsyscreate(Xfid*, Fid*);
34
static	Xfid*	fsysread(Xfid*, Fid*);
35
static	Xfid*	fsyswrite(Xfid*, Fid*);
36
static	Xfid*	fsysclunk(Xfid*, Fid*);
37
static	Xfid*	fsysremove(Xfid*, Fid*);
38
static	Xfid*	fsysstat(Xfid*, Fid*);
39
static	Xfid*	fsyswstat(Xfid*, Fid*);
40
 
41
Xfid* 	(*fcall[Tmax])(Xfid*, Fid*) =
42
{
43
	[Tflush]	= fsysflush,
44
	[Tversion]	= fsysversion,
45
	[Tauth]	= fsysauth,
46
	[Tattach]	= fsysattach,
47
	[Twalk]	= fsyswalk,
48
	[Topen]	= fsysopen,
49
	[Tcreate]	= fsyscreate,
50
	[Tread]	= fsysread,
51
	[Twrite]	= fsyswrite,
52
	[Tclunk]	= fsysclunk,
53
	[Tremove]= fsysremove,
54
	[Tstat]	= fsysstat,
55
	[Twstat]	= fsyswstat,
56
};
57
 
58
char Eperm[] = "permission denied";
59
char Eexist[] = "file does not exist";
60
char Enotdir[] = "not a directory";
61
 
62
Dirtab dirtab[]=
63
{
64
	{ ".",			QTDIR,	Qdir,		0500|DMDIR },
65
	{ "acme",		QTDIR,	Qacme,	0500|DMDIR },
66
	{ "cons",		QTFILE,	Qcons,	0600 },
67
	{ "consctl",	QTFILE,	Qconsctl,	0000 },
68
	{ "draw",		QTDIR,	Qdraw,	0000|DMDIR },	/* to suppress graphics progs started in acme */
69
	{ "editout",	QTFILE,	Qeditout,	0200 },
70
	{ "index",		QTFILE,	Qindex,	0400 },
71
	{ "label",		QTFILE,	Qlabel,	0600 },
72
	{ "new",		QTDIR,	Qnew,	0500|DMDIR },
73
	{ nil, }
74
};
75
 
76
Dirtab dirtabw[]=
77
{
78
	{ ".",			QTDIR,		Qdir,			0500|DMDIR },
79
	{ "addr",		QTFILE,		QWaddr,		0600 },
80
	{ "body",		QTAPPEND,	QWbody,		0600|DMAPPEND },
81
	{ "ctl",		QTFILE,		QWctl,		0600 },
82
	{ "data",		QTFILE,		QWdata,		0600 },
83
	{ "editout",	QTFILE,		QWeditout,	0200 },
84
	{ "errors",		QTFILE,		QWerrors,		0200 },
85
	{ "event",		QTFILE,		QWevent,		0600 },
86
	{ "rdsel",		QTFILE,		QWrdsel,		0400 },
87
	{ "wrsel",		QTFILE,		QWwrsel,		0200 },
88
	{ "tag",		QTAPPEND,	QWtag,		0600|DMAPPEND },
89
	{ "xdata",		QTFILE,		QWxdata,		0600 },
90
	{ nil, }
91
};
92
 
93
typedef struct Mnt Mnt;
94
struct Mnt
95
{
96
	QLock;
97
	int		id;
98
	Mntdir	*md;
99
};
100
 
101
Mnt	mnt;
102
 
103
Xfid*	respond(Xfid*, Fcall*, char*);
104
int		dostat(int, Dirtab*, uchar*, int, uint);
105
uint	getclock(void);
106
 
107
char	*user = "Wile E. Coyote";
108
int	clockfd;
109
static int closing = 0;
110
int	messagesize = Maxblock+IOHDRSZ;	/* good start */
111
 
112
void	fsysproc(void *);
113
 
114
void
115
fsysinit(void)
116
{
117
	int p[2];
118
	int n, fd;
119
	char buf[256];
120
 
121
	if(pipe(p) < 0)
122
		error("can't create pipe");
123
	cfd = p[0];
124
	sfd = p[1];
125
	fmtinstall('F', fcallfmt);
126
	clockfd = open("/dev/time", OREAD|OCEXEC);
127
	fd = open("/dev/user", OREAD);
128
	if(fd >= 0){
129
		n = read(fd, buf, sizeof buf-1);
130
		if(n > 0){
131
			buf[n] = 0;
132
			user = estrdup(buf);
133
		}
134
		close(fd);
135
	}
136
	proccreate(fsysproc, nil, STACK);
137
}
138
 
139
void
140
fsysproc(void *)
141
{
142
	int n;
143
	Xfid *x;
144
	Fid *f;
145
	Fcall t;
146
	uchar *buf;
147
 
148
	threadsetname("fsysproc");
149
 
150
	x = nil;
151
	for(;;){
152
		buf = emalloc(messagesize+UTFmax);	/* overflow for appending partial rune in xfidwrite */
153
		n = read9pmsg(sfd, buf, messagesize);
154
		if(n <= 0){
155
			if(closing)
156
				break;
157
			error("i/o error on server channel");
158
		}
159
		if(x == nil){
160
			sendp(cxfidalloc, nil);
161
			x = recvp(cxfidalloc);
162
		}
163
		x->buf = buf;
164
		if(convM2S(buf, n, x) != n)
165
			error("convert error in convM2S");
166
		if(DEBUG)
167
			fprint(2, "%F\n", &x->Fcall);
168
		if(fcall[x->type] == nil)
169
			x = respond(x, &t, "bad fcall type");
170
		else{
171
			switch(x->type){
172
			case Tversion:
173
			case Tauth:
174
			case Tflush:
175
				f = nil;
176
				break;
177
			case Tattach:
178
				f = newfid(x->fid);
179
				break;
180
			default:
181
				f = newfid(x->fid);
182
				if(!f->busy){
183
					x->f = f;
184
					x = respond(x, &t, "fid not in use");
185
					continue;
186
				}
187
				break;
188
			}
189
			x->f = f;
190
			x  = (*fcall[x->type])(x, f);
191
		}
192
	}
193
}
194
 
195
Mntdir*
196
fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
197
{
198
	Mntdir *m;
199
	int id;
200
 
201
	qlock(&mnt);
202
	id = ++mnt.id;
203
	m = emalloc(sizeof *m);
204
	m->id = id;
205
	m->dir =  dir;
206
	m->ref = 1;	/* one for Command, one will be incremented in attach */
207
	m->ndir = ndir;
208
	m->next = mnt.md;
209
	m->incl = incl;
210
	m->nincl = nincl;
211
	mnt.md = m;
212
	qunlock(&mnt);
213
	return m;
214
}
215
 
216
void
217
fsysincid(Mntdir *m)
218
{
219
	qlock(&mnt);
220
	m->ref++;
221
	qunlock(&mnt);
222
}
223
 
224
void
225
fsysdelid(Mntdir *idm)
226
{
227
	Mntdir *m, *prev;
228
	int i;
229
	char buf[64];
230
 
231
	if(idm == nil)
232
		return;
233
	qlock(&mnt);
234
	if(--idm->ref > 0){
235
		qunlock(&mnt);
236
		return;
237
	}
238
	prev = nil;
239
	for(m=mnt.md; m; m=m->next){
240
		if(m == idm){
241
			if(prev)
242
				prev->next = m->next;
243
			else
244
				mnt.md = m->next;
245
			for(i=0; i<m->nincl; i++)
246
				free(m->incl[i]);
247
			free(m->incl);
248
			free(m->dir);
249
			free(m);
250
			qunlock(&mnt);
251
			return;
252
		}
253
		prev = m;
254
	}
255
	qunlock(&mnt);
256
	sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
257
	sendp(cerr, estrdup(buf));
258
}
259
 
260
/*
261
 * Called only in exec.c:/^run(), from a different FD group
262
 */
263
Mntdir*
264
fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
265
{
266
	char buf[256];
267
	Mntdir *m;
268
 
269
	/* close server side so don't hang if acme is half-exited */
270
	close(sfd);
271
	m = fsysaddid(dir, ndir, incl, nincl);
272
	sprint(buf, "%d", m->id);
273
	if(mount(cfd, -1, "/mnt/acme", MREPL, buf) < 0){
274
		fsysdelid(m);
275
		return nil;
276
	}
277
	close(cfd);
278
	bind("/mnt/acme", "/mnt/wsys", MREPL);
279
	if(bind("/mnt/acme", "/dev", MBEFORE) < 0){
280
		fsysdelid(m);
281
		return nil;
282
	}
283
	return m;
284
}
285
 
286
void
287
fsysclose(void)
288
{
289
	closing = 1;
290
	close(cfd);
291
	close(sfd);
292
}
293
 
294
Xfid*
295
respond(Xfid *x, Fcall *t, char *err)
296
{
297
	int n;
298
 
299
	if(err){
300
		t->type = Rerror;
301
		t->ename = err;
302
	}else
303
		t->type = x->type+1;
304
	t->fid = x->fid;
305
	t->tag = x->tag;
306
	if(x->buf == nil)
307
		x->buf = emalloc(messagesize);
308
	n = convS2M(t, x->buf, messagesize);
309
	if(n <= 0)
310
		error("convert error in convS2M");
311
	if(write(sfd, x->buf, n) != n)
312
		error("write error in respond");
313
	free(x->buf);
314
	x->buf = nil;
315
	if(DEBUG)
316
		fprint(2, "r: %F\n", t);
317
	return x;
318
}
319
 
320
static
321
Xfid*
322
fsysversion(Xfid *x, Fid*)
323
{
324
	Fcall t;
325
 
326
	if(x->msize < 256)
327
		return respond(x, &t, "version: message size too small");
328
	if(x->msize < messagesize)
329
		messagesize = x->msize;
330
	t.msize = messagesize;
331
	if(strncmp(x->version, "9P2000", 6) != 0)
332
		return respond(x, &t, "unrecognized 9P version");
333
	t.version = "9P2000";
334
	return respond(x, &t, nil);
335
}
336
 
337
static
338
Xfid*
339
fsysauth(Xfid *x, Fid*)
340
{
341
	Fcall t;
342
 
343
	return respond(x, &t, "acme: authentication not required");
344
}
345
 
346
static
347
Xfid*
348
fsysflush(Xfid *x, Fid*)
349
{
350
	sendp(x->c, xfidflush);
351
	return nil;
352
}
353
 
354
static
355
Xfid*
356
fsysattach(Xfid *x, Fid *f)
357
{
358
	Fcall t;
359
	int id;
360
	Mntdir *m;
361
 
362
	if(strcmp(x->uname, user) != 0)
363
		return respond(x, &t, Eperm);
364
	f->busy = TRUE;
365
	f->open = FALSE;
366
	f->qid.path = Qdir;
367
	f->qid.type = QTDIR;
368
	f->qid.vers = 0;
369
	f->dir = dirtab;
370
	f->nrpart = 0;
371
	f->w = nil;
372
	t.qid = f->qid;
373
	f->mntdir = nil;
374
	id = atoi(x->aname);
375
	qlock(&mnt);
376
	for(m=mnt.md; m; m=m->next)
377
		if(m->id == id){
378
			f->mntdir = m;
379
			m->ref++;
380
			break;
381
		}
382
	if(m == nil)
383
		sendp(cerr, estrdup("unknown id in attach"));
384
	qunlock(&mnt);
385
	return respond(x, &t, nil);
386
}
387
 
388
static
389
Xfid*
390
fsyswalk(Xfid *x, Fid *f)
391
{
392
	Fcall t;
393
	int c, i, j, id;
394
	Qid q;
395
	uchar type;
396
	ulong path;
397
	Fid *nf;
398
	Dirtab *d, *dir;
399
	Window *w;
400
	char *err;
401
 
402
	nf = nil;
403
	w = nil;
404
	if(f->open)
405
		return respond(x, &t, "walk of open file");
406
	if(x->fid != x->newfid){
407
		nf = newfid(x->newfid);
408
		if(nf->busy)
409
			return respond(x, &t, "newfid already in use");
410
		nf->busy = TRUE;
411
		nf->open = FALSE;
412
		nf->mntdir = f->mntdir;
413
		if(f->mntdir)
414
			f->mntdir->ref++;
415
		nf->dir = f->dir;
416
		nf->qid = f->qid;
417
		nf->w = f->w;
418
		nf->nrpart = 0;	/* not open, so must be zero */
419
		if(nf->w)
420
			incref(nf->w);
421
		f = nf;	/* walk f */
422
	}
423
 
424
	t.nwqid = 0;
425
	err = nil;
426
	dir = nil;
427
	id = WIN(f->qid);
428
	q = f->qid;
429
 
430
	if(x->nwname > 0){
431
		for(i=0; i<x->nwname; i++){
432
			if((q.type & QTDIR) == 0){
433
				err = Enotdir;
434
				break;
435
			}
436
 
437
			if(strcmp(x->wname[i], "..") == 0){
438
				type = QTDIR;
439
				path = Qdir;
440
				id = 0;
441
				if(w){
442
					winclose(w);
443
					w = nil;
444
				}
445
    Accept:
446
				if(i == MAXWELEM){
447
					err = "name too long";
448
					break;
449
				}
450
				q.type = type;
451
				q.vers = 0;
452
				q.path = QID(id, path);
453
				t.wqid[t.nwqid++] = q;
454
				continue;
455
			}
456
 
457
			/* is it a numeric name? */
458
			for(j=0; (c=x->wname[i][j]); j++)
459
				if(c<'0' || '9'<c)
460
					goto Regular;
461
			/* yes: it's a directory */
462
			if(w)	/* name has form 27/23; get out before losing w */
463
				break;
464
			id = atoi(x->wname[i]);
465
			qlock(&row);
466
			w = lookid(id, FALSE);
467
			if(w == nil){
468
				qunlock(&row);
469
				break;
470
			}
471
			incref(w);	/* we'll drop reference at end if there's an error */
472
			path = Qdir;
473
			type = QTDIR;
474
			qunlock(&row);
475
			dir = dirtabw;
476
			goto Accept;
477
 
478
    Regular:
479
//			if(FILE(f->qid) == Qacme)	/* empty directory */
480
//				break;
481
			if(strcmp(x->wname[i], "new") == 0){
482
				if(w)
483
					error("w set in walk to new");
484
				sendp(cnewwindow, nil);	/* signal newwindowthread */
485
				w = recvp(cnewwindow);	/* receive new window */
486
				incref(w);
487
				type = QTDIR;
488
				path = QID(w->id, Qdir);
489
				id = w->id;
490
				dir = dirtabw;
491
				goto Accept;
492
			}
493
 
494
			if(id == 0)
495
				d = dirtab;
496
			else
497
				d = dirtabw;
498
			d++;	/* skip '.' */
499
			for(; d->name; d++)
500
				if(strcmp(x->wname[i], d->name) == 0){
501
					path = d->qid;
502
					type = d->type;
503
					dir = d;
504
					goto Accept;
505
				}
506
 
507
			break;	/* file not found */
508
		}
509
 
510
		if(i==0 && err == nil)
511
			err = Eexist;
512
	}
513
 
514
	if(err!=nil || t.nwqid<x->nwname){
515
		if(nf){
516
			nf->busy = FALSE;
517
			fsysdelid(nf->mntdir);
518
		}
519
	}else if(t.nwqid  == x->nwname){
520
		if(w){
521
			f->w = w;
522
			w = nil;	/* don't drop the reference */
523
		}
524
		if(dir)
525
			f->dir = dir;
526
		f->qid = q;
527
	}
528
 
529
	if(w != nil)
530
		winclose(w);
531
 
532
	return respond(x, &t, err);
533
}
534
 
535
static
536
Xfid*
537
fsysopen(Xfid *x, Fid *f)
538
{
539
	Fcall t;
540
	int m;
541
 
542
	/* can't truncate anything, so just disregard */
543
	x->mode &= ~(OTRUNC|OCEXEC);
544
	/* can't execute or remove anything */
545
	if(x->mode==OEXEC || (x->mode&ORCLOSE))
546
		goto Deny;
547
	switch(x->mode){
548
	default:
549
		goto Deny;
550
	case OREAD:
551
		m = 0400;
552
		break;
553
	case OWRITE:
554
		m = 0200;
555
		break;
556
	case ORDWR:
557
		m = 0600;
558
		break;
559
	}
560
	if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
561
		goto Deny;
562
 
563
	sendp(x->c, xfidopen);
564
	return nil;
565
 
566
    Deny:
567
	return respond(x, &t, Eperm);
568
}
569
 
570
static
571
Xfid*
572
fsyscreate(Xfid *x, Fid*)
573
{
574
	Fcall t;
575
 
576
	return respond(x, &t, Eperm);
577
}
578
 
579
static
580
int
581
idcmp(void *a, void *b)
582
{
583
	return *(int*)a - *(int*)b;
584
}
585
 
586
static
587
Xfid*
588
fsysread(Xfid *x, Fid *f)
589
{
590
	Fcall t;
591
	uchar *b;
592
	int i, id, n, o, e, j, k, *ids, nids;
593
	Dirtab *d, dt;
594
	Column *c;
595
	uint clock, len;
596
	char buf[16];
597
 
598
	if(f->qid.type & QTDIR){
599
		if(FILE(f->qid) == Qacme){	/* empty dir */
600
			t.data = nil;
601
			t.count = 0;
602
			respond(x, &t, nil);
603
			return x;
604
		}
605
		o = x->offset;
606
		e = x->offset+x->count;
607
		clock = getclock();
608
		b = emalloc(messagesize);
609
		id = WIN(f->qid);
610
		n = 0;
611
		if(id > 0)
612
			d = dirtabw;
613
		else
614
			d = dirtab;
615
		d++;	/* first entry is '.' */
616
		for(i=0; d->name!=nil && i<e; i+=len){
617
			len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);
618
			if(len <= BIT16SZ)
619
				break;
620
			if(i >= o)
621
				n += len;
622
			d++;
623
		}
624
		if(id == 0){
625
			qlock(&row);
626
			nids = 0;
627
			ids = nil;
628
			for(j=0; j<row.ncol; j++){
629
				c = row.col[j];
630
				for(k=0; k<c->nw; k++){
631
					ids = erealloc(ids, (nids+1)*sizeof(int));
632
					ids[nids++] = c->w[k]->id;
633
				}
634
			}
635
			qunlock(&row);
636
			qsort(ids, nids, sizeof ids[0], idcmp);
637
			j = 0;
638
			dt.name = buf;
639
			for(; j<nids && i<e; i+=len){
640
				k = ids[j];
641
				sprint(dt.name, "%d", k);
642
				dt.qid = QID(k, Qdir);
643
				dt.type = QTDIR;
644
				dt.perm = DMDIR|0700;
645
				len = dostat(k, &dt, b+n, x->count-n, clock);
646
				if(len == 0)
647
					break;
648
				if(i >= o)
649
					n += len;
650
				j++;
651
			}
652
			free(ids);
653
		}
654
		t.data = (char*)b;
655
		t.count = n;
656
		respond(x, &t, nil);
657
		free(b);
658
		return x;
659
	}
660
	sendp(x->c, xfidread);
661
	return nil;
662
}
663
 
664
static
665
Xfid*
666
fsyswrite(Xfid *x, Fid*)
667
{
668
	sendp(x->c, xfidwrite);
669
	return nil;
670
}
671
 
672
static
673
Xfid*
674
fsysclunk(Xfid *x, Fid *f)
675
{
676
	fsysdelid(f->mntdir);
677
	sendp(x->c, xfidclose);
678
	return nil;
679
}
680
 
681
static
682
Xfid*
683
fsysremove(Xfid *x, Fid*)
684
{
685
	Fcall t;
686
 
687
	return respond(x, &t, Eperm);
688
}
689
 
690
static
691
Xfid*
692
fsysstat(Xfid *x, Fid *f)
693
{
694
	Fcall t;
695
 
696
	t.stat = emalloc(messagesize-IOHDRSZ);
697
	t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
698
	x = respond(x, &t, nil);
699
	free(t.stat);
700
	return x;
701
}
702
 
703
static
704
Xfid*
705
fsyswstat(Xfid *x, Fid*)
706
{
707
	Fcall t;
708
 
709
	return respond(x, &t, Eperm);
710
}
711
 
712
Fid*
713
newfid(int fid)
714
{
715
	Fid *f, *ff, **fh;
716
 
717
	ff = nil;
718
	fh = &fids[fid&(Nhash-1)];
719
	for(f=*fh; f; f=f->next)
720
		if(f->fid == fid)
721
			return f;
722
		else if(ff==nil && f->busy==FALSE)
723
			ff = f;
724
	if(ff){
725
		ff->fid = fid;
726
		return ff;
727
	}
728
	f = emalloc(sizeof *f);
729
	f->fid = fid;
730
	f->next = *fh;
731
	*fh = f;
732
	return f;
733
}
734
 
735
uint
736
getclock()
737
{
738
	char buf[32];
739
 
740
	buf[0] = '\0';
741
	pread(clockfd, buf, sizeof buf, 0);
742
	return atoi(buf);
743
}
744
 
745
int
746
dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
747
{
748
	Dir d;
749
 
750
	d.qid.path = QID(id, dir->qid);
751
	d.qid.vers = 0;
752
	d.qid.type = dir->type;
753
	d.mode = dir->perm;
754
	d.length = 0;	/* would be nice to do better */
755
	d.name = dir->name;
756
	d.uid = user;
757
	d.gid = user;
758
	d.muid = user;
759
	d.atime = clock;
760
	d.mtime = clock;
761
	return convD2M(&d, buf, nbuf);
762
}