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 "stdinc.h"
2
#include <fcall.h>
3
#include "vac.h"
4
 
5
#define convM2Su(a, b, c, d) convM2S(a, b, c)
6
#define convS2Mu(a, b, c, d) convS2M(a, b, c)
7
#define convM2Du(a, b, c, d) convM2D(a, b, c)
8
#define convD2Mu(a, b, c, d) convD2M(a, b, c)
9
 
10
typedef struct Fid Fid;
11
 
12
enum
13
{
14
	Stacksize = 320 * 1024,	/* was 32K */
15
	OPERM	= 0x3		/* mask of all permission types in open mode */
16
};
17
 
18
struct Fid
19
{
20
	short busy;
21
	short open;
22
	int fid;
23
	char *user;
24
	Qid qid;
25
	VacFile *file;
26
	VacDirEnum *vde;
27
	Fid	*next;
28
};
29
 
30
enum
31
{
32
	Pexec =		1,
33
	Pwrite = 	2,
34
	Pread = 	4,
35
	Pother = 	1,
36
	Pgroup = 	8,
37
	Powner =	64
38
};
39
 
40
Fid	*fids;
41
uchar	*data;
42
int	mfd[2];
43
int	srvfd = -1;
44
char	*user;
45
uchar	mdata[8192+IOHDRSZ];
46
int messagesize = sizeof mdata;
47
Fcall	rhdr;
48
Fcall	thdr;
49
VacFs	*fs;
50
VtConn  *conn;
51
int	noperm;
52
int	dotu;
53
char *defmnt;
54
 
55
Fid *	newfid(int);
56
void	error(char*);
57
void	io(void);
58
void	vacshutdown(void);
59
void	usage(void);
60
int	perm(Fid*, int);
61
int	permf(VacFile*, char*, int);
62
ulong	getl(void *p);
63
void	init(char*, char*, long, int);
64
int	vacdirread(Fid *f, char *p, long off, long cnt);
65
int	vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
66
void 	srv(void* a);
67
 
68
 
69
char	*rflush(Fid*), *rversion(Fid*),
70
	*rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
71
	*ropen(Fid*), *rcreate(Fid*),
72
	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
73
	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
74
 
75
char 	*(*fcalls[Tmax])(Fid*);
76
 
77
void
78
initfcalls(void)
79
{
80
	fcalls[Tflush]=	rflush;
81
	fcalls[Tversion]=	rversion;
82
	fcalls[Tattach]=	rattach;
83
	fcalls[Tauth]=		rauth;
84
	fcalls[Twalk]=		rwalk;
85
	fcalls[Topen]=		ropen;
86
	fcalls[Tcreate]=	rcreate;
87
	fcalls[Tread]=		rread;
88
	fcalls[Twrite]=	rwrite;
89
	fcalls[Tclunk]=	rclunk;
90
	fcalls[Tremove]=	rremove;
91
	fcalls[Tstat]=		rstat;
92
	fcalls[Twstat]=	rwstat;
93
}
94
 
95
char	Eperm[] =	"permission denied";
96
char	Enotdir[] =	"not a directory";
97
char	Enotexist[] =	"file does not exist";
98
char	Einuse[] =	"file in use";
99
char	Eexist[] =	"file exists";
100
char	Enotowner[] =	"not owner";
101
char	Eisopen[] = 	"file already open for I/O";
102
char	Excl[] = 	"exclusive use file already open";
103
char	Ename[] = 	"illegal name";
104
char	Erdonly[] = 	"read only file system";
105
char	Eio[] = 	"i/o error";
106
char	Eempty[] = 	"directory is not empty";
107
char	Emode[] =	"illegal mode";
108
 
109
int dflag;
110
 
111
void
112
notifyf(void *a, char *s)
113
{
114
	USED(a);
115
	if(strncmp(s, "interrupt", 9) == 0)
116
		noted(NCONT);
117
	noted(NDFLT);
118
}
119
 
