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 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 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 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 = 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
openmode(ulong o)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
sysfd2path(ulong * arg)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
syspipe(ulong * arg)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
sysdup(ulong * arg)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
sysopen(ulong * arg)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
fdclose(int fd,int flag)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
sysclose(ulong * arg)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
unionread(Chan * c,void * va,long n)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
unionrewind(Chan * c)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
dirfixed(uchar * p,uchar * e,Dir * d)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*
dirname(uchar * p,int * n)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
dirsetname(char * name,int len,uchar * p,long n,long maxn)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
mountrock(Chan * c,uchar * p,uchar ** pe)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
mountrockread(Chan * c,uchar * op,long n,long * nn)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
mountrewind(Chan * c)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
mountfix(Chan * c,uchar * op,long n,long maxn)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
read(ulong * arg,vlong * offp)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
sys_read(ulong * arg)695 sys_read(ulong *arg)
696 {
697 return read(arg, nil);
698 }
699
700 long
syspread(ulong * arg)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
write(ulong * arg,vlong * offp)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
sys_write(ulong * arg)768 sys_write(ulong *arg)
769 {
770 return write(arg, nil);
771 }
772
773 long
syspwrite(ulong * arg)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
sseek(ulong * arg)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
sysseek(ulong * arg)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
sysoseek(ulong * arg)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
validstat(uchar * s,int n)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*
pathlast(Path * p)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
sysfstat(ulong * arg)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
sysstat(ulong * arg)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
syschdir(ulong * arg)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
bindmount(int ismount,int fd,int afd,char * arg0,char * arg1,ulong flag,char * spec)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
sysbind(ulong * arg)1067 sysbind(ulong *arg)
1068 {
1069 return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
1070 }
1071
1072 long
sysmount(ulong * arg)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
sys_mount(ulong * arg)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
sysunmount(ulong * arg)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
syscreate(ulong * arg)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
sysremove(ulong * arg)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
wstat(Chan * c,uchar * d,int nd)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
syswstat(ulong * arg)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
sysfwstat(ulong * arg)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
packoldstat(uchar * buf,Dir * d)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
sys_stat(ulong * arg)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
sys_fstat(ulong * arg)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
sys_wstat(ulong *)1324 sys_wstat(ulong *)
1325 {
1326 error("old wstat system call - recompile");
1327 return -1;
1328 }
1329
1330 long
sys_fwstat(ulong *)1331 sys_fwstat(ulong *)
1332 {
1333 error("old fwstat system call - recompile");
1334 return -1;
1335 }
1336