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	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
 
8
/*
9
 * The sys*() routines needn't poperror() as they return directly to syscall().
10
 */
11
 
12
static void
13
unlockfgrp(Fgrp *f)
14
{
15
	int ex;
16
 
17
	ex = f->exceed;
18
	f->exceed = 0;
19
	unlock(f);
20
	if(ex)
21
		pprint("warning: process exceeds %d file descriptors\n", ex);
22
}
23
 
24
int
25
growfd(Fgrp *f, int fd)	/* fd is always >= 0 */
26
{
27
	Chan **newfd, **oldfd;
28
 
29
	if(fd < f->nfd)
30
		return 0;
31
	if(fd >= f->nfd+DELTAFD)
32
		return -1;	/* out of range */
33
	/*
34
	 * Unbounded allocation is unwise
35
	 */
36
	if(f->nfd >= 5000){
37
    Exhausted:
38
		print("no free file descriptors\n");
39
		return -1;
40
	}
41
	newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
42
	if(newfd == 0)
43
		goto Exhausted;
44
	oldfd = f->fd;
45
	memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
46
	f->fd = newfd;
47
	free(oldfd);
48
	f->nfd += DELTAFD;
49
	if(fd > f->maxfd){
50
		if(fd/100 > f->maxfd/100)
51
			f->exceed = (fd/100)*100;
52
		f->maxfd = fd;
53
	}
54
	return 1;
55
}
56
 
57
/*
58
 *  this assumes that the fgrp is locked
59
 */
60
int
61
findfreefd(Fgrp *f, int start)
62
{
63
	int fd;
64
 
65
	for(fd=start; fd<f->nfd; fd++)
66
		if(f->fd[fd] == 0)
67
			break;
68
	if(fd >= f->nfd && growfd(f, fd) < 0)
69
		return -1;
70
	return fd;
71
}
72
 
73
int
74
newfd(Chan *c)
75
{
76
	int fd;
77
	Fgrp *f;
78
 
79
	f = up->fgrp;
80
	lock(f);
81
	fd = findfreefd(f, 0);
82
	if(fd < 0){
83
		unlockfgrp(f);
84
		return -1;
85
	}
86
	if(fd > f->maxfd)
87
		f->maxfd = fd;
88
	f->fd[fd] = c;
89
	unlockfgrp(f);
90
	return fd;
91
}
92
 
93
int
94
newfd2(int fd[2], Chan *c[2])
95
{
96
	Fgrp *f;
97
 
98
	f = up->fgrp;
99
	lock(f);
100
	fd[0] = findfreefd(f, 0);
101
	if(fd[0] < 0){
102
		unlockfgrp(f);
103
		return -1;
104
	}
105
	fd[1] = findfreefd(f, fd[0]+1);
106
	if(fd[1] < 0){
107
		unlockfgrp(f);
108
		return -1;
109
	}
110
	if(fd[1] > f->maxfd)
111
		f->maxfd = fd[1];
112
	f->fd[fd[0]] = c[0];
113
	f->fd[fd[1]] = c[1];
114
	unlockfgrp(f);
115
 
116
	return 0;
117
}
118
 
119
Chan*
120
fdtochan(int fd, int mode, int chkmnt, int iref)
121
{
122
	Chan *c;
123
	Fgrp *f;
124
 
125
	c = 0;
126
	f = up->fgrp;
127
 
128
	lock(f);
129
	if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
130
		unlock(f);
131
		error(Ebadfd);
132
	}
133
	if(iref)
134
		incref(c);
135
	unlock(f);
136
 
137
	if(chkmnt && (c->flag&CMSG)) {
138
		if(iref)
139
			cclose(c);
140
		error(Ebadusefd);
141
	}
142
 
143
	if(mode<0 || c->mode==ORDWR)
144
		return c;
145
 
146
	if((mode&OTRUNC) && c->mode==OREAD) {
147
		if(iref)
148
			cclose(c);
149
		error(Ebadusefd);
150
	}
151
 
152
	if((mode&~OTRUNC) != c->mode) {
153
		if(iref)
154
			cclose(c);
155
		error(Ebadusefd);
156
	}
157
 
158
	return c;
159
}
160
 
161
int
162
openmode(ulong o)
163
{
164
	o &= ~(OTRUNC|OCEXEC|ORCLOSE);
165
	if(o > OEXEC)
166
		error(Ebadarg);
167
	if(o == OEXEC)
168
		return OREAD;
169
	return o;
170
}
171
 
172
long
173
sysfd2path(ulong *arg)
174
{
175
	Chan *c;
176
 
177
	validaddr(arg[1], arg[2], 1);
178
 
179
	c = fdtochan(arg[0], -1, 0, 1);
180
	snprint((char*)arg[1], arg[2], "%s", chanpath(c));
181
	cclose(c);
182
	return 0;
183
}
184
 
