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