120
void
121
threadmain(int argc, char *argv[])
122
{
123
	char *defsrv, *srvname;
124
	int p[2], fd;
125
	int stdio;
126
	char *host = nil;
127
	long ncache;
128
 
129
	stdio = 0;
130
	ncache = 256;
131
	fmtinstall('H', encodefmt);
132
	fmtinstall('V', vtscorefmt);
133
	fmtinstall('F', vtfcallfmt);
134
 
135
	defmnt = nil;
136
	defsrv = nil;
137
	ARGBEGIN{
138
	case 'd':
139
		fmtinstall('F', fcallfmt);
140
		dflag = 1;
141
		break;
142
	case 'c':
143
		ncache = atoi(EARGF(usage()));
144
		break;
145
	case 'i':
146
		defmnt = nil;
147
		stdio = 1;
148
		mfd[0] = 0;
149
		mfd[1] = 1;
150
		break;
151
	case 'h':
152
		host = EARGF(usage());
153
		break;
154
	case 'S':
155
		defsrv = EARGF(usage());
156
		break;
157
	case 's':
158
		defsrv = "vacfs";
159
		break;
160
	case 'm':
161
		defmnt = EARGF(usage());
162
		break;
163
	case 'p':
164
		noperm = 1;
165
		break;
166
	case 'V':
167
		chattyventi = 1;
168
		break;
169
	default:
170
		usage();
171
	}ARGEND
172
 
173
	if(argc != 1)
174
		usage();
175
 
176
	if(defsrv == nil && defmnt == nil && !stdio)
177
		defmnt = "/n/vac";
178
	if(stdio && defmnt)
179
		sysfatal("cannot use -m with -i");
180
 
181
	initfcalls();
182
 
183
	notify(notifyf);
184
	user = getuser();
185
 
186
	conn = vtdial(host);
187
	if(conn == nil)
188
		sysfatal("could not connect to server: %r");
189
 
190
	if(vtconnect(conn) < 0)
191
		sysfatal("vtconnect: %r");
192
 
193
	fs = vacfsopen(conn, argv[0], VtOREAD, ncache);
194
	if(fs == nil)
195
		sysfatal("vacfsopen: %r");
196
 
197
	if(!stdio){
198
		if(pipe(p) < 0)
199
			sysfatal("pipe failed: %r");
200
		mfd[0] = p[0];
201
		mfd[1] = p[0];
202
		srvfd = p[1];
203
		if(defsrv){
204
			srvname = smprint("/srv/%s", defsrv);
205
			fd = create(srvname, OWRITE|ORCLOSE, 0666);
206
			if(fd < 0)
207
				sysfatal("create %s: %r", srvname);
208
			if(fprint(fd, "%d", srvfd) < 0)
209
				sysfatal("write %s: %r", srvname);
210
			free(srvname);
211
		}
212
	}
213
 
214
	procrfork(srv, 0, Stacksize, RFFDG|RFNAMEG|RFNOTEG);
215
 
216
	if(!stdio){
217
		close(p[0]);
218
		if(defmnt){
219
			if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
220
				sysfatal("mount %s: %r", defmnt);
221
		}
222
	}
223
	threadexits(0);
224
}
225
 
226
void
227
srv(void *a)
228
{
229
	USED(a);
230
	io();
231
	vacshutdown();
232
}
233
 
234
void
235
usage(void)
236
{
237
	fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
238
	threadexitsall("usage");
239
}
240
 
241
char*
242
rversion(Fid *unused)
243
{
244
	Fid *f;
245
 
246
	USED(unused);
247
 
248
	for(f = fids; f; f = f->next)
249
		if(f->busy)
250
			rclunk(f);
251
 
252
	if(rhdr.msize < 256)
253
		return vtstrdup("version: message size too small");
254
	messagesize = rhdr.msize;
255
	if(messagesize > sizeof mdata)
256
		messagesize = sizeof mdata;
257
	thdr.msize = messagesize;
258
	if(strncmp(rhdr.version, "9P2000", 6) != 0)
259
		return vtstrdup("unrecognized 9P version");
260
	thdr.version = "9P2000";
261
	if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
262
		dotu = 1;
263
		thdr.version = "9P2000.u";
264
	}