185
long
186
syspipe(ulong *arg)
187
{
188
	int fd[2];
189
	Chan *c[2];
190
	Dev *d;
191
	static char *datastr[] = {"data", "data1"};
192
 
193
	validaddr(arg[0], sizeof(fd), 1);
194
	validalign(arg[0], sizeof(int));
195
	d = devtab[devno('|', 0)];
196
	c[0] = namec("#|", Atodir, 0, 0);
197
	c[1] = 0;
198
	fd[0] = -1;
199
	fd[1] = -1;
200
 
201
	if(waserror()){
202
		cclose(c[0]);
203
		if(c[1])
204
			cclose(c[1]);
205
		nexterror();
206
	}
207
	c[1] = cclone(c[0]);
208
	if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
209
		error(Egreg);
210
	if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
211
		error(Egreg);
212
	c[0] = d->open(c[0], ORDWR);
213
	c[1] = d->open(c[1], ORDWR);
214
	if(newfd2(fd, c) < 0)
215
		error(Enofd);
216
	poperror();
217
 
218
	((int*)arg[0])[0] = fd[0];
219
	((int*)arg[0])[1] = fd[1];
220
	return 0;
221
}
222
 
223
long
224
sysdup(ulong *arg)
225
{
226
	int fd;
227
	Chan *c, *oc;
228
	Fgrp *f = up->fgrp;
229
 
230
	/*
231
	 * Close after dup'ing, so date > #d/1 works
232
	 */
233
	c = fdtochan(arg[0], -1, 0, 1);
234
	fd = arg[1];
235
	if(fd != -1){
236
		lock(f);
237
		if(fd<0 || growfd(f, fd)<0) {
238
			unlockfgrp(f);
239
			cclose(c);
240
			error(Ebadfd);
241
		}
242
		if(fd > f->maxfd)
243
			f->maxfd = fd;
244
 
245
		oc = f->fd[fd];
246
		f->fd[fd] = c;
247
		unlockfgrp(f);
248
		if(oc)
249
			cclose(oc);
250
	}else{
251
		if(waserror()) {
252
			cclose(c);
253
			nexterror();
254
		}
255
		fd = newfd(c);
256
		if(fd < 0)
257
			error(Enofd);
258
		poperror();
259
	}
260
 
261
	return fd;
262
}
263
 
264
long
265
sysopen(ulong *arg)
266
{
267
	int fd;
268
	Chan *c;
269
 
270
	openmode(arg[1]);	/* error check only */
271
	validaddr(arg[0], 1, 0);
272
	c = namec((char*)arg[0], Aopen, arg[1], 0);
273
	if(waserror()){
274
		cclose(c);
275
		nexterror();
276
	}
277
	fd = newfd(c);
278
	if(fd < 0)
279
		error(Enofd);
280
	poperror();
281
	return fd;
282
}
283
 
284
void
285
fdclose(int fd, int flag)
286
{
287
	int i;
288
	Chan *c;
289
	Fgrp *f = up->fgrp;
290
 
291
	lock(f);
292
	c = f->fd[fd];
293
	if(c == 0){
294
		/* can happen for users with shared fd tables */
295
		unlock(f);
296
		return;
297
	}
298
	if(flag){
299
		if(c==0 || !(c->flag&flag)){
300
			unlock(f);
301
			return;
302
		}
303
	}
304
	f->fd[fd] = 0;
305
	if(fd == f->maxfd)
306
		for(i=fd; --i>=0 && f->fd[i]==0; )
307
			f->maxfd = i;
308
 
309
	unlock(f);
310
	cclose(c);
311
}
312
 
313
long
314
sysclose(ulong *arg)
315
{
316
	fdtochan(arg[0], -1, 0, 0);
317
	fdclose(arg[0], 0);
318
 
319
	return 0;
320
}
321
 
322
long
323
unionread(Chan *c, void *va, long n)
324
{
325
	int i;
326
	long nr;
327
	Mhead *m;
328
	Mount *mount;
329
 
330
	qlock(&c->umqlock);
331
	m = c->umh;
332
	rlock(&m->lock);
333
	mount = m->mount;
334
	/* bring mount in sync with c->uri and c->umc */
335
	for(i = 0; mount != nil && i < c->uri; i++)
336
		mount = mount->next;
337
 
338
	nr = 0;
339
	while(mount != nil){
340
		/* Error causes component of union to be skipped */
341
		if(mount->to && !waserror()){
342
			if(c->umc == nil){
343
				c->umc = cclone(mount->to);
344
				c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
345
			}
346
 
347
			nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
348
			c->umc->offset += nr;
349
			poperror();
350
		}
351
		if(nr > 0)
352
			break;
353
 
354
		/* Advance to next element */
355
		c->uri++;
356
		if(c->umc){
357
			cclose(c->umc);
358
			c->umc = nil;
359
		}
360
		mount = mount->next;
361
	}
362
	runlock(&m->lock);
363
	qunlock(&c->umqlock);
364
	return nr;
365
}
366
 
