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 <auth.h>
4
#include <fcall.h>
5
#define Extern	extern
6
#include "exportfs.h"
7
 
8
extern char *netdir, *local, *remote;
9
 
10
char Ebadfid[] = "Bad fid";
11
char Enotdir[] = "Not a directory";
12
char Edupfid[] = "Fid already in use";
13
char Eopen[] = "Fid already opened";
14
char Exmnt[] = "Cannot .. past mount point";
15
char Emip[] = "Mount in progress";
16
char Enopsmt[] = "Out of pseudo mount points";
17
char Enomem[] = "No memory";
18
char Eversion[] = "Bad 9P2000 version";
19
char Ereadonly[] = "File system read only";
20
 
21
ulong messagesize;
22
int readonly;
23
 
24
void
25
Xversion(Fsrpc *t)
26
{
27
	Fcall rhdr;
28
 
29
	if(t->work.msize > messagesize)
30
		t->work.msize = messagesize;
31
	messagesize = t->work.msize;
32
	if(strncmp(t->work.version, "9P2000", 6) != 0){
33
		reply(&t->work, &rhdr, Eversion);
34
		return;
35
	}
36
	rhdr.version = "9P2000";
37
	rhdr.msize = t->work.msize;
38
	reply(&t->work, &rhdr, 0);
39
	t->busy = 0;
40
}
41
 
42
void
43
Xauth(Fsrpc *t)
44
{
45
	Fcall rhdr;
46
 
47
	reply(&t->work, &rhdr, "exportfs: authentication not required");
48
	t->busy = 0;
49
}
50
 
51
void
52
Xflush(Fsrpc *t)
53
{
54
	Fsrpc *w, *e;
55
	Fcall rhdr;
56
 
57
	e = &Workq[Nr_workbufs];
58
 
59
	for(w = Workq; w < e; w++) {
60
		if(w->work.tag == t->work.oldtag) {
61
			DEBUG(DFD, "\tQ busy %d pid %p can %d\n", w->busy, w->pid, w->canint);
62
			if(w->busy && w->pid) {
63
				w->flushtag = t->work.tag;
64
				DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
65
				if(w->canint)
66
					postnote(PNPROC, w->pid, "flush");
67
				t->busy = 0;
68
				return;
69
			}
70
		}
71
	}
72
 
73
	reply(&t->work, &rhdr, 0);
74
	DEBUG(DFD, "\tflush reply\n");
75
	t->busy = 0;
76
}
77
 
78
void
79
Xattach(Fsrpc *t)
80
{
81
	int i, nfd;
82
	Fcall rhdr;
83
	Fid *f;
84
	char buf[128];
85
 
86
	f = newfid(t->work.fid);
87
	if(f == 0) {
88
		reply(&t->work, &rhdr, Ebadfid);
89
		t->busy = 0;
90
		return;
91
	}
92
 
93
	if(srvfd >= 0){
94
		if(psmpt == 0){
95
		Nomount:
96
			reply(&t->work, &rhdr, Enopsmt);
97
			t->busy = 0;
98
			freefid(t->work.fid);
99
			return;
100
		}
101
		for(i=0; i<Npsmpt; i++)
102
			if(psmap[i] == 0)
103
				break;
104
		if(i >= Npsmpt)
105
			goto Nomount;
106
		sprint(buf, "%d", i);
107
		f->f = file(psmpt, buf);
108
		if(f->f == nil)
109
			goto Nomount;
110
		sprint(buf, "/mnt/exportfs/%d", i);
111
		nfd = dup(srvfd, -1);
112
		if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
113
			errstr(buf, sizeof buf);
114
			reply(&t->work, &rhdr, buf);
115
			t->busy = 0;
116
			freefid(t->work.fid);
117
			close(nfd);
118
			return;
119
		}
120
		psmap[i] = 1;
121
		f->mid = i;
122
	}else{
123
		f->f = root;
124
		f->f->ref++;
125
	}
126
 
127
	rhdr.qid = f->f->qid;
128
	reply(&t->work, &rhdr, 0);
129
	t->busy = 0;
130
}
131
 