265
	return nil;
266
}
267
 
268
char*
269
rflush(Fid *f)
270
{
271
	USED(f);
272
	return 0;
273
}
274
 
275
char*
276
rauth(Fid *f)
277
{
278
	USED(f);
279
	return vtstrdup("vacfs: authentication not required");
280
}
281
 
282
char*
283
rattach(Fid *f)
284
{
285
	/* no authentication for the momment */
286
	VacFile *file;
287
	char err[80];
288
 
289
	file = vacfsgetroot(fs);
290
	if(file == nil) {
291
		rerrstr(err, sizeof err);
292
		return vtstrdup(err);
293
	}
294
 
295
	f->busy = 1;
296
	f->file = file;
297
	f->qid.path = vacfilegetid(f->file);
298
	f->qid.vers = 0;
299
	f->qid.type = QTDIR;
300
	thdr.qid = f->qid;
301
	if(rhdr.uname[0])
302
		f->user = vtstrdup(rhdr.uname);
303
	else
304
		f->user = "none";
305
	return 0;
306
}
307
 
308
char*
309
rwalk(Fid *f)
310
{
311
	VacFile *file, *nfile;
312
	Fid *nf;
313
	int nqid, nwname;
314
	Qid qid;
315
	char *err = nil;
316
 
317
	if(f->busy == 0)
318
		return Enotexist;
319
	nf = nil;
320
	if(rhdr.fid != rhdr.newfid){
321
		if(f->open)
322
			return vtstrdup(Eisopen);
323
		if(f->busy == 0)
324
			return vtstrdup(Enotexist);
325
		nf = newfid(rhdr.newfid);
326
		if(nf->busy)
327
			return vtstrdup(Eisopen);
328
		nf->busy = 1;
329
		nf->open = 0;
330
		nf->qid = f->qid;
331
		nf->file = vacfileincref(f->file);
332
		nf->user = vtstrdup(f->user);
333
		f = nf;
334
	}
335
 
336
	nwname = rhdr.nwname;
337
 
338
	/* easy case */
339
	if(nwname == 0) {
340
		thdr.nwqid = 0;
341
		return 0;
342
	}
343
 
344
	file = f->file;
345
	vacfileincref(file);
346
	qid = f->qid;
347
 
348
	for(nqid = 0; nqid < nwname; nqid++){
349
		if((qid.type & QTDIR) == 0){
350
			err = Enotdir;
351
			break;
352
		}
353
		if(!permf(file, f->user, Pexec)) {
354
			err = Eperm;
355
			break;
356
		}
357
		nfile = vacfilewalk(file, rhdr.wname[nqid]);
358
		if(nfile == nil)
359
			break;
360
		vacfiledecref(file);
361
		file = nfile;
362
		qid.type = QTFILE;
363
		if(vacfileisdir(file))
364
			qid.type = QTDIR;
365
		qid.vers = vacfilegetmcount(file);
366
		qid.path = vacfilegetid(file);
367
		thdr.wqid[nqid] = qid;
368
	}
369
 
370
	thdr.nwqid = nqid;
371
 
372
	if(nqid == nwname){
373
		/* success */
374
		f->qid = thdr.wqid[nqid-1];
375
		vacfiledecref(f->file);
376
		f->file = file;
377
		return 0;
378
	}
379
 
380
	vacfiledecref(file);
381
	if(nf != nil)
382
		rclunk(nf);
383
 
384
	/* only error on the first element */
385
	if(nqid == 0)
386
		return vtstrdup(err);
387
 
388
	return 0;
389
}
390
 