367
static void
368
unionrewind(Chan *c)
369
{
370
	qlock(&c->umqlock);
371
	c->uri = 0;
372
	if(c->umc){
373
		cclose(c->umc);
374
		c->umc = nil;
375
	}
376
	qunlock(&c->umqlock);
377
}
378
 
379
static int
380
dirfixed(uchar *p, uchar *e, Dir *d)
381
{
382
	int len;
383
 
384
	len = GBIT16(p)+BIT16SZ;
385
	if(p + len > e)
386
		return -1;
387
 
388
	p += BIT16SZ;	/* ignore size */
389
	d->type = devno(GBIT16(p), 1);
390
	p += BIT16SZ;
391
	d->dev = GBIT32(p);
392
	p += BIT32SZ;
393
	d->qid.type = GBIT8(p);
394
	p += BIT8SZ;
395
	d->qid.vers = GBIT32(p);
396
	p += BIT32SZ;
397
	d->qid.path = GBIT64(p);
398
	p += BIT64SZ;
399
	d->mode = GBIT32(p);
400
	p += BIT32SZ;
401
	d->atime = GBIT32(p);
402
	p += BIT32SZ;
403
	d->mtime = GBIT32(p);
404
	p += BIT32SZ;
405
	d->length = GBIT64(p);
406
 
407
	return len;
408
}
409
 
410
static char*
411
dirname(uchar *p, int *n)
412
{
413
	p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
414
		+ BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
415
	*n = GBIT16(p);
416
	return (char*)p+BIT16SZ;
417
}
418
 
419
static long
420
dirsetname(char *name, int len, uchar *p, long n, long maxn)
421
{
422
	char *oname;
423
	int olen;
424
	long nn;
425
 
426
	if(n == BIT16SZ)
427
		return BIT16SZ;
428
 
429
	oname = dirname(p, &olen);
430
 
431
	nn = n+len-olen;
432
	PBIT16(p, nn-BIT16SZ);
433
	if(nn > maxn)
434
		return BIT16SZ;
435
 
436
	if(len != olen)
437
		memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
438
	PBIT16((uchar*)(oname-2), len);
439
	memmove(oname, name, len);
440
	return nn;
441
}
442
 
443
/*
444
 * Mountfix might have caused the fixed results of the directory read
445
 * to overflow the buffer.  Catch the overflow in c->dirrock.
446
 */
447
static void
448
mountrock(Chan *c, uchar *p, uchar **pe)
449
{
450
	uchar *e, *r;
451
	int len, n;
452
 
453
	e = *pe;
454
 
455
	/* find last directory entry */
456
	for(;;){
457
		len = BIT16SZ+GBIT16(p);
458
		if(p+len >= e)
459
			break;
460
		p += len;
461
	}
462
 
463
	/* save it away */
464
	qlock(&c->rockqlock);
465
	if(c->nrock+len > c->mrock){
466
		n = ROUND(c->nrock+len, 1024);
467
		r = smalloc(n);
468
		memmove(r, c->dirrock, c->nrock);
469
		free(c->dirrock);
470
		c->dirrock = r;
471
		c->mrock = n;
472
	}
473
	memmove(c->dirrock+c->nrock, p, len);
474
	c->nrock += len;
475
	qunlock(&c->rockqlock);
476
 
477
	/* drop it */
478
	*pe = p;
479
}
480
 
481
/*
482
 * Satisfy a directory read with the results saved in c->dirrock.
483
 */
484
static int
485
mountrockread(Chan *c, uchar *op, long n, long *nn)
486
{
487
	long dirlen;
488
	uchar *rp, *erp, *ep, *p;
489
 
490
	/* common case */
491
	if(c->nrock == 0)
492
		return 0;
493
 
494
	/* copy out what we can */
495
	qlock(&c->rockqlock);
496
	rp = c->dirrock;
497
	erp = rp+c->nrock;
498
	p = op;
499
	ep = p+n;
500
	while(rp+BIT16SZ <= erp){
501
		dirlen = BIT16SZ+GBIT16(rp);
502
		if(p+dirlen > ep)
503
			break;
504
		memmove(p, rp, dirlen);
505
		p += dirlen;
506
		rp += dirlen;
507
	}
508
 
509
	if(p == op){
510
		qunlock(&c->rockqlock);
511
		return 0;
512
	}
513
 
514
	/* shift the rest */
515
	if(rp != erp)
516
		memmove(c->dirrock, rp, erp-rp);
517
	c->nrock = erp - rp;
518
 
519
	*nn = p - op;
520
	qunlock(&c->rockqlock);
521
	return 1;
522
}
523
 