132
Fid*
133
clonefid(Fid *f, int new)
134
{
135
	Fid *n;
136
 
137
	n = newfid(new);
138
	if(n == 0) {
139
		n = getfid(new);
140
		if(n == 0)
141
			fatal("inconsistent fids");
142
		if(n->fid >= 0)
143
			close(n->fid);
144
		freefid(new);
145
		n = newfid(new);
146
		if(n == 0)
147
			fatal("inconsistent fids2");
148
	}
149
	n->f = f->f;
150
	n->f->ref++;
151
	return n;
152
}
153
 
154
void
155
Xwalk(Fsrpc *t)
156
{
157
	char err[ERRMAX], *e;
158
	Fcall rhdr;
159
	Fid *f, *nf;
160
	File *wf;
161
	int i;
162
 
163
	f = getfid(t->work.fid);
164
	if(f == 0) {
165
		reply(&t->work, &rhdr, Ebadfid);
166
		t->busy = 0;
167
		return;
168
	}
169
 
170
	nf = nil;
171
	if(t->work.newfid != t->work.fid){
172
		nf = clonefid(f, t->work.newfid);
173
		f = nf;
174
	}
175
 
176
	rhdr.nwqid = 0;
177
	e = nil;
178
	for(i=0; i<t->work.nwname; i++){
179
		if(i == MAXWELEM){
180
			e = "Too many path elements";
181
			break;
182
		}
183
 
184
		if(strcmp(t->work.wname[i], "..") == 0) {
185
			if(f->f->parent == nil) {
186
				e = Exmnt;
187
				break;
188
			}
189
			wf = f->f->parent;
190
			wf->ref++;
191
			goto Accept;
192
		}
193
 
194
		wf = file(f->f, t->work.wname[i]);
195
		if(wf == 0){
196
			errstr(err, sizeof err);
197
			e = err;
198
			break;
199
		}
200
    Accept:
201
		freefile(f->f);
202
		rhdr.wqid[rhdr.nwqid++] = wf->qid;
203
		f->f = wf;
204
		continue;
205
	}
206
 
207
	if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
208
		freefid(t->work.newfid);
209
	if(rhdr.nwqid > 0)
210
		e = nil;
211
	reply(&t->work, &rhdr, e);
212
	t->busy = 0;
213
}
214
 
215
void
216
Xclunk(Fsrpc *t)
217
{
218
	Fcall rhdr;
219
	Fid *f;
220
 
221
	f = getfid(t->work.fid);
222
	if(f == 0) {
223
		reply(&t->work, &rhdr, Ebadfid);
224
		t->busy = 0;
225
		return;
226
	}
227
 
228
	if(f->fid >= 0)
229
		close(f->fid);
230
 
231
	freefid(t->work.fid);
232
	reply(&t->work, &rhdr, 0);
233
	t->busy = 0;
234
}
235
 
236
void
237
Xstat(Fsrpc *t)
238
{
239
	char err[ERRMAX], *path;
240
	Fcall rhdr;
241
	Fid *f;
242
	Dir *d;
243
	int s;
244
	uchar *statbuf;
245
 
246
	f = getfid(t->work.fid);
247
	if(f == 0) {
248
		reply(&t->work, &rhdr, Ebadfid);
249
		t->busy = 0;
250
		return;
251
	}
252
	if(f->fid >= 0)
253
		d = dirfstat(f->fid);
254
	else {
255
		path = makepath(f->f, "");
256
		d = dirstat(path);
257
		free(path);
258
	}
259
 
260
	if(d == nil) {
261
		errstr(err, sizeof err);
262
		reply(&t->work, &rhdr, err);
263
		t->busy = 0;
264
		return;
265
	}
266
 
267
	d->qid.path = f->f->qidt->uniqpath;
268
	s = sizeD2M(d);
269
	statbuf = emallocz(s);
270
	s = convD2M(d, statbuf, s);
271
	free(d);
272
	rhdr.nstat = s;
273
	rhdr.stat = statbuf;
274
	reply(&t->work, &rhdr, 0);
275
	free(statbuf);
276
	t->busy = 0;
277
}
278
 
279
static int
280
getiounit(int fd)
281
{
282
	int n;
283
 
284
	n = iounit(fd);
285
	if(n > messagesize-IOHDRSZ)
286
		n = messagesize-IOHDRSZ;
287
	return n;
288
}
289
 