391
char *
392
ropen(Fid *f)
393
{
394
	int mode, trunc;
395
 
396
	if(f->open)
397
		return vtstrdup(Eisopen);
398
	if(!f->busy)
399
		return vtstrdup(Enotexist);
400
 
401
	mode = rhdr.mode;
402
	thdr.iounit = messagesize - IOHDRSZ;
403
	if(f->qid.type & QTDIR){
404
		if(mode != OREAD)
405
			return vtstrdup(Eperm);
406
		if(!perm(f, Pread))
407
			return vtstrdup(Eperm);
408
		thdr.qid = f->qid;
409
		f->vde = nil;
410
		f->open = 1;
411
		return 0;
412
	}
413
	if(mode & ORCLOSE)
414
		return vtstrdup(Erdonly);
415
	trunc = mode & OTRUNC;
416
	mode &= OPERM;
417
	if(mode==OWRITE || mode==ORDWR || trunc)
418
		if(!perm(f, Pwrite))
419
			return vtstrdup(Eperm);
420
	if(mode==OREAD || mode==ORDWR)
421
		if(!perm(f, Pread))
422
			return vtstrdup(Eperm);
423
	if(mode==OEXEC)
424
		if(!perm(f, Pexec))
425
			return vtstrdup(Eperm);
426
	thdr.qid = f->qid;
427
	thdr.iounit = messagesize - IOHDRSZ;
428
	f->open = 1;
429
	return 0;
430
}
431
 
432
char*
433
rcreate(Fid* fid)
434
{
435
	VacFile *vf;
436
	ulong mode;
437
 
438
	if(fid->open)
439
		return vtstrdup(Eisopen);
440
	if(!fid->busy)
441
		return vtstrdup(Enotexist);
442
	if(fs->mode & ModeSnapshot)
443
		return vtstrdup(Erdonly);
444
	vf = fid->file;
445
	if(!vacfileisdir(vf))
446
		return vtstrdup(Enotdir);
447
	if(!permf(vf, fid->user, Pwrite))
448
		return vtstrdup(Eperm);
449
 
450
	mode = rhdr.perm & 0777;
451
 
452
	if(rhdr.perm & DMDIR){
453
		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
454
			return vtstrdup(Emode);
455
		switch(rhdr.mode & OPERM){
456
		default:
457
			return vtstrdup(Emode);
458
		case OEXEC:
459
		case OREAD:
460
			break;
461
		case OWRITE:
462
		case ORDWR:
463
			return vtstrdup(Eperm);
464
		}
465
		mode |= ModeDir;
466
	}
467
	vf = vacfilecreate(vf, rhdr.name, mode);
468
	if(vf == nil) {
469
		char err[80];
470
		rerrstr(err, sizeof err);
471
 
472
		return vtstrdup(err);
473
	}
474
 
475
	vacfiledecref(fid->file);
476
 
477
	fid->file = vf;
478
	fid->qid.type = QTFILE;
479
	if(vacfileisdir(vf))
480
		fid->qid.type = QTDIR;
481
	fid->qid.vers = vacfilegetmcount(vf);
482
	fid->qid.path = vacfilegetid(vf);
483
 
484
	thdr.qid = fid->qid;
485
	thdr.iounit = messagesize - IOHDRSZ;
486
 
487
	return 0;
488
}
489
 
490
char*
491
rread(Fid *f)
492
{
493
	char *buf;
494
	vlong off;
495
	int cnt;
496
	VacFile *vf;
497
	char err[80];
498
	int n;
499
 
500
	if(!f->busy)
501
		return vtstrdup(Enotexist);
502
	vf = f->file;
503
	thdr.count = 0;
504
	off = rhdr.offset;
505
	buf = thdr.data;
506
	cnt = rhdr.count;
507
	if(f->qid.type & QTDIR)
508
		n = vacdirread(f, buf, off, cnt);
509
	else if(vacfilegetmode(f->file)&ModeDevice)
510
		return vtstrdup("device");
511
	else if(vacfilegetmode(f->file)&ModeLink)
512
		return vtstrdup("symbolic link");
513
	else if(vacfilegetmode(f->file)&ModeNamedPipe)
514
		return vtstrdup("named pipe");
515
	else
516
		n = vacfileread(vf, buf, cnt, off);
517
	if(n < 0) {
518
		rerrstr(err, sizeof err);
519
		return vtstrdup(err);
520
	}
521
	thdr.count = n;
522
	return 0;
523
}
524
 