524
static void
525
mountrewind(Chan *c)
526
{
527
	c->nrock = 0;
528
}
529
 
530
/*
531
 * Rewrite the results of a directory read to reflect current 
532
 * name space bindings and mounts.  Specifically, replace
533
 * directory entries for bind and mount points with the results
534
 * of statting what is mounted there.  Except leave the old names.
535
 */
536
static long
537
mountfix(Chan *c, uchar *op, long n, long maxn)
538
{
539
	char *name;
540
	int nbuf, nname;
541
	Chan *nc;
542
	Mhead *mh;
543
	Mount *m;
544
	uchar *p;
545
	int dirlen, rest;
546
	long l;
547
	uchar *buf, *e;
548
	Dir d;
549
 
550
	p = op;
551
	buf = nil;
552
	nbuf = 0;
553
	for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
554
		dirlen = dirfixed(p, e, &d);
555
		if(dirlen < 0)
556
			break;
557
		nc = nil;
558
		mh = nil;
559
		if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
560
			/*
561
			 * If it's a union directory and the original is
562
			 * in the union, don't rewrite anything.
563
			 */
564
			for(m=mh->mount; m; m=m->next)
565
				if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
566
					goto Norewrite;
567
 
568
			name = dirname(p, &nname);
569
			/*
570
			 * Do the stat but fix the name.  If it fails, leave old entry.
571
			 * BUG: If it fails because there isn't room for the entry,
572
			 * what can we do?  Nothing, really.  Might as well skip it.
573
			 */
574
			if(buf == nil){
575
				buf = smalloc(4096);
576
				nbuf = 4096;
577
			}
578
			if(waserror())
579
				goto Norewrite;
580
			l = devtab[nc->type]->stat(nc, buf, nbuf);
581
			l = dirsetname(name, nname, buf, l, nbuf);
582
			if(l == BIT16SZ)
583
				error("dirsetname");
584
			poperror();
585
 
586
			/*
587
			 * Shift data in buffer to accomodate new entry,
588
			 * possibly overflowing into rock.
589
			 */
590
			rest = e - (p+dirlen);
591
			if(l > dirlen){
592
				while(p+l+rest > op+maxn){
593
					mountrock(c, p, &e);
594
					if(e == p){
595
						dirlen = 0;
596
						goto Norewrite;
597
					}
598
					rest = e - (p+dirlen);
599
				}
600
			}
601
			if(l != dirlen){
602
				memmove(p+l, p+dirlen, rest);
603
				dirlen = l;
604
				e = p+dirlen+rest;
605
			}
606
 
607
			/*
608
			 * Rewrite directory entry.
609
			 */
610
			memmove(p, buf, l);
611
 
612
		    Norewrite:
613
			cclose(nc);
614
			putmhead(mh);
615
		}
616
	}
617
	if(buf)
618
		free(buf);
619
 
620
	if(p != e)
621
		error("oops in rockfix");
622
 
623
	return e-op;
624
}
625
 
626
static long
627
read(ulong *arg, vlong *offp)
628
{
629
	long n, nn, nnn;
630
	uchar *p;
631
	Chan *c;
632
	vlong off;
633
 
634
	n = arg[2];
635
	validaddr(arg[1], n, 1);
636
	p = (void*)arg[1];
637
	c = fdtochan(arg[0], OREAD, 1, 1);
638
 
639
	if(waserror()){
640
		cclose(c);
641
		nexterror();
642
	}
643
 
644
	/*
645
	 * The offset is passed through on directories, normally.
646
	 * Sysseek complains, but pread is used by servers like exportfs,
647
	 * that shouldn't need to worry about this issue.
648
	 *
649
	 * Notice that c->devoffset is the offset that c's dev is seeing.
650
	 * The number of bytes read on this fd (c->offset) may be different
651
	 * due to rewritings in rockfix.
652
	 */
653
	if(offp == nil)	/* use and maintain channel's offset */
654
		off = c->offset;
655
	else
656
		off = *offp;
657
	if(off < 0)
658
		error(Enegoff);
659
 
660
	if(off == 0){	/* rewind to the beginning of the directory */
661
		if(offp == nil){
662
			c->offset = 0;
663
			c->devoffset = 0;
664
		}
665
		mountrewind(c);
666
		unionrewind(c);
667
	}
668
 
669
	if(c->qid.type & QTDIR){
670
		if(mountrockread(c, p, n, &nn)){
671
			/* do nothing: mountrockread filled buffer */
672
		}else if(c->umh)
673
			nn = unionread(c, p, n);
674
		else{
675
			if(off != c->offset)
676
				error(Edirseek);
677
			nn = devtab[c->type]->read(c, p, n, c->devoffset);
678
		}
679
		nnn = mountfix(c, p, nn, n);
680
	}else
681
		nnn = nn = devtab[c->type]->read(c, p, n, off);
682
 
683
	lock(c);
684
	c->devoffset += nn;
685
	c->offset += nnn;
686
	unlock(c);
687
 
688
	poperror();
689
	cclose(c);
690
 
691
	return nnn;
692
}
693
 
