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	"lib.h"
3
#include	"dat.h"
4
#include	"fns.h"
5
#include	"error.h"
6
 
7
Chan*
8
fdtochan(int fd, int mode, int chkmnt, int iref)
9
{
10
	Fgrp *f;
11
	Chan *c;
12
 
13
	c = 0;
14
	f = up->fgrp;
15
 
16
	lock(&f->ref.lk);
17
	if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
18
		unlock(&f->ref.lk);
19
		error(Ebadfd);
20
	}
21
	if(iref)
22
		refinc(&c->ref);
23
	unlock(&f->ref.lk);
24
 
25
	if(chkmnt && (c->flag&CMSG))
26
		goto bad;
27
	if(mode<0 || c->mode==ORDWR)
28
		return c;
29
	if((mode&OTRUNC) && c->mode==OREAD)
30
		goto bad;
31
	if((mode&~OTRUNC) != c->mode)
32
		goto bad;
33
	return c;
34
bad:
35
	if(iref)
36
		cclose(c);
37
	error(Ebadusefd);
38
	return nil; /* shut up compiler */
39
}
40
 
41
static void
42
fdclose(int fd, int flag)
43
{
44
	int i;
45
	Chan *c;
46
	Fgrp *f;
47
 
48
	f = up->fgrp;
49
 
50
	lock(&f->ref.lk);
51
	c = f->fd[fd];
52
	if(c == 0) {
53
		unlock(&f->ref.lk);
54
		return;
55
	}
56
	if(flag) {
57
		if(c==0 || !(c->flag&flag)) {
58
			unlock(&f->ref.lk);
59
			return;
60
		}
61
	}
62
	f->fd[fd] = 0;
63
	if(fd == f->maxfd)
64
		for(i=fd; --i>=0 && f->fd[i]==0; )
65
			f->maxfd = i;
66
 
67
	unlock(&f->ref.lk);
68
	cclose(c);
69
}
70
 
71
static int
72
newfd(Chan *c)
73
{
74
	int i;
75
	Fgrp *f;
76
 
77
	f = up->fgrp;
78
	lock(&f->ref.lk);
79
	for(i=0; i<NFD; i++)
80
		if(f->fd[i] == 0){
81
			if(i > f->maxfd)
82
				f->maxfd = i;
83
			f->fd[i] = c;
84
			unlock(&f->ref.lk);
85
			return i;
86
		}
87
	unlock(&f->ref.lk);
88
	error("no file descriptors");
89
	return 0;
90
}
91
 
92
int
93
sysclose(int fd)
94
{
95
	if(waserror())
96
		return -1;
97
 
98
	fdtochan(fd, -1, 0, 0);
99
	fdclose(fd, 0);
100
	poperror();
101
	return 0;
102
}
103
 
104
int
105
syscreate(char *path, int mode, ulong perm)
106
{
107
	int fd;
108
	Chan *c = 0;
109
 
110
	if(waserror()) {
111
		cclose(c);
112
		return -1;
113
	}
114
 
115
	openmode(mode);			/* error check only */
116
	c = namec(path, Acreate, mode, perm);
117
	fd = newfd((Chan*)c);
118
	poperror();
119
	return fd;
120
}
121
 
122
int
123
sysdup(int old, int new)
124
{
125
	Chan *oc;
126
	Fgrp *f = up->fgrp;
127
	Chan *c = 0;
128
 
129
	if(waserror())
130
		return -1;
131
 
132
	c = fdtochan(old, -1, 0, 1);
133
	if(new != -1) {
134
		if(new < 0 || NFD <= new) {
135
			cclose(c);
136
			error(Ebadfd);
137
		}
138
		lock(&f->ref.lk);
139
		if(new > f->maxfd)
140
			f->maxfd = new;
141
		oc = f->fd[new];
142
		f->fd[new] = (Chan*)c;
143
		unlock(&f->ref.lk);
144
		if(oc != 0)
145
			cclose(oc);
146
	}
147
	else {
148
		if(waserror()) {
149
			cclose(c);
150
			nexterror();
151
		}
152
		new = newfd((Chan*)c);
153
		poperror();
154
	}
155
	poperror();
156
	return new;
157
}
158
 
159
int
160
sysfstat(int fd, char *buf)
161
{
162
	Chan *c = 0;
163
 
164
	if(waserror()) {
165
		cclose(c);
166
		return -1;
167
	}
168
	c = fdtochan(fd, -1, 0, 1);
169
	devtab[c->type]->stat((Chan*)c, buf);
170
	poperror();
171
	cclose(c);
172
	return 0;
173
}
174
 