525
char*
526
rwrite(Fid *f)
527
{
528
	USED(f);
529
	return vtstrdup(Erdonly);
530
}
531
 
532
char *
533
rclunk(Fid *f)
534
{
535
	f->busy = 0;
536
	f->open = 0;
537
	vtfree(f->user);
538
	f->user = nil;
539
	if(f->file)
540
		vacfiledecref(f->file);
541
	f->file = nil;
542
	vdeclose(f->vde);
543
	f->vde = nil;
544
	return 0;
545
}
546
 
547
char *
548
rremove(Fid *f)
549
{
550
	VacFile *vf, *vfp;
551
	char errbuf[80];
552
	char *err = nil;
553
 
554
	if(!f->busy)
555
		return vtstrdup(Enotexist);
556
	vf = f->file;
557
	vfp = vacfilegetparent(vf);
558
 
559
	if(!permf(vfp, f->user, Pwrite)) {
560
		err = Eperm;
561
		goto Exit;
562
	}
563
 
564
	if(!vacfileremove(vf)) {
565
		rerrstr(errbuf, sizeof errbuf);
566
		err = errbuf;
567
	}
568
 
569
Exit:
570
	vacfiledecref(vfp);
571
	rclunk(f);
572
	return vtstrdup(err);
573
}
574
 
575
char *
576
rstat(Fid *f)
577
{
578
	VacDir dir;
579
	static uchar statbuf[1024];
580
	VacFile *parent;
581
 
582
	if(!f->busy)
583
		return vtstrdup(Enotexist);
584
	parent = vacfilegetparent(f->file);
585
	vacfilegetdir(f->file, &dir);
586
	thdr.stat = statbuf;
587
	thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
588
	vdcleanup(&dir);
589
	vacfiledecref(parent);
590
	return 0;
591
}
592
 
593
char *
594
rwstat(Fid *f)
595
{
596
	if(!f->busy)
597
		return vtstrdup(Enotexist);
598
	return vtstrdup(Erdonly);
599
}
600
 
601
int
602
vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
603
{
604
	int ret;
605
	Dir dir;
606
 
607
	memset(&dir, 0, sizeof(dir));
608
 
609
	dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
610
	if(vd->qidspace)
611
		dir.qid.path += vd->qidoffset;
612
	dir.qid.vers = vd->mcount;
613
	dir.mode = vd->mode & 0777;
614
	if(vd->mode & ModeAppend){
615
		dir.qid.type |= QTAPPEND;
616
		dir.mode |= DMAPPEND;
617
	}
618
	if(vd->mode & ModeExclusive){
619
		dir.qid.type |= QTEXCL;
620
		dir.mode |= DMEXCL;
621
	}
622
	if(vd->mode & ModeDir){
623
		dir.qid.type |= QTDIR;
624
		dir.mode |= DMDIR;
625
	}
626
 
627
 
628
	dir.atime = vd->atime;
629
	dir.mtime = vd->mtime;
630
	dir.length = vd->size;
631
 
632
	dir.name = vd->elem;
633
	dir.uid = vd->uid;
634
	dir.gid = vd->gid;
635
	dir.muid = vd->mid;
636
 
637
	ret = convD2Mu(&dir, p, np, dotu);
638
	return ret;
639
}
640
 