694
long
695
sys_read(ulong *arg)
696
{
697
	return read(arg, nil);
698
}
699
 
700
long
701
syspread(ulong *arg)
702
{
703
	vlong v;
704
	va_list list;
705
 
706
	/* use varargs to guarantee alignment of vlong */
707
	va_start(list, arg[2]);
708
	v = va_arg(list, vlong);
709
	va_end(list);
710
 
711
	if(v == ~0ULL)
712
		return read(arg, nil);
713
 
714
	return read(arg, &v);
715
}
716
 
717
static long
718
write(ulong *arg, vlong *offp)
719
{
720
	Chan *c;
721
	long m, n;
722
	vlong off;
723
 
724
	validaddr(arg[1], arg[2], 0);
725
	n = 0;
726
	c = fdtochan(arg[0], OWRITE, 1, 1);
727
	if(waserror()) {
728
		if(offp == nil){
729
			lock(c);
730
			c->offset -= n;
731
			unlock(c);
732
		}
733
		cclose(c);
734
		nexterror();
735
	}
736
 
737
	if(c->qid.type & QTDIR)
738
		error(Eisdir);
739
 
740
	n = arg[2];
741
 
742
	if(offp == nil){	/* use and maintain channel's offset */
743
		lock(c);
744
		off = c->offset;
745
		c->offset += n;
746
		unlock(c);
747
	}else
748
		off = *offp;
749
 
750
	if(off < 0)
751
		error(Enegoff);
752
 
753
	m = devtab[c->type]->write(c, (void*)arg[1], n, off);
754
 
755
	if(offp == nil && m < n){
756
		lock(c);
757
		c->offset -= n - m;
758
		unlock(c);
759
	}
760
 
761
	poperror();
762
	cclose(c);
763
 
764
	return m;
765
}
766
 
767
long
768
sys_write(ulong *arg)
769
{
770
	return write(arg, nil);
771
}
772
 
773
long
774
syspwrite(ulong *arg)
775
{
776
	vlong v;
777
	va_list list;
778
 
779
	/* use varargs to guarantee alignment of vlong */
780
	va_start(list, arg[2]);
781
	v = va_arg(list, vlong);
782
	va_end(list);
783
 
784
	if(v == ~0ULL)
785
		return write(arg, nil);
786
 
787
	return write(arg, &v);
788
}
789
 
790
static void
791
sseek(ulong *arg)
792
{
793
	Chan *c;
794
	uchar buf[sizeof(Dir)+100];
795
	Dir dir;
796
	int n;
797
	vlong off;
798
	union {
799
		vlong v;
800
		ulong u[2];
801
	} o;
802
 
803
	c = fdtochan(arg[1], -1, 1, 1);
804
	if(waserror()){
805
		cclose(c);
806
		nexterror();
807
	}
808
	if(devtab[c->type]->dc == '|')
809
		error(Eisstream);
810
 
811
	off = 0;
812
	o.u[0] = arg[2];
813
	o.u[1] = arg[3];
814
	switch(arg[4]){
815
	case 0:
816
		off = o.v;
817
		if((c->qid.type & QTDIR) && off != 0)
818
			error(Eisdir);
819
		if(off < 0)
820
			error(Enegoff);
821
		c->offset = off;
822
		break;
823
 
824
	case 1:
825
		if(c->qid.type & QTDIR)
826
			error(Eisdir);
827
		lock(c);	/* lock for read/write update */
828
		off = o.v + c->offset;
829
		if(off < 0){
830
			unlock(c);
831
			error(Enegoff);
832
		}
833
		c->offset = off;
834
		unlock(c);
835
		break;
836
 
837
	case 2:
838
		if(c->qid.type & QTDIR)
839
			error(Eisdir);
840
		n = devtab[c->type]->stat(c, buf, sizeof buf);
841
		if(convM2D(buf, n, &dir, nil) == 0)
842
			error("internal error: stat error in seek");
843
		off = dir.length + o.v;
844
		if(off < 0)
845
			error(Enegoff);
846
		c->offset = off;
847
		break;
848
 
849
	default:
850
		error(Ebadarg);
851
	}
852
	*(vlong*)arg[0] = off;
853
	c->uri = 0;
854
	c->dri = 0;
855
	cclose(c);
856
	poperror();
857
}
858
 