175
int
176
sysfwstat(int fd, char *buf)
177
{
178
	Chan *c = 0;
179
 
180
	if(waserror()) {
181
		cclose(c);
182
		return -1;
183
	}
184
	nameok(buf);
185
	c = fdtochan(fd, -1, 1, 1);
186
	devtab[c->type]->wstat((Chan*)c, buf);
187
	poperror();
188
	cclose(c);
189
	return 0;
190
}
191
 
192
int
193
syschdir(char *dir)
194
{
195
	return 0;
196
}
197
 
198
long
199
bindmount(Chan *c0, char *old, int flag, char *spec)
200
{
201
	int ret;
202
	Chan *c1 = 0;
203
 
204
	if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
205
		error(Ebadarg);
206
 
207
	c1 = namec(old, Amount, 0, 0);
208
	if(waserror()){
209
		cclose(c1);
210
		nexterror();
211
	}
212
 
213
	ret = cmount(c0, c1, flag, spec);
214
 
215
	poperror();
216
	cclose(c1);
217
	return ret;
218
}
219
 
220
int
221
sysbind(char *new, char *old, int flags)
222
{
223
	long r;
224
	Chan *c0 = 0;
225
 
226
	if(waserror()) {
227
		cclose(c0);
228
		return -1;
229
	}
230
	c0 = namec(new, Aaccess, 0, 0);
231
	r = bindmount(c0, old, flags, "");
232
	poperror();
233
	cclose(c0);
234
	return 0;
235
}
236
 
237
int
238
sysmount(int fd, char *old, int flags, char *spec)
239
{
240
	long r;
241
	Chan *c0 = 0, *bc = 0;
242
	struct {
243
		Chan*	chan;
244
		char*	spec;
245
		int	flags;
246
	} mntparam;
247
 
248
	if(waserror()) {
249
		cclose(bc);
250
		cclose(c0);
251
		return -1;
252
	}
253
	bc = fdtochan(fd, ORDWR, 0, 1);
254
	mntparam.chan = (Chan*)bc;
255
	mntparam.spec = spec;
256
	mntparam.flags = flags;
257
	c0 = (*devtab[devno('M', 0)].attach)(&mntparam);
258
	cclose(bc);
259
	r = bindmount(c0, old, flags, spec);
260
	poperror();
261
	cclose(c0);
262
 
263
	return r;
264
}
265
 
266
int
267
sysunmount(char *old, char *new)
268
{
269
	Chan *cmount = 0, *cmounted = 0;
270
 
271
	if(waserror()) {
272
		cclose(cmount);
273
		cclose(cmounted);
274
		return -1;
275
	}
276
 
277
	cmount = namec(new, Amount, OREAD, 0);
278
	if(old != 0)
279
		cmounted = namec(old, Aopen, OREAD, 0);
280
 
281
	cunmount(cmount, cmounted);
282
	poperror();	
283
	cclose(cmount);
284
	cclose(cmounted);
285
	return 0;
286
}
287
 
288
int
289
sysopen(char *path, int mode)
290
{
291
	int fd;
292
	Chan *c = 0;
293
 
294
	if(waserror()){
295
		cclose(c);
296
		return -1;
297
	}
298
	openmode(mode);				/* error check only */
299
	c = namec(path, Aopen, mode, 0);
300
	fd = newfd((Chan*)c);
301
	poperror();
302
	return fd;
303
}
304
 
305
long
306
unionread(Chan *c, void *va, long n)
307
{
308
	long nr;
309
	Chan *nc = 0;
310
	Pgrp *pg = 0;
311
 
312
	pg = up->pgrp;
313
	rlock(&pg->ns);
314
 
315
	for(;;) {
316
		if(waserror()) {
317
			runlock(&pg->ns);
318
			nexterror();
319
		}
320
		nc = clone(c->mnt->to, 0);
321
		poperror();
322
 
323
		if(c->mountid != c->mnt->mountid) {
324
			runlock(&pg->ns);
325
			cclose(nc);
326
			return 0;
327
		}
328
 
329
		/* Error causes component of union to be skipped */
330
		if(waserror()) {	
331
			cclose(nc);
332
			goto next;
333
		}
334
 
335
		nc = (*devtab[nc->type].open)((Chan*)nc, OREAD);
336
		nc->offset = c->offset;
337
		nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset);
338
		/* devdirread e.g. changes it */
339
		c->offset = nc->offset;	
340
		poperror();
341
 
342
		cclose(nc);
343
		if(nr > 0) {
344
			runlock(&pg->ns);
345
			return nr;
346
		}
347
		/* Advance to next element */
348
	next:
349
		c->mnt = c->mnt->next;
350
		if(c->mnt == 0)
351
			break;
352
		c->mountid = c->mnt->mountid;
353
		c->offset = 0;
354
	}
