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