290
void
291
Xcreate(Fsrpc *t)
292
{
293
	char err[ERRMAX], *path;
294
	Fcall rhdr;
295
	Fid *f;
296
	File *nf;
297
 
298
	if(readonly) {
299
		reply(&t->work, &rhdr, Ereadonly);
300
		t->busy = 0;
301
		return;
302
	}
303
	f = getfid(t->work.fid);
304
	if(f == 0) {
305
		reply(&t->work, &rhdr, Ebadfid);
306
		t->busy = 0;
307
		return;
308
	}
309
 
310
 
311
	path = makepath(f->f, t->work.name);
312
	f->fid = create(path, t->work.mode, t->work.perm);
313
	free(path);
314
	if(f->fid < 0) {
315
		errstr(err, sizeof err);
316
		reply(&t->work, &rhdr, err);
317
		t->busy = 0;
318
		return;
319
	}
320
 
321
	nf = file(f->f, t->work.name);
322
	if(nf == 0) {
323
		errstr(err, sizeof err);
324
		reply(&t->work, &rhdr, err);
325
		t->busy = 0;
326
		return;
327
	}
328
 
329
	f->mode = t->work.mode;
330
	freefile(f->f);
331
	f->f = nf;
332
	rhdr.qid = f->f->qid;
333
	rhdr.iounit = getiounit(f->fid);
334
	reply(&t->work, &rhdr, 0);
335
	t->busy = 0;
336
}
337
 
338
void
339
Xremove(Fsrpc *t)
340
{
341
	char err[ERRMAX], *path;
342
	Fcall rhdr;
343
	Fid *f;
344
 
345
	if(readonly) {
346
		reply(&t->work, &rhdr, Ereadonly);
347
		t->busy = 0;
348
		return;
349
	}
350
	f = getfid(t->work.fid);
351
	if(f == 0) {
352
		reply(&t->work, &rhdr, Ebadfid);
353
		t->busy = 0;
354
		return;
355
	}
356
 
357
	path = makepath(f->f, "");
358
	DEBUG(DFD, "\tremove: %s\n", path);
359
	if(remove(path) < 0) {
360
		free(path);
361
		errstr(err, sizeof err);
362
		reply(&t->work, &rhdr, err);
363
		t->busy = 0;
364
		return;
365
	}
366
	free(path);
367
 
368
	f->f->inval = 1;
369
	if(f->fid >= 0)
370
		close(f->fid);
371
	freefid(t->work.fid);
372
 
373
	reply(&t->work, &rhdr, 0);
374
	t->busy = 0;
375
}
376
 
377
void
378
Xwstat(Fsrpc *t)
379
{
380
	char err[ERRMAX], *path;
381
	Fcall rhdr;
382
	Fid *f;
383
	int s;
384
	char *strings;
385
	Dir d;
386
 
387
	if(readonly) {
388
		reply(&t->work, &rhdr, Ereadonly);
389
		t->busy = 0;
390
		return;
391
	}
392
	f = getfid(t->work.fid);
393
	if(f == 0) {
394
		reply(&t->work, &rhdr, Ebadfid);
395
		t->busy = 0;
396
		return;
397
	}
398
	strings = emallocz(t->work.nstat);	/* ample */
399
	if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
400
		rerrstr(err, sizeof err);
401
		reply(&t->work, &rhdr, err);
402
		t->busy = 0;
403
		free(strings);
404
		return;
405
	}
406
 
407
	if(f->fid >= 0)
408
		s = dirfwstat(f->fid, &d);
409
	else {
410
		path = makepath(f->f, "");
411
		s = dirwstat(path, &d);
412
		free(path);
413
	}
414
	if(s < 0) {
415
		rerrstr(err, sizeof err);
416
		reply(&t->work, &rhdr, err);
417
	}
418
	else {
419
		/* wstat may really be rename */
420
		if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
421
			free(f->f->name);
422
			f->f->name = estrdup(d.name);
423
		}
424
		reply(&t->work, &rhdr, 0);
425
	}
426
	free(strings);
427
	t->busy = 0;
428
}
429
 
430
/*
431
 * based on libthread's threadsetname, but drags in less library code.
432
 * actually just sets the arguments displayed.
433
 */
434
void
435
procsetname(char *fmt, ...)
436
{
437
	int fd;
438
	char *cmdname;
439
	char buf[128];
440
	va_list arg;
441
 
442
	va_start(arg, fmt);
443
	cmdname = vsmprint(fmt, arg);
444
	va_end(arg);
445
	if (cmdname == nil)
446
		return;
447
	snprint(buf, sizeof buf, "#p/%d/args", getpid());
448
	if((fd = open(buf, OWRITE)) >= 0){
449
		write(fd, cmdname, strlen(cmdname)+1);
450
		close(fd);
451
	}
452
	free(cmdname);
453
}
454
 