641
int
642
vacdirread(Fid *f, char *p, long off, long cnt)
643
{
644
	int i, n, nb;
645
	VacDir vd;
646
 
647
	/*
648
	 * special case of rewinding a directory
649
	 * otherwise ignore the offset
650
	 */
651
	if(off == 0 && f->vde){
652
		vdeclose(f->vde);
653
		f->vde = nil;
654
	}
655
 
656
	if(f->vde == nil){
657
		f->vde = vdeopen(f->file);
658
		if(f->vde == nil)
659
			return -1;
660
	}
661
 
662
	for(nb = 0; nb < cnt; nb += n) {
663
		i = vderead(f->vde, &vd);
664
		if(i < 0)
665
			return -1;
666
		if(i == 0)
667
			break;
668
		n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
669
		if(n <= BIT16SZ) {
670
			vdeunread(f->vde);
671
			break;
672
		}
673
		vdcleanup(&vd);
674
		p += n;
675
	}
676
	return nb;
677
}
678
 
679
Fid *
680
newfid(int fid)
681
{
682
	Fid *f, *ff;
683
 
684
	ff = 0;
685
	for(f = fids; f; f = f->next)
686
		if(f->fid == fid)
687
			return f;
688
		else if(!ff && !f->busy)
689
			ff = f;
690
	if(ff){
691
		ff->fid = fid;
692
		return ff;
693
	}
694
	f = vtmallocz(sizeof *f);
695
	f->fid = fid;
696
	f->next = fids;
697
	fids = f;
698
	return f;
699
}
700
 
701
void
702
io(void)
703
{
704
	char *err;
705
	int n;
706
 
707
	for(;;){
708
		n = read9pmsg(mfd[0], mdata, sizeof mdata);
709
		if(n <= 0)
710
			break;
711
		if(convM2Su(mdata, n, &rhdr, dotu) != n)
712
			sysfatal("convM2S conversion error");
713
 
714
		if(dflag)
715
			fprint(2, "vacfs:<-%F\n", &rhdr);
716
 
717
		thdr.data = (char*)mdata + IOHDRSZ;
718
		if(!fcalls[rhdr.type])
719
			err = "bad fcall type";
720
		else
721
			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
722
		if(err){
723
			thdr.type = Rerror;
724
			thdr.ename = err;
725
		}else{
726
			thdr.type = rhdr.type + 1;
727
			thdr.fid = rhdr.fid;
728
		}
729
		thdr.tag = rhdr.tag;
730
		if(dflag)
731
			fprint(2, "vacfs:->%F\n", &thdr);
732
		n = convS2Mu(&thdr, mdata, messagesize, dotu);
733
		if(n <= BIT16SZ)
734
			sysfatal("convS2Mu conversion error");
735
		if(err)
736
			vtfree(err);
737
 
738
		if(write(mfd[1], mdata, n) != n)
739
			sysfatal("mount write: %r");
740
	}
741
}
742
 
743
int
744
permf(VacFile *vf, char *user, int p)
745
{
746
	VacDir dir;
747
	ulong perm;
748
 
749
	if(vacfilegetdir(vf, &dir))
750
		return 0;
751
	perm = dir.mode & 0777;
752
 
753
	if(noperm)
754
		goto Good;
755
	if((p*Pother) & perm)
756
		goto Good;
757
	if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
758
		goto Good;
759
	if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
760
		goto Good;
761
	vdcleanup(&dir);
762
	return 0;
763
Good:
764
	vdcleanup(&dir);
765
	return 1;
766
}
767
 
768
int
769
perm(Fid *f, int p)
770
{
771
	return permf(f->file, f->user, p);
772
}
773
 
774
void
775
vacshutdown(void)
776
{
777
	Fid *f;
778
 
779
	for(f = fids; f; f = f->next) {
780
		if(!f->busy)
781
			continue;
782
		rclunk(f);
783
	}
784
 
785
	vacfsclose(fs);
786
	vthangup(conn);
787
}
788