355
	runlock(&pg->ns);
356
	return 0;
357
}
358
 
359
long
360
sysread(int fd, void *va, long n)
361
{
362
	int dir;
363
	Lock *cl;
364
	Chan *c = 0;
365
 
366
	if(waserror()) {
367
		cclose(c);
368
		return -1;
369
	}
370
	c = fdtochan(fd, OREAD, 1, 1);
371
 
372
	dir = c->qid.path&CHDIR;
373
	if(dir) {
374
		n -= n%DIRLEN;
375
		if(c->offset%DIRLEN || n==0)
376
			error(Etoosmall);
377
	}
378
 
379
	if(dir && c->mnt)
380
		n = unionread((Chan*)c, va, n);
381
	else
382
		n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset);
383
 
384
	cl = (Lock*)&c->r.l;
385
	lock(cl);
386
	c->offset += n;
387
	unlock(cl);
388
 
389
	poperror();
390
	cclose(c);
391
 
392
	return n;
393
}
394
 
395
int
396
sysremove(char *path)
397
{
398
	Chan *c = 0;
399
 
400
	if(waserror()) {
401
		if(c != 0)
402
			c->type = 0;	/* see below */
403
		cclose(c);
404
		return -1;
405
	}
406
	c = namec(path, Aaccess, 0, 0);
407
	(*devtab[c->type].remove)((Chan*)c);
408
	/*
409
	 * Remove clunks the fid, but we need to recover the Chan
410
	 * so fake it up.  rootclose() is known to be a nop.
411
	 */
412
	c->type = 0;
413
	poperror();
414
	cclose(c);
415
	return 0;
416
}
417
 
418
long
419
sysseek(int fd, long off, int whence)
420
{
421
	Dir dir;
422
	Chan *c;
423
	char buf[DIRLEN];
424
 
425
	if(waserror())
426
		return -1;
427
 
428
	c = fdtochan(fd, -1, 1, 0);
429
	if(c->qid.path & CHDIR)
430
		error(Eisdir);
431
 
432
	switch(whence) {
433
	case 0:
434
		c->offset = off;
435
		break;
436
 
437
	case 1:
438
		lock(&c->r.l);	/* lock for read/write update */
439
		c->offset += off;
440
		off = c->offset;
441
		unlock(&c->r.l);
442
		break;
443
 
444
	case 2:
445
		(*devtab[c->type].stat)(c, buf);
446
		convM2D(buf, &dir);
447
		c->offset = dir.length + off;
448
		off = c->offset;
449
		break;
450
	}
451
	poperror();
452
	return off;
453
}
454
 
455
int
456
sysstat(char *path, char *buf)
457
{
458
	Chan *c = 0;
459
 
460
	if(waserror()){
461
		cclose(c);
462
		return -1;
463
	}
464
	c = namec(path, Aaccess, 0, 0);
465
	(*devtab[c->type].stat)((Chan*)c, buf);
466
	poperror();
467
	cclose(c);
468
	return 0;
469
}
470
 
471
long
472
syswrite(int fd, void *va, long n)
473
{
474
	Lock *cl;
475
	Chan *c = 0;
476
 
477
	if(waserror()) {
478
		cclose(c);
479
		return -1;
480
	}
481
	c = fdtochan(fd, OWRITE, 1, 1);
482
	if(c->qid.path & CHDIR)
483
		error(Eisdir);
484
 
485
	n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset);
486
 
487
	cl = (Lock*)&c->r.l;
488
	lock(cl);
489
	c->offset += n;
490
	unlock(cl);
491
 
492
	poperror();
493
	cclose(c);
494
 
495
	return n;
496
}
497
 
498
int
499
syswstat(char *path, char *buf)
500
{
501
	Chan *c = 0;
502
 
503
	if(waserror()) {
504
		cclose(c);
505
		return -1;
506
	}
507
 
508
	nameok(buf);
509
	c = namec(path, Aaccess, 0, 0);
510
	(*devtab[c->type].wstat)((Chan*)c, buf);
511
	poperror();
512
	cclose(c);
513
	return 0;
514
}
515
 
516
int
517
sysdirstat(char *name, Dir *dir)
518
{
519
	char buf[DIRLEN];
520
 
521
	if(sysstat(name, buf) == -1)
522
		return -1;
523
	convM2D(buf, dir);
524
	return 0;
525
}
526
 