859
long
860
sysseek(ulong *arg)
861
{
862
	validaddr(arg[0], sizeof(vlong), 1);
863
	validalign(arg[0], sizeof(vlong));
864
	sseek(arg);
865
	return 0;
866
}
867
 
868
long
869
sysoseek(ulong *arg)
870
{
871
	union {
872
		vlong v;
873
		ulong u[2];
874
	} o;
875
	ulong a[5];
876
 
877
	o.v = (long)arg[1];
878
	a[0] = (ulong)&o.v;
879
	a[1] = arg[0];
880
	a[2] = o.u[0];
881
	a[3] = o.u[1];
882
	a[4] = arg[2];
883
	sseek(a);
884
	return o.v;
885
}
886
 
887
void
888
validstat(uchar *s, int n)
889
{
890
	int m;
891
	char buf[64];
892
 
893
	if(statcheck(s, n) < 0)
894
		error(Ebadstat);
895
	/* verify that name entry is acceptable */
896
	s += STATFIXLEN - 4*BIT16SZ;	/* location of first string */
897
	/*
898
	 * s now points at count for first string.
899
	 * if it's too long, let the server decide; this is
900
	 * only for his protection anyway. otherwise
901
	 * we'd have to allocate and waserror.
902
	 */
903
	m = GBIT16(s);
904
	s += BIT16SZ;
905
	if(m+1 > sizeof buf)
906
		return;
907
	memmove(buf, s, m);
908
	buf[m] = '\0';
909
	/* name could be '/' */
910
	if(strcmp(buf, "/") != 0)
911
		validname(buf, 0);
912
}
913
 
914
static char*
915
pathlast(Path *p)
916
{
917
	char *s;
918
 
919
	if(p == nil)
920
		return nil;
921
	if(p->len == 0)
922
		return nil;
923
	s = strrchr(p->s, '/');
924
	if(s)
925
		return s+1;
926
	return p->s;
927
}
928
 
929
long
930
sysfstat(ulong *arg)
931
{
932
	Chan *c;
933
	uint l;
934
 
935
	l = arg[2];
936
	validaddr(arg[1], l, 1);
937
	c = fdtochan(arg[0], -1, 0, 1);
938
	if(waserror()) {
939
		cclose(c);
940
		nexterror();
941
	}
942
	l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
943
	poperror();
944
	cclose(c);
945
	return l;
946
}
947
 
948
long
949
sysstat(ulong *arg)
950
{
951
	char *name;
952
	Chan *c;
953
	uint l;
954
 
955
	l = arg[2];
956
	validaddr(arg[1], l, 1);
957
	validaddr(arg[0], 1, 0);
958
	c = namec((char*)arg[0], Aaccess, 0, 0);
959
	if(waserror()){
960
		cclose(c);
961
		nexterror();
962
	}
963
	l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
964
	name = pathlast(c->path);
965
	if(name)
966
		l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
967
 
968
	poperror();
969
	cclose(c);
970
	return l;
971
}
972
 
973
long
974
syschdir(ulong *arg)
975
{
976
	Chan *c;
977
 
978
	validaddr(arg[0], 1, 0);
979
 
980
	c = namec((char*)arg[0], Atodir, 0, 0);
981
	cclose(up->dot);
982
	up->dot = c;
983
	return 0;
984
}
985
 
986
long
987
bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
988
{
989
	int ret;
990
	Chan *c0, *c1, *ac, *bc;
991
	struct{
992
		Chan	*chan;
993
		Chan	*authchan;
994
		char	*spec;
995
		int	flags;
996
	}bogus;
997
 
998
	if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
999
		error(Ebadarg);
1000
 
1001
	if(ismount){
1002
		validaddr((ulong)spec, 1, 0);
1003
		spec = validnamedup(spec, 1);
1004
		if(waserror()){
1005
			free(spec);
1006
			nexterror();
1007
		}
1008
 
1009
		if(up->pgrp->noattach)
1010
			error(Enoattach);
1011
 
1012
		ac = nil;
1013
		bc = fdtochan(fd, ORDWR, 0, 1);
1014
		if(waserror()) {
1015
			if(ac)
1016
				cclose(ac);
1017
			cclose(bc);
1018
			nexterror();
1019
		}
1020
 
1021
		if(afd >= 0)
1022
			ac = fdtochan(afd, ORDWR, 0, 1);
1023
 
1024
		bogus.flags = flag & MCACHE;
1025
		bogus.chan = bc;
1026
		bogus.authchan = ac;
1027
		bogus.spec = spec;
1028
		ret = devno('M', 0);
1029
		c0 = devtab[ret]->attach((char*)&bogus);
1030
		poperror();	/* ac bc */
1031
		if(ac)
1032
			cclose(ac);
1033
		cclose(bc);
1034
	}else{
1035
		spec = 0;
1036
		validaddr((ulong)arg0, 1, 0);
1037
		c0 = namec(arg0, Abind, 0, 0);
1038
	}
1039
 
1040
	if(waserror()){
1041
		cclose(c0);
1042
		nexterror();
1043
	}
1044
 
1045
	validaddr((ulong)arg1, 1, 0);
1046
	c1 = namec(arg1, Amount, 0, 0);
1047
	if(waserror()){
1048
		cclose(c1);
1049
		nexterror();
1050
	}
1051
 
1052
	ret = cmount(&c0, c1, flag, spec);
1053
 
1054
	poperror();
1055
	cclose(c1);
1056
	poperror();
1057
	cclose(c0);
1058
	if(ismount){
1059
		fdclose(fd, 0);
1060
		poperror();
1061
		free(spec);
1062
	}
1063
	return ret;
1064
}
1065
 