455
void
456
slave(Fsrpc *f)
457
{
458
	Proc *p;
459
	uintptr pid;
460
	Fcall rhdr;
461
	static int nproc;
462
 
463
	if(readonly){
464
		switch(f->work.type){
465
		case Twrite:
466
			reply(&f->work, &rhdr, Ereadonly);
467
			f->busy = 0;
468
			return;
469
		case Topen:
470
		  	if((f->work.mode&3) == OWRITE || (f->work.mode&OTRUNC)){
471
				reply(&f->work, &rhdr, Ereadonly);
472
				f->busy = 0;
473
				return;
474
			}
475
		}
476
	}
477
	for(;;) {
478
		for(p = Proclist; p; p = p->next) {
479
			if(p->busy == 0) {
480
				f->pid = p->pid;
481
				p->busy = 1;
482
				pid = (uintptr)rendezvous((void*)p->pid, f);
483
				if(pid != p->pid)
484
					fatal("rendezvous sync fail");
485
				return;
486
			}	
487
		}
488
 
489
		if(++nproc > MAXPROC)
490
			fatal("too many procs");
491
 
492
		pid = rfork(RFPROC|RFMEM);
493
		switch(pid) {
494
		case -1:
495
			fatal("rfork");
496
 
497
		case 0:
498
			if (local[0] != '\0')
499
				if (netdir[0] != '\0')
500
					procsetname("%s: %s -> %s", netdir, 
501
						local, remote);
502
				else
503
					procsetname("%s -> %s", local, remote);
504
			blockingslave();
505
			fatal("slave");
506
 
507
		default:
508
			p = malloc(sizeof(Proc));
509
			if(p == 0)
510
				fatal("out of memory");
511
 
512
			p->busy = 0;
513
			p->pid = pid;
514
			p->next = Proclist;
515
			Proclist = p;
516
 
517
			rendezvous((void*)pid, p);
518
		}
519
	}
520
}
521
 
522
void
523
blockingslave(void)
524
{
525
	Fsrpc *p;
526
	Fcall rhdr;
527
	Proc *m;
528
	uintptr pid;
529
 
530
	notify(flushaction);
531
 
532
	pid = getpid();
533
 
534
	m = rendezvous((void*)pid, 0);
535
 
536
	for(;;) {
537
		p = rendezvous((void*)pid, (void*)pid);
538
		if(p == (void*)~0)			/* Interrupted */
539
			continue;
540
 
541
		DEBUG(DFD, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid);
542
		if(p->flushtag != NOTAG)
543
			goto flushme;
544
 
545
		switch(p->work.type) {
546
		case Tread:
547
			slaveread(p);
548
			break;
549
 
550
		case Twrite:
551
			slavewrite(p);
552
			break;
553
 
554
		case Topen:
555
			slaveopen(p);
556
			break;
557
 
558
		default:
559
			reply(&p->work, &rhdr, "exportfs: slave type error");
560
		}
561
		if(p->flushtag != NOTAG) {
562
flushme:
563
			p->work.type = Tflush;
564
			p->work.tag = p->flushtag;
565
			reply(&p->work, &rhdr, 0);
566
		}
567
		p->busy = 0;
568
		m->busy = 0;
569
	}
570
}
571
 
572
int
573
openmount(int sfd)
574
{
575
	int p[2];
576
	char *arg[10], fdbuf[20], mbuf[20];
577
 
578
	if(pipe(p) < 0)
579
		return -1;
580
 
581
	switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG)){
582
	case -1:
583
		return -1;
584
 
585
	default:
586
		close(sfd);
587
		close(p[0]);
588
		return p[1];
589
 
590
	case 0:
591
		break;
592
	}
593
 
594
	close(p[1]);
595
 
596
	arg[0] = "exportfs";
597
	snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
598
	arg[1] = fdbuf;
599
	snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
600
	arg[2] = mbuf;
601
	arg[3] = nil;
602
 
603
	close(0);
604
	close(1);
605
	dup(p[0], 0);
606
	dup(p[0], 1);