527
int
528
sysdirfstat(int fd, Dir *dir)
529
{
530
	char buf[DIRLEN];
531
 
532
	if(sysfstat(fd, buf) == -1)
533
		return -1;
534
 
535
	convM2D(buf, dir);
536
	return 0;
537
}
538
 
539
int
540
sysdirwstat(char *name, Dir *dir)
541
{
542
	char buf[DIRLEN];
543
 
544
	convD2M(dir, buf);
545
	return syswstat(name, buf);
546
}
547
 
548
int
549
sysdirfwstat(int fd, Dir *dir)
550
{
551
	char buf[DIRLEN];
552
 
553
	convD2M(dir, buf);
554
	return sysfwstat(fd, buf);
555
}
556
 
557
long
558
sysdirread(int fd, Dir *dbuf, long count)
559
{
560
	int c, n, i, r;
561
	char buf[DIRLEN*50];
562
 
563
	n = 0;
564
	count = (count/sizeof(Dir)) * DIRLEN;
565
	while(n < count) {
566
		c = count - n;
567
		if(c > sizeof(buf))
568
			c = sizeof(buf);
569
		r = sysread(fd, buf, c);
570
		if(r == 0)
571
			break;
572
		if(r < 0 || r % DIRLEN)
573
			return -1;
574
		for(i=0; i<r; i+=DIRLEN) {
575
			convM2D(buf+i, dbuf);
576
			dbuf++;
577
		}
578
		n += r;
579
		if(r != c)
580
			break;
581
	}
582
 
583
	return (n/DIRLEN) * sizeof(Dir);
584
}
585
 
586
static int
587
call(char *clone, char *dest, int *cfdp, char *dir, char *local)
588
{
589
	int fd, cfd, n;
590
	char *p, name[3*NAMELEN+5], data[3*NAMELEN+10];
591
 
592
	cfd = sysopen(clone, ORDWR);
593
	if(cfd < 0){
594
		werrstr("%s: %r", clone);
595
		return -1;
596
	}
597
 
598
	/* get directory name */
599
	n = sysread(cfd, name, sizeof(name)-1);
600
	if(n < 0) {
601
		sysclose(cfd);
602
		return -1;
603
	}
604
	name[n] = 0;
605
	sprint(name, "%d", strtoul(name, 0, 0));
606
	p = strrchr(clone, '/');
607
	*p = 0;
608
	if(dir)
609
		snprint(dir, 2*NAMELEN, "%s/%s", clone, name);
610
	snprint(data, sizeof(data), "%s/%s/data", clone, name);
611
 
612
	/* connect */
613
	/* set local side (port number, for example) if we need to */
614
	if(local)
615
		snprint(name, sizeof(name), "connect %s %s", dest, local);
616
	else
617
		snprint(name, sizeof(name), "connect %s", dest);
618
	if(syswrite(cfd, name, strlen(name)) < 0){
619
		werrstr("%s failed: %r", name);
620
		sysclose(cfd);
621
		return -1;
622
	}
623
 
624
	/* open data connection */
625
	fd = sysopen(data, ORDWR);
626
	if(fd < 0){
627
		werrstr("can't open %s: %r", data);
628
		sysclose(cfd);
629
		return -1;
630
	}
631
	if(cfdp)
632
		*cfdp = cfd;
633
	else
634
		sysclose(cfd);
635
	return fd;
636
}
637
 
638
int
639
sysdial(char *dest, char *local, char *dir, int *cfdp)
640
{
641
	int n, fd, rv;
642
	char *p, net[128], clone[NAMELEN+12];
643
 
644
	/* go for a standard form net!... */
645
	p = strchr(dest, '!');
646
	if(p == 0){
647
		snprint(net, sizeof(net), "net!%s", dest);
648
	} else {
649
		strncpy(net, dest, sizeof(net)-1);
650
		net[sizeof(net)-1] = 0;
651
	}
652
 
653
	/* call the connection server */
654
	fd = sysopen("/net/cs", ORDWR);
655
	if(fd < 0){
656
		/* no connection server, don't translate */
657
		p = strchr(net, '!');
658
		*p++ = 0;
659
		snprint(clone, sizeof(clone), "/net/%s/clone", net);
660
		return call(clone, p, cfdp, dir, local);
661
	}
662
 
663
	/*
664
	 *  send dest to connection to translate
665
	 */
666
	if(syswrite(fd, net, strlen(net)) < 0){
667
		werrstr("%s: %r", net);
668
		sysclose(fd);
669
		return -1;
670
	}
671
 
672
	/*
673
	 *  loop through each address from the connection server till
674
	 *  we get one that works.
675
	 */
676
	rv = -1;
677
	sysseek(fd, 0, 0);
678
	while((n = sysread(fd, net, sizeof(net) - 1)) > 0){
679
		net[n] = 0;
680
		p = strchr(net, ' ');
681
		if(p == 0)
682
			continue;
683
		*p++ = 0;
684
		rv = call(net, p, cfdp, dir, local);
685
		if(rv >= 0)
686
			break;
687
	}
688
	sysclose(fd);
689
	return rv;
690
}
691
 
