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