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 if(c->qid.type & QTDIR || offp == nil){
684 lock(c);
685 c->devoffset += nn;
686 c->offset += nnn;
687 unlock(c);
688 }
689
690 poperror();
691 cclose(c);
692
693 return nnn;
694 }
695
696 long
sys_read(ulong * arg)697 sys_read(ulong *arg)
698 {
699 return read(arg, nil);
700 }
701
702 long
syspread(ulong * arg)703 syspread(ulong *arg)
704 {
705 vlong v;
706 va_list list;
707
708 /* use varargs to guarantee alignment of vlong */
709 va_start(list, arg[2]);
710 v = va_arg(list, vlong);
711 va_end(list);
712
713 if(v == ~0ULL)
714 return read(arg, nil);
715
716 return read(arg, &v);
717 }
718
719 static long
write(ulong * arg,vlong * offp)720 write(ulong *arg, vlong *offp)
721 {
722 Chan *c;
723 long m, n;
724 vlong off;
725
726 validaddr(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);
732 c->offset -= n;
733 unlock(c);
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);
746 off = c->offset;
747 c->offset += n;
748 unlock(c);
749 }else
750 off = *offp;
751
752 if(off < 0)
753 error(Enegoff);
754
755 m = devtab[c->type]->write(c, (void*)arg[1], n, off);
756
757 if(offp == nil && m < n){
758 lock(c);
759 c->offset -= n - m;
760 unlock(c);
761 }
762
763 poperror();
764 cclose(c);
765
766 return m;
767 }
768
769 long
sys_write(ulong * arg)770 sys_write(ulong *arg)
771 {
772 return write(arg, nil);
773 }
774
775 long
syspwrite(ulong * arg)776 syspwrite(ulong *arg)
777 {
778 vlong v;
779 va_list list;
780
781 /* use varargs to guarantee alignment of vlong */
782 va_start(list, arg[2]);
783 v = va_arg(list, vlong);
784 va_end(list);
785
786 if(v == ~0ULL)
787 return write(arg, nil);
788
789 return write(arg, &v);
790 }
791
792 static void
sseek(ulong * arg)793 sseek(ulong *arg)
794 {
795 Chan *c;
796 uchar buf[sizeof(Dir)+100];
797 Dir dir;
798 int n;
799 vlong off;
800 union {
801 vlong v;
802 ulong u[2];
803 } o;
804
805 c = fdtochan(arg[1], -1, 1, 1);
806 if(waserror()){
807 cclose(c);
808 nexterror();
809 }
810 if(devtab[c->type]->dc == '|')
811 error(Eisstream);
812
813 off = 0;
814 o.u[0] = arg[2];
815 o.u[1] = arg[3];
816 switch(arg[4]){
817 case 0:
818 off = o.v;
819 if((c->qid.type & QTDIR) && off != 0)
820 error(Eisdir);
821 if(off < 0)
822 error(Enegoff);
823 c->offset = off;
824 break;
825
826 case 1:
827 if(c->qid.type & QTDIR)
828 error(Eisdir);
829 lock(c); /* lock for read/write update */
830 off = o.v + c->offset;
831 if(off < 0){
832 unlock(c);
833 error(Enegoff);
834 }
835 c->offset = off;
836 unlock(c);
837 break;
838
839 case 2:
840 if(c->qid.type & QTDIR)
841 error(Eisdir);
842 n = devtab[c->type]->stat(c, buf, sizeof buf);
843 if(convM2D(buf, n, &dir, nil) == 0)
844 error("internal error: stat error in seek");
845 off = dir.length + o.v;
846 if(off < 0)
847 error(Enegoff);
848 c->offset = off;
849 break;
850
851 default:
852 error(Ebadarg);
853 }
854 *(vlong*)arg[0] = off;
855 c->uri = 0;
856 c->dri = 0;
857 cclose(c);
858 poperror();
859 }
860
861 long
sysseek(ulong * arg)862 sysseek(ulong *arg)
863 {
864 validaddr(arg[0], sizeof(vlong), 1);
865 validalign(arg[0], sizeof(vlong));
866 sseek(arg);
867 return 0;
868 }
869
870 long
sysoseek(ulong * arg)871 sysoseek(ulong *arg)
872 {
873 union {
874 vlong v;
875 ulong u[2];
876 } o;
877 ulong a[5];
878
879 o.v = (long)arg[1];
880 a[0] = (ulong)&o.v;
881 a[1] = arg[0];
882 a[2] = o.u[0];
883 a[3] = o.u[1];
884 a[4] = arg[2];
885 sseek(a);
886 return o.v;
887 }
888
889 void
validstat(uchar * s,int n)890 validstat(uchar *s, int n)
891 {
892 int m;
893 char buf[64];
894
895 if(statcheck(s, n) < 0)
896 error(Ebadstat);
897 /* verify that name entry is acceptable */
898 s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
899 /*
900 * s now points at count for first string.
901 * if it's too long, let the server decide; this is
902 * only for his protection anyway. otherwise
903 * we'd have to allocate and waserror.
904 */
905 m = GBIT16(s);
906 s += BIT16SZ;
907 if(m+1 > sizeof buf)
908 return;
909 memmove(buf, s, m);
910 buf[m] = '\0';
911 /* name could be '/' */
912 if(strcmp(buf, "/") != 0)
913 validname(buf, 0);
914 }
915
916 static char*
pathlast(Path * p)917 pathlast(Path *p)
918 {
919 char *s;
920
921 if(p == nil)
922 return nil;
923 if(p->len == 0)
924 return nil;
925 s = strrchr(p->s, '/');
926 if(s)
927 return s+1;
928 return p->s;
929 }
930
931 long
sysfstat(ulong * arg)932 sysfstat(ulong *arg)
933 {
934 Chan *c;
935 uint l;
936
937 l = arg[2];
938 validaddr(arg[1], l, 1);
939 c = fdtochan(arg[0], -1, 0, 1);
940 if(waserror()) {
941 cclose(c);
942 nexterror();
943 }
944 l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
945 poperror();
946 cclose(c);
947 return l;
948 }
949
950 long
sysstat(ulong * arg)951 sysstat(ulong *arg)
952 {
953 char *name;
954 Chan *c;
955 uint l;
956
957 l = arg[2];
958 validaddr(arg[1], l, 1);
959 validaddr(arg[0], 1, 0);
960 c = namec((char*)arg[0], Aaccess, 0, 0);
961 if(waserror()){
962 cclose(c);
963 nexterror();
964 }
965 l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
966 name = pathlast(c->path);
967 if(name)
968 l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
969
970 poperror();
971 cclose(c);
972 return l;
973 }
974
975 long
syschdir(ulong * arg)976 syschdir(ulong *arg)
977 {
978 Chan *c;
979
980 validaddr(arg[0], 1, 0);
981
982 c = namec((char*)arg[0], Atodir, 0, 0);
983 cclose(up->dot);
984 up->dot = c;
985 return 0;
986 }
987
988 long
bindmount(int ismount,int fd,int afd,char * arg0,char * arg1,ulong flag,char * spec)989 bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
990 {
991 int ret;
992 Chan *c0, *c1, *ac, *bc;
993 struct{
994 Chan *chan;
995 Chan *authchan;
996 char *spec;
997 int flags;
998 }bogus;
999
1000 if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
1001 error(Ebadarg);
1002
1003 if(ismount){
1004 validaddr((ulong)spec, 1, 0);
1005 spec = validnamedup(spec, 1);
1006 if(waserror()){
1007 free(spec);
1008 nexterror();
1009 }
1010
1011 if(up->pgrp->noattach)
1012 error(Enoattach);
1013
1014 ac = nil;
1015 bc = fdtochan(fd, ORDWR, 0, 1);
1016 if(waserror()) {
1017 if(ac)
1018 cclose(ac);
1019 cclose(bc);
1020 nexterror();
1021 }
1022
1023 if(afd >= 0)
1024 ac = fdtochan(afd, ORDWR, 0, 1);
1025
1026 bogus.flags = flag & MCACHE;
1027 bogus.chan = bc;
1028 bogus.authchan = ac;
1029 bogus.spec = spec;
1030 ret = devno('M', 0);
1031 c0 = devtab[ret]->attach((char*)&bogus);
1032 poperror(); /* ac bc */
1033 if(ac)
1034 cclose(ac);
1035 cclose(bc);
1036 }else{
1037 spec = 0;
1038 validaddr((ulong)arg0, 1, 0);
1039 c0 = namec(arg0, Abind, 0, 0);
1040 }
1041
1042 if(waserror()){
1043 cclose(c0);
1044 nexterror();
1045 }
1046
1047 validaddr((ulong)arg1, 1, 0);
1048 c1 = namec(arg1, Amount, 0, 0);
1049 if(waserror()){
1050 cclose(c1);
1051 nexterror();
1052 }
1053
1054 ret = cmount(&c0, c1, flag, spec);
1055
1056 poperror();
1057 cclose(c1);
1058 poperror();
1059 cclose(c0);
1060 if(ismount){
1061 fdclose(fd, 0);
1062 poperror();
1063 free(spec);
1064 }
1065 return ret;
1066 }
1067
1068 long
sysbind(ulong * arg)1069 sysbind(ulong *arg)
1070 {
1071 return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
1072 }
1073
1074 long
sysmount(ulong * arg)1075 sysmount(ulong *arg)
1076 {
1077 return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
1078 }
1079
1080 long
sys_mount(ulong * arg)1081 sys_mount(ulong *arg)
1082 {
1083 return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
1084 }
1085
1086 long
sysunmount(ulong * arg)1087 sysunmount(ulong *arg)
1088 {
1089 Chan *cmount, *cmounted;
1090
1091 cmounted = 0;
1092
1093 validaddr(arg[1], 1, 0);
1094 cmount = namec((char *)arg[1], Amount, 0, 0);
1095 if(waserror()) {
1096 cclose(cmount);
1097 if(cmounted)
1098 cclose(cmounted);
1099 nexterror();
1100 }
1101
1102 if(arg[0]) {
1103 /*
1104 * This has to be namec(..., Aopen, ...) because
1105 * if arg[0] is something like /srv/cs or /fd/0,
1106 * opening it is the only way to get at the real
1107 * Chan underneath.
1108 */
1109 validaddr(arg[0], 1, 0);
1110 cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
1111 }
1112 cunmount(cmount, cmounted);
1113 poperror();
1114 cclose(cmount);
1115 if(cmounted)
1116 cclose(cmounted);
1117 return 0;
1118 }
1119
1120 long
syscreate(ulong * arg)1121 syscreate(ulong *arg)
1122 {
1123 int fd;
1124 Chan *c;
1125
1126 openmode(arg[1]&~OEXCL); /* error check only; OEXCL okay here */
1127 validaddr(arg[0], 1, 0);
1128 c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
1129 if(waserror()) {
1130 cclose(c);
1131 nexterror();
1132 }
1133 fd = newfd(c);
1134 if(fd < 0)
1135 error(Enofd);
1136 poperror();
1137 return fd;
1138 }
1139
1140 long
sysremove(ulong * arg)1141 sysremove(ulong *arg)
1142 {
1143 Chan *c;
1144
1145 validaddr(arg[0], 1, 0);
1146 c = namec((char*)arg[0], Aremove, 0, 0);
1147 /*
1148 * Removing mount points is disallowed to avoid surprises
1149 * (which should be removed: the mount point or the mounted Chan?).
1150 */
1151 if(c->ismtpt){
1152 cclose(c);
1153 error(Eismtpt);
1154 }
1155 if(waserror()){
1156 c->type = 0; /* see below */
1157 cclose(c);
1158 nexterror();
1159 }
1160 devtab[c->type]->remove(c);
1161 /*
1162 * Remove clunks the fid, but we need to recover the Chan
1163 * so fake it up. rootclose() is known to be a nop.
1164 */
1165 c->type = 0;
1166 poperror();
1167 cclose(c);
1168 return 0;
1169 }
1170
1171 static long
wstat(Chan * c,uchar * d,int nd)1172 wstat(Chan *c, uchar *d, int nd)
1173 {
1174 long l;
1175 int namelen;
1176
1177 if(waserror()){
1178 cclose(c);
1179 nexterror();
1180 }
1181 if(c->ismtpt){
1182 /*
1183 * Renaming mount points is disallowed to avoid surprises
1184 * (which should be renamed? the mount point or the mounted Chan?).
1185 */
1186 dirname(d, &namelen);
1187 if(namelen)
1188 nameerror(chanpath(c), Eismtpt);
1189 }
1190 l = devtab[c->type]->wstat(c, d, nd);
1191 poperror();
1192 cclose(c);
1193 return l;
1194 }
1195
1196 long
syswstat(ulong * arg)1197 syswstat(ulong *arg)
1198 {
1199 Chan *c;
1200 uint l;
1201
1202 l = arg[2];
1203 validaddr(arg[1], l, 0);
1204 validstat((uchar*)arg[1], l);
1205 validaddr(arg[0], 1, 0);
1206 c = namec((char*)arg[0], Aaccess, 0, 0);
1207 return wstat(c, (uchar*)arg[1], l);
1208 }
1209
1210 long
sysfwstat(ulong * arg)1211 sysfwstat(ulong *arg)
1212 {
1213 Chan *c;
1214 uint l;
1215
1216 l = arg[2];
1217 validaddr(arg[1], l, 0);
1218 validstat((uchar*)arg[1], l);
1219 c = fdtochan(arg[0], -1, 1, 1);
1220 return wstat(c, (uchar*)arg[1], l);
1221 }
1222
1223 static void
packoldstat(uchar * buf,Dir * d)1224 packoldstat(uchar *buf, Dir *d)
1225 {
1226 uchar *p;
1227 ulong q;
1228
1229 /* lay down old stat buffer - grotty code but it's temporary */
1230 p = buf;
1231 strncpy((char*)p, d->name, 28);
1232 p += 28;
1233 strncpy((char*)p, d->uid, 28);
1234 p += 28;
1235 strncpy((char*)p, d->gid, 28);
1236 p += 28;
1237 q = d->qid.path & ~(uvlong)DMDIR; /* make sure doesn't accidentally look like directory */
1238 if(d->qid.type & QTDIR) /* this is the real test of a new directory */
1239 q |= DMDIR;
1240 PBIT32(p, q);
1241 p += BIT32SZ;
1242 PBIT32(p, d->qid.vers);
1243 p += BIT32SZ;
1244 PBIT32(p, d->mode);
1245 p += BIT32SZ;
1246 PBIT32(p, d->atime);
1247 p += BIT32SZ;
1248 PBIT32(p, d->mtime);
1249 p += BIT32SZ;
1250 PBIT64(p, d->length);
1251 p += BIT64SZ;
1252 PBIT16(p, d->type);
1253 p += BIT16SZ;
1254 PBIT16(p, d->dev);
1255 }
1256
1257 long
sys_stat(ulong * arg)1258 sys_stat(ulong *arg)
1259 {
1260 Chan *c;
1261 uint l;
1262 uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1263 char strs[128], *name;
1264 Dir d;
1265 char old[] = "old stat system call - recompile";
1266
1267 validaddr(arg[1], 116, 1);
1268 validaddr(arg[0], 1, 0);
1269 c = namec((char*)arg[0], Aaccess, 0, 0);
1270 if(waserror()){
1271 cclose(c);
1272 nexterror();
1273 }
1274 l = devtab[c->type]->stat(c, buf, sizeof buf);
1275 /* buf contains a new stat buf; convert to old. yuck. */
1276 if(l <= BIT16SZ) /* buffer too small; time to face reality */
1277 error(old);
1278 name = pathlast(c->path);
1279 if(name)
1280 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1281 l = convM2D(buf, l, &d, strs);
1282 if(l == 0)
1283 error(old);
1284 packoldstat((uchar*)arg[1], &d);
1285
1286 poperror();
1287 cclose(c);
1288 return 0;
1289 }
1290
1291 long
sys_fstat(ulong * arg)1292 sys_fstat(ulong *arg)
1293 {
1294 Chan *c;
1295 char *name;
1296 uint l;
1297 uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1298 char strs[128];
1299 Dir d;
1300 char old[] = "old fstat system call - recompile";
1301
1302 validaddr(arg[1], 116, 1);
1303 c = fdtochan(arg[0], -1, 0, 1);
1304 if(waserror()){
1305 cclose(c);
1306 nexterror();
1307 }
1308 l = devtab[c->type]->stat(c, buf, sizeof buf);
1309 /* buf contains a new stat buf; convert to old. yuck. */
1310 if(l <= BIT16SZ) /* buffer too small; time to face reality */
1311 error(old);
1312 name = pathlast(c->path);
1313 if(name)
1314 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1315 l = convM2D(buf, l, &d, strs);
1316 if(l == 0)
1317 error(old);
1318 packoldstat((uchar*)arg[1], &d);
1319
1320 poperror();
1321 cclose(c);
1322 return 0;
1323 }
1324
1325 long
sys_wstat(ulong *)1326 sys_wstat(ulong *)
1327 {
1328 error("old wstat system call - recompile");
1329 return -1;
1330 }
1331
1332 long
sys_fwstat(ulong *)1333 sys_fwstat(ulong *)
1334 {
1335 error("old fwstat system call - recompile");
1336 return -1;
1337 }
1338