1066
long
1067
sysbind(ulong *arg)
1068
{
1069
	return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
1070
}
1071
 
1072
long
1073
sysmount(ulong *arg)
1074
{
1075
	return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
1076
}
1077
 
1078
long
1079
sys_mount(ulong *arg)
1080
{
1081
	return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
1082
}
1083
 
1084
long
1085
sysunmount(ulong *arg)
1086
{
1087
	Chan *cmount, *cmounted;
1088
 
1089
	cmounted = 0;
1090
 
1091
	validaddr(arg[1], 1, 0);
1092
	cmount = namec((char *)arg[1], Amount, 0, 0);
1093
	if(waserror()) {
1094
		cclose(cmount);
1095
		if(cmounted)
1096
			cclose(cmounted);
1097
		nexterror();
1098
	}
1099
 
1100
	if(arg[0]) {
1101
		/*
1102
		 * This has to be namec(..., Aopen, ...) because
1103
		 * if arg[0] is something like /srv/cs or /fd/0,
1104
		 * opening it is the only way to get at the real
1105
		 * Chan underneath.
1106
		 */
1107
		validaddr(arg[0], 1, 0);
1108
		cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
1109
	}
1110
	cunmount(cmount, cmounted);
1111
	poperror();
1112
	cclose(cmount);
1113
	if(cmounted)
1114
		cclose(cmounted);
1115
	return 0;
1116
}
1117
 
1118
long
1119
syscreate(ulong *arg)
1120
{
1121
	int fd;
1122
	Chan *c;
1123
 
1124
	openmode(arg[1]&~OEXCL);	/* error check only; OEXCL okay here */
1125
	validaddr(arg[0], 1, 0);
1126
	c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
1127
	if(waserror()) {
1128
		cclose(c);
1129
		nexterror();
1130
	}
1131
	fd = newfd(c);
1132
	if(fd < 0)
1133
		error(Enofd);
1134
	poperror();
1135
	return fd;
1136
}
1137
 
1138
long
1139
sysremove(ulong *arg)
1140
{
1141
	Chan *c;
1142
 
1143
	validaddr(arg[0], 1, 0);
1144
	c = namec((char*)arg[0], Aremove, 0, 0);
1145
	/*
1146
	 * Removing mount points is disallowed to avoid surprises
1147
	 * (which should be removed: the mount point or the mounted Chan?).
1148
	 */
1149
	if(c->ismtpt){
1150
		cclose(c);
1151
		error(Eismtpt);
1152
	}
1153
	if(waserror()){
1154
		c->type = 0;	/* see below */
1155
		cclose(c);
1156
		nexterror();
1157
	}
1158
	devtab[c->type]->remove(c);
1159
	/*
1160
	 * Remove clunks the fid, but we need to recover the Chan
1161
	 * so fake it up.  rootclose() is known to be a nop.
1162
	 */
1163
	c->type = 0;
1164
	poperror();
1165
	cclose(c);
1166
	return 0;
1167
}
1168
 
1169
static long
1170
wstat(Chan *c, uchar *d, int nd)
1171
{
1172
	long l;
1173
	int namelen;
1174
 
1175
	if(waserror()){
1176
		cclose(c);
1177
		nexterror();
1178
	}
1179
	if(c->ismtpt){
1180
		/*
1181
		 * Renaming mount points is disallowed to avoid surprises
1182
		 * (which should be renamed? the mount point or the mounted Chan?).
1183
		 */
1184
		dirname(d, &namelen);
1185
		if(namelen)
1186
			nameerror(chanpath(c), Eismtpt);
1187
	}
1188
	l = devtab[c->type]->wstat(c, d, nd);
1189
	poperror();
1190
	cclose(c);
1191
	return l;
1192
}
1193
 