692
static int
693
identtrans(char *addr, char *naddr, int na, char *file, int nf)
694
{
695
	char *p;
696
	char reply[4*NAMELEN];
697
 
698
	/* parse the network */
699
	strncpy(reply, addr, sizeof(reply));
700
	reply[sizeof(reply)-1] = 0;
701
	p = strchr(reply, '!');
702
	if(p)
703
		*p++ = 0;
704
 
705
	sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply);
706
	strncpy(naddr, p, na);
707
	naddr[na-1] = 0;
708
	return 1;
709
}
710
 
711
static int
712
nettrans(char *addr, char *naddr, int na, char *file, int nf)
713
{
714
	long n;
715
	int fd;
716
	char *cp;
717
	char reply[4*NAMELEN];
718
 
719
	/*
720
	 *  ask the connection server
721
	 */
722
	fd = sysopen("/net/cs", ORDWR);
723
	if(fd < 0)
724
		return identtrans(addr, naddr, na, file, nf);
725
	if(syswrite(fd, addr, strlen(addr)) < 0){
726
		sysclose(fd);
727
		return -1;
728
	}
729
	sysseek(fd, 0, 0);
730
	n = sysread(fd, reply, sizeof(reply)-1);
731
	sysclose(fd);
732
	if(n <= 0)
733
		return -1;
734
	reply[n] = '\0';
735
 
736
	/*
737
	 *  parse the reply
738
	 */
739
	cp = strchr(reply, ' ');
740
	if(cp == 0)
741
		return -1;
742
	*cp++ = 0;
743
	strncpy(naddr, cp, na);
744
	naddr[na-1] = 0;
745
	strncpy(file, reply, nf);
746
	file[nf-1] = 0;
747
	return 0;
748
}
749
 
750
int
751
sysannounce(char *addr, char *dir)
752
{
753
	char *cp;
754
	int ctl, n, m;
755
	char buf[3*NAMELEN];
756
	char buf2[3*NAMELEN];
757
	char netdir[2*NAMELEN];
758
	char naddr[3*NAMELEN];
759
 
760
	/*
761
	 *  translate the address
762
	 */
763
	if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){
764
		werrstr("can't translate address");
765
		return -1;
766
	}
767
 
768
	/*
769
	 * get a control channel
770
	 */
771
	ctl = sysopen(netdir, ORDWR);
772
	if(ctl<0){
773
		werrstr("can't open control channel");
774
		return -1;
775
	}
776
	cp = strrchr(netdir, '/');
777
	*cp = 0;
778
 
779
	/*
780
	 *  find out which line we have
781
	 */
782
	n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir);
783
	m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
784
	if(m <= 0) {
785
		sysclose(ctl);
786
		werrstr("can't read control file");
787
		return -1;
788
	}
789
	buf[n+m] = 0;
790
 
791
	/*
792
	 *  make the call
793
	 */
794
	n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr);
795
	if(syswrite(ctl, buf2, n) != n) {
796
		sysclose(ctl);
797
		werrstr("announcement fails");
798
		return -1;
799
	}
800
 
801
	strcpy(dir, buf);
802
 
803
	return ctl;
804
}
805
 
806
int
807
syslisten(char *dir, char *newdir)
808
{
809
	char *cp;
810
	int ctl, n, m;
811
	char buf[3*NAMELEN];
812
 
813
	/*
814
	 *  open listen, wait for a call
815
	 */
816
	sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir);
817
	ctl = sysopen(buf, ORDWR);
818
	if(ctl < 0)
819
		return -1;
820
 
821
	/*
822
	 *  find out which line we have
823
	 */
824
	strcpy(buf, dir);
825
	cp = strrchr(buf, '/');
826
	*++cp = 0;
827
	n = cp-buf;
828
	m = sysread(ctl, cp, sizeof(buf) - n - 1);
829
	if(n<=0){
830
		sysclose(ctl);
831
		return -1;
832
	}
833
	buf[n+m] = 0;
834
 
835
	strcpy(newdir, buf);
836
	return ctl;
837
}