607
	exec("/bin/exportfs", arg);
608
	_exits("whoops: exec failed");	
609
	return -1;
610
}
611
 
612
void
613
slaveopen(Fsrpc *p)
614
{
615
	char err[ERRMAX], *path;
616
	Fcall *work, rhdr;
617
	Fid *f;
618
	Dir *d;
619
 
620
	work = &p->work;
621
 
622
	f = getfid(work->fid);
623
	if(f == 0) {
624
		reply(work, &rhdr, Ebadfid);
625
		return;
626
	}
627
	if(f->fid >= 0) {
628
		close(f->fid);
629
		f->fid = -1;
630
	}
631
 
632
	path = makepath(f->f, "");
633
	DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
634
 
635
	p->canint = 1;
636
	if(p->flushtag != NOTAG){
637
		free(path);
638
		return;
639
	}
640
	/* There is a race here I ignore because there are no locks */
641
	f->fid = open(path, work->mode);
642
	free(path);
643
	p->canint = 0;
644
	if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
645
	Error:
646
		errstr(err, sizeof err);
647
		reply(work, &rhdr, err);
648
		return;
649
	}
650
	f->f->qid = d->qid;
651
	free(d);
652
	if(f->f->qid.type & QTMOUNT){	/* fork new exportfs for this */
653
		f->fid = openmount(f->fid);
654
		if(f->fid < 0)
655
			goto Error;
656
	}
657
 
658
	DEBUG(DFD, "\topen: fd %d\n", f->fid);
659
	f->mode = work->mode;
660
	f->offset = 0;
661
	rhdr.iounit = getiounit(f->fid);
662
	rhdr.qid = f->f->qid;
663
	reply(work, &rhdr, 0);
664
}
665
 
666
void
667
slaveread(Fsrpc *p)
668
{
669
	Fid *f;
670
	int n, r;
671
	Fcall *work, rhdr;
672
	char *data, err[ERRMAX];
673
 
674
	work = &p->work;
675
 
676
	f = getfid(work->fid);
677
	if(f == 0) {
678
		reply(work, &rhdr, Ebadfid);
679
		return;
680
	}
681
 
682
	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
683
	p->canint = 1;
684
	if(p->flushtag != NOTAG)
685
		return;
686
	data = malloc(n);
687
	if(data == nil)
688
		fatal(Enomem);
689
 
690
	/* can't just call pread, since directories must update the offset */
691
	if(patternfile != nil && (f->f->qid.type&QTDIR))
692
		r = preaddir(f, (uchar*)data, n, work->offset);
693
	else
694
		r = pread(f->fid, data, n, work->offset);
695
	p->canint = 0;
696
	if(r < 0) {
697
		free(data);
698
		errstr(err, sizeof err);
699
		reply(work, &rhdr, err);
700
		return;
701
	}
702
 
703
	DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
704
 
705
	rhdr.data = data;
706
	rhdr.count = r;
707
	reply(work, &rhdr, 0);
708
	free(data);
709
}
710
 
711
void
712
slavewrite(Fsrpc *p)
713
{
714
	char err[ERRMAX];
715
	Fcall *work, rhdr;
716
	Fid *f;
717
	int n;
718
 
719
	work = &p->work;
720
 
721
	f = getfid(work->fid);
722
	if(f == 0) {
723
		reply(work, &rhdr, Ebadfid);
724
		return;
725
	}
726
 
727
	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
728
	p->canint = 1;
729
	if(p->flushtag != NOTAG)
730
		return;
731
	n = pwrite(f->fid, work->data, n, work->offset);
732
	p->canint = 0;
733
	if(n < 0) {
734
		errstr(err, sizeof err);
735
		reply(work, &rhdr, err);
736
		return;
737
	}
738
 
739
	DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
740
 
741
	rhdr.count = n;
742
	reply(work, &rhdr, 0);
743
}
744
 
745
void
746
reopen(Fid *f)
747
{
748
	USED(f);
749
	fatal("reopen");
750
}
751
 
752
void
753
flushaction(void *a, char *cause)
754
{
755
	USED(a);
756
	if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
757
		fprint(2, "exportsrv: note: %s\n", cause);
758
		exits("noted");
759
	}
760
	if(strncmp(cause, "kill", 4) == 0)
761
		noted(NDFLT);
762
 
763
	noted(NCONT);
764
}