1194
long
1195
syswstat(ulong *arg)
1196
{
1197
	Chan *c;
1198
	uint l;
1199
 
1200
	l = arg[2];
1201
	validaddr(arg[1], l, 0);
1202
	validstat((uchar*)arg[1], l);
1203
	validaddr(arg[0], 1, 0);
1204
	c = namec((char*)arg[0], Aaccess, 0, 0);
1205
	return wstat(c, (uchar*)arg[1], l);
1206
}
1207
 
1208
long
1209
sysfwstat(ulong *arg)
1210
{
1211
	Chan *c;
1212
	uint l;
1213
 
1214
	l = arg[2];
1215
	validaddr(arg[1], l, 0);
1216
	validstat((uchar*)arg[1], l);
1217
	c = fdtochan(arg[0], -1, 1, 1);
1218
	return wstat(c, (uchar*)arg[1], l);
1219
}
1220
 
1221
static void
1222
packoldstat(uchar *buf, Dir *d)
1223
{
1224
	uchar *p;
1225
	ulong q;
1226
 
1227
	/* lay down old stat buffer - grotty code but it's temporary */
1228
	p = buf;
1229
	strncpy((char*)p, d->name, 28);
1230
	p += 28;
1231
	strncpy((char*)p, d->uid, 28);
1232
	p += 28;
1233
	strncpy((char*)p, d->gid, 28);
1234
	p += 28;
1235
	q = d->qid.path & ~DMDIR;	/* make sure doesn't accidentally look like directory */
1236
	if(d->qid.type & QTDIR)	/* this is the real test of a new directory */
1237
		q |= DMDIR;
1238
	PBIT32(p, q);
1239
	p += BIT32SZ;
1240
	PBIT32(p, d->qid.vers);
1241
	p += BIT32SZ;
1242
	PBIT32(p, d->mode);
1243
	p += BIT32SZ;
1244
	PBIT32(p, d->atime);
1245
	p += BIT32SZ;
1246
	PBIT32(p, d->mtime);
1247
	p += BIT32SZ;
1248
	PBIT64(p, d->length);
1249
	p += BIT64SZ;
1250
	PBIT16(p, d->type);
1251
	p += BIT16SZ;
1252
	PBIT16(p, d->dev);
1253
}
1254
 
1255
long
1256
sys_stat(ulong *arg)
1257
{
1258
	Chan *c;
1259
	uint l;
1260
	uchar buf[128];	/* old DIRLEN plus a little should be plenty */
1261
	char strs[128], *name;
1262
	Dir d;
1263
	char old[] = "old stat system call - recompile";
1264
 
1265
	validaddr(arg[1], 116, 1);
1266
	validaddr(arg[0], 1, 0);
1267
	c = namec((char*)arg[0], Aaccess, 0, 0);
1268
	if(waserror()){
1269
		cclose(c);
1270
		nexterror();
1271
	}
1272
	l = devtab[c->type]->stat(c, buf, sizeof buf);
1273
	/* buf contains a new stat buf; convert to old. yuck. */
1274
	if(l <= BIT16SZ)	/* buffer too small; time to face reality */
1275
		error(old);
1276
	name = pathlast(c->path);
1277
	if(name)
1278
		l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1279
	l = convM2D(buf, l, &d, strs);
1280
	if(l == 0)
1281
		error(old);
1282
	packoldstat((uchar*)arg[1], &d);
1283
 
1284
	poperror();
1285
	cclose(c);
1286
	return 0;
1287
}
1288
 
1289
long
1290
sys_fstat(ulong *arg)
1291
{
1292
	Chan *c;
1293
	char *name;
1294
	uint l;
1295
	uchar buf[128];	/* old DIRLEN plus a little should be plenty */
1296
	char strs[128];
1297
	Dir d;
1298
	char old[] = "old fstat system call - recompile";
1299
 
1300
	validaddr(arg[1], 116, 1);
1301
	c = fdtochan(arg[0], -1, 0, 1);
1302
	if(waserror()){
1303
		cclose(c);
1304
		nexterror();
1305
	}
1306
	l = devtab[c->type]->stat(c, buf, sizeof buf);
1307
	/* buf contains a new stat buf; convert to old. yuck. */
1308
	if(l <= BIT16SZ)	/* buffer too small; time to face reality */
1309
		error(old);
1310
	name = pathlast(c->path);
1311
	if(name)
1312
		l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1313
	l = convM2D(buf, l, &d, strs);
1314
	if(l == 0)
1315
		error(old);
1316
	packoldstat((uchar*)arg[1], &d);
1317
 
1318
	poperror();
1319
	cclose(c);
1320
	return 0;
1321
}
1322
 
1323
long
1324
sys_wstat(ulong *)
1325
{
1326
	error("old wstat system call - recompile");
1327
	return -1;
1328
}
1329
 
1330
long
1331
sys_fwstat(ulong *)
1332
{
1333
	error("old fwstat system call - recompile");
1334
	return -1;
1335
}