1 #include "u.h"
2 #include "lib.h"
3 #include "dat.h"
4 #include "fns.h"
5 #include "error.h"
6
7 Chan*
fdtochan(int fd,int mode,int chkmnt,int iref)8 fdtochan(int fd, int mode, int chkmnt, int iref)
9 {
10 Fgrp *f;
11 Chan *c;
12
13 c = 0;
14 f = up->fgrp;
15
16 lock(&f->ref.lk);
17 if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
18 unlock(&f->ref.lk);
19 error(Ebadfd);
20 }
21 if(iref)
22 refinc(&c->ref);
23 unlock(&f->ref.lk);
24
25 if(chkmnt && (c->flag&CMSG))
26 goto bad;
27 if(mode<0 || c->mode==ORDWR)
28 return c;
29 if((mode&OTRUNC) && c->mode==OREAD)
30 goto bad;
31 if((mode&~OTRUNC) != c->mode)
32 goto bad;
33 return c;
34 bad:
35 if(iref)
36 cclose(c);
37 error(Ebadusefd);
38 return nil; /* shut up compiler */
39 }
40
41 static void
fdclose(int fd,int flag)42 fdclose(int fd, int flag)
43 {
44 int i;
45 Chan *c;
46 Fgrp *f;
47
48 f = up->fgrp;
49
50 lock(&f->ref.lk);
51 c = f->fd[fd];
52 if(c == 0) {
53 unlock(&f->ref.lk);
54 return;
55 }
56 if(flag) {
57 if(c==0 || !(c->flag&flag)) {
58 unlock(&f->ref.lk);
59 return;
60 }
61 }
62 f->fd[fd] = 0;
63 if(fd == f->maxfd)
64 for(i=fd; --i>=0 && f->fd[i]==0; )
65 f->maxfd = i;
66
67 unlock(&f->ref.lk);
68 cclose(c);
69 }
70
71 static int
newfd(Chan * c)72 newfd(Chan *c)
73 {
74 int i;
75 Fgrp *f;
76
77 f = up->fgrp;
78 lock(&f->ref.lk);
79 for(i=0; i<NFD; i++)
80 if(f->fd[i] == 0){
81 if(i > f->maxfd)
82 f->maxfd = i;
83 f->fd[i] = c;
84 unlock(&f->ref.lk);
85 return i;
86 }
87 unlock(&f->ref.lk);
88 error("no file descriptors");
89 return 0;
90 }
91
92 int
sysclose(int fd)93 sysclose(int fd)
94 {
95 if(waserror())
96 return -1;
97
98 fdtochan(fd, -1, 0, 0);
99 fdclose(fd, 0);
100 poperror();
101 return 0;
102 }
103
104 int
syscreate(char * path,int mode,ulong perm)105 syscreate(char *path, int mode, ulong perm)
106 {
107 int fd;
108 Chan *c = 0;
109
110 if(waserror()) {
111 cclose(c);
112 return -1;
113 }
114
115 openmode(mode); /* error check only */
116 c = namec(path, Acreate, mode, perm);
117 fd = newfd((Chan*)c);
118 poperror();
119 return fd;
120 }
121
122 int
sysdup(int old,int new)123 sysdup(int old, int new)
124 {
125 Chan *oc;
126 Fgrp *f = up->fgrp;
127 Chan *c = 0;
128
129 if(waserror())
130 return -1;
131
132 c = fdtochan(old, -1, 0, 1);
133 if(new != -1) {
134 if(new < 0 || NFD <= new) {
135 cclose(c);
136 error(Ebadfd);
137 }
138 lock(&f->ref.lk);
139 if(new > f->maxfd)
140 f->maxfd = new;
141 oc = f->fd[new];
142 f->fd[new] = (Chan*)c;
143 unlock(&f->ref.lk);
144 if(oc != 0)
145 cclose(oc);
146 }
147 else {
148 if(waserror()) {
149 cclose(c);
150 nexterror();
151 }
152 new = newfd((Chan*)c);
153 poperror();
154 }
155 poperror();
156 return new;
157 }
158
159 int
sysfstat(int fd,char * buf)160 sysfstat(int fd, char *buf)
161 {
162 Chan *c = 0;
163
164 if(waserror()) {
165 cclose(c);
166 return -1;
167 }
168 c = fdtochan(fd, -1, 0, 1);
169 devtab[c->type]->stat((Chan*)c, buf);
170 poperror();
171 cclose(c);
172 return 0;
173 }
174
175 int
sysfwstat(int fd,char * buf)176 sysfwstat(int fd, char *buf)
177 {
178 Chan *c = 0;
179
180 if(waserror()) {
181 cclose(c);
182 return -1;
183 }
184 nameok(buf);
185 c = fdtochan(fd, -1, 1, 1);
186 devtab[c->type]->wstat((Chan*)c, buf);
187 poperror();
188 cclose(c);
189 return 0;
190 }
191
192 int
syschdir(char * dir)193 syschdir(char *dir)
194 {
195 return 0;
196 }
197
198 long
bindmount(Chan * c0,char * old,int flag,char * spec)199 bindmount(Chan *c0, char *old, int flag, char *spec)
200 {
201 int ret;
202 Chan *c1 = 0;
203
204 if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
205 error(Ebadarg);
206
207 c1 = namec(old, Amount, 0, 0);
208 if(waserror()){
209 cclose(c1);
210 nexterror();
211 }
212
213 ret = cmount(c0, c1, flag, spec);
214
215 poperror();
216 cclose(c1);
217 return ret;
218 }
219
220 int
sysbind(char * new,char * old,int flags)221 sysbind(char *new, char *old, int flags)
222 {
223 long r;
224 Chan *c0 = 0;
225
226 if(waserror()) {
227 cclose(c0);
228 return -1;
229 }
230 c0 = namec(new, Aaccess, 0, 0);
231 r = bindmount(c0, old, flags, "");
232 poperror();
233 cclose(c0);
234 return 0;
235 }
236
237 int
sysmount(int fd,char * old,int flags,char * spec)238 sysmount(int fd, char *old, int flags, char *spec)
239 {
240 long r;
241 Chan *c0 = 0, *bc = 0;
242 struct {
243 Chan* chan;
244 char* spec;
245 int flags;
246 } mntparam;
247
248 if(waserror()) {
249 cclose(bc);
250 cclose(c0);
251 return -1;
252 }
253 bc = fdtochan(fd, ORDWR, 0, 1);
254 mntparam.chan = (Chan*)bc;
255 mntparam.spec = spec;
256 mntparam.flags = flags;
257 c0 = (*devtab[devno('M', 0)].attach)(&mntparam);
258 cclose(bc);
259 r = bindmount(c0, old, flags, spec);
260 poperror();
261 cclose(c0);
262
263 return r;
264 }
265
266 int
sysunmount(char * old,char * new)267 sysunmount(char *old, char *new)
268 {
269 Chan *cmount = 0, *cmounted = 0;
270
271 if(waserror()) {
272 cclose(cmount);
273 cclose(cmounted);
274 return -1;
275 }
276
277 cmount = namec(new, Amount, OREAD, 0);
278 if(old != 0)
279 cmounted = namec(old, Aopen, OREAD, 0);
280
281 cunmount(cmount, cmounted);
282 poperror();
283 cclose(cmount);
284 cclose(cmounted);
285 return 0;
286 }
287
288 int
sysopen(char * path,int mode)289 sysopen(char *path, int mode)
290 {
291 int fd;
292 Chan *c = 0;
293
294 if(waserror()){
295 cclose(c);
296 return -1;
297 }
298 openmode(mode); /* error check only */
299 c = namec(path, Aopen, mode, 0);
300 fd = newfd((Chan*)c);
301 poperror();
302 return fd;
303 }
304
305 long
unionread(Chan * c,void * va,long n)306 unionread(Chan *c, void *va, long n)
307 {
308 long nr;
309 Chan *nc = 0;
310 Pgrp *pg = 0;
311
312 pg = up->pgrp;
313 rlock(&pg->ns);
314
315 for(;;) {
316 if(waserror()) {
317 runlock(&pg->ns);
318 nexterror();
319 }
320 nc = clone(c->mnt->to, 0);
321 poperror();
322
323 if(c->mountid != c->mnt->mountid) {
324 runlock(&pg->ns);
325 cclose(nc);
326 return 0;
327 }
328
329 /* Error causes component of union to be skipped */
330 if(waserror()) {
331 cclose(nc);
332 goto next;
333 }
334
335 nc = (*devtab[nc->type].open)((Chan*)nc, OREAD);
336 nc->offset = c->offset;
337 nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset);
338 /* devdirread e.g. changes it */
339 c->offset = nc->offset;
340 poperror();
341
342 cclose(nc);
343 if(nr > 0) {
344 runlock(&pg->ns);
345 return nr;
346 }
347 /* Advance to next element */
348 next:
349 c->mnt = c->mnt->next;
350 if(c->mnt == 0)
351 break;
352 c->mountid = c->mnt->mountid;
353 c->offset = 0;
354 }
355 runlock(&pg->ns);
356 return 0;
357 }
358
359 long
sysread(int fd,void * va,long n)360 sysread(int fd, void *va, long n)
361 {
362 int dir;
363 Lock *cl;
364 Chan *c = 0;
365
366 if(waserror()) {
367 cclose(c);
368 return -1;
369 }
370 c = fdtochan(fd, OREAD, 1, 1);
371
372 dir = c->qid.path&CHDIR;
373 if(dir) {
374 n -= n%DIRLEN;
375 if(c->offset%DIRLEN || n==0)
376 error(Etoosmall);
377 }
378
379 if(dir && c->mnt)
380 n = unionread((Chan*)c, va, n);
381 else
382 n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset);
383
384 cl = (Lock*)&c->r.l;
385 lock(cl);
386 c->offset += n;
387 unlock(cl);
388
389 poperror();
390 cclose(c);
391
392 return n;
393 }
394
395 int
sysremove(char * path)396 sysremove(char *path)
397 {
398 Chan *c = 0;
399
400 if(waserror()) {
401 if(c != 0)
402 c->type = 0; /* see below */
403 cclose(c);
404 return -1;
405 }
406 c = namec(path, Aaccess, 0, 0);
407 (*devtab[c->type].remove)((Chan*)c);
408 /*
409 * Remove clunks the fid, but we need to recover the Chan
410 * so fake it up. rootclose() is known to be a nop.
411 */
412 c->type = 0;
413 poperror();
414 cclose(c);
415 return 0;
416 }
417
418 long
sysseek(int fd,long off,int whence)419 sysseek(int fd, long off, int whence)
420 {
421 Dir dir;
422 Chan *c;
423 char buf[DIRLEN];
424
425 if(waserror())
426 return -1;
427
428 c = fdtochan(fd, -1, 1, 0);
429 if(c->qid.path & CHDIR)
430 error(Eisdir);
431
432 switch(whence) {
433 case 0:
434 c->offset = off;
435 break;
436
437 case 1:
438 lock(&c->r.l); /* lock for read/write update */
439 c->offset += off;
440 off = c->offset;
441 unlock(&c->r.l);
442 break;
443
444 case 2:
445 (*devtab[c->type].stat)(c, buf);
446 convM2D(buf, &dir);
447 c->offset = dir.length + off;
448 off = c->offset;
449 break;
450 }
451 poperror();
452 return off;
453 }
454
455 int
sysstat(char * path,char * buf)456 sysstat(char *path, char *buf)
457 {
458 Chan *c = 0;
459
460 if(waserror()){
461 cclose(c);
462 return -1;
463 }
464 c = namec(path, Aaccess, 0, 0);
465 (*devtab[c->type].stat)((Chan*)c, buf);
466 poperror();
467 cclose(c);
468 return 0;
469 }
470
471 long
syswrite(int fd,void * va,long n)472 syswrite(int fd, void *va, long n)
473 {
474 Lock *cl;
475 Chan *c = 0;
476
477 if(waserror()) {
478 cclose(c);
479 return -1;
480 }
481 c = fdtochan(fd, OWRITE, 1, 1);
482 if(c->qid.path & CHDIR)
483 error(Eisdir);
484
485 n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset);
486
487 cl = (Lock*)&c->r.l;
488 lock(cl);
489 c->offset += n;
490 unlock(cl);
491
492 poperror();
493 cclose(c);
494
495 return n;
496 }
497
498 int
syswstat(char * path,char * buf)499 syswstat(char *path, char *buf)
500 {
501 Chan *c = 0;
502
503 if(waserror()) {
504 cclose(c);
505 return -1;
506 }
507
508 nameok(buf);
509 c = namec(path, Aaccess, 0, 0);
510 (*devtab[c->type].wstat)((Chan*)c, buf);
511 poperror();
512 cclose(c);
513 return 0;
514 }
515
516 int
sysdirstat(char * name,Dir * dir)517 sysdirstat(char *name, Dir *dir)
518 {
519 char buf[DIRLEN];
520
521 if(sysstat(name, buf) == -1)
522 return -1;
523 convM2D(buf, dir);
524 return 0;
525 }
526
527 int
sysdirfstat(int fd,Dir * dir)528 sysdirfstat(int fd, Dir *dir)
529 {
530 char buf[DIRLEN];
531
532 if(sysfstat(fd, buf) == -1)
533 return -1;
534
535 convM2D(buf, dir);
536 return 0;
537 }
538
539 int
sysdirwstat(char * name,Dir * dir)540 sysdirwstat(char *name, Dir *dir)
541 {
542 char buf[DIRLEN];
543
544 convD2M(dir, buf);
545 return syswstat(name, buf);
546 }
547
548 int
sysdirfwstat(int fd,Dir * dir)549 sysdirfwstat(int fd, Dir *dir)
550 {
551 char buf[DIRLEN];
552
553 convD2M(dir, buf);
554 return sysfwstat(fd, buf);
555 }
556
557 long
sysdirread(int fd,Dir * dbuf,long count)558 sysdirread(int fd, Dir *dbuf, long count)
559 {
560 int c, n, i, r;
561 char buf[DIRLEN*50];
562
563 n = 0;
564 count = (count/sizeof(Dir)) * DIRLEN;
565 while(n < count) {
566 c = count - n;
567 if(c > sizeof(buf))
568 c = sizeof(buf);
569 r = sysread(fd, buf, c);
570 if(r == 0)
571 break;
572 if(r < 0 || r % DIRLEN)
573 return -1;
574 for(i=0; i<r; i+=DIRLEN) {
575 convM2D(buf+i, dbuf);
576 dbuf++;
577 }
578 n += r;
579 if(r != c)
580 break;
581 }
582
583 return (n/DIRLEN) * sizeof(Dir);
584 }
585
586 static int
call(char * clone,char * dest,int * cfdp,char * dir,char * local)587 call(char *clone, char *dest, int *cfdp, char *dir, char *local)
588 {
589 int fd, cfd, n;
590 char *p, name[3*NAMELEN+5], data[3*NAMELEN+10];
591
592 cfd = sysopen(clone, ORDWR);
593 if(cfd < 0){
594 werrstr("%s: %r", clone);
595 return -1;
596 }
597
598 /* get directory name */
599 n = sysread(cfd, name, sizeof(name)-1);
600 if(n < 0) {
601 sysclose(cfd);
602 return -1;
603 }
604 name[n] = 0;
605 sprint(name, "%d", strtoul(name, 0, 0));
606 p = strrchr(clone, '/');
607 *p = 0;
608 if(dir)
609 snprint(dir, 2*NAMELEN, "%s/%s", clone, name);
610 snprint(data, sizeof(data), "%s/%s/data", clone, name);
611
612 /* connect */
613 /* set local side (port number, for example) if we need to */
614 if(local)
615 snprint(name, sizeof(name), "connect %s %s", dest, local);
616 else
617 snprint(name, sizeof(name), "connect %s", dest);
618 if(syswrite(cfd, name, strlen(name)) < 0){
619 werrstr("%s failed: %r", name);
620 sysclose(cfd);
621 return -1;
622 }
623
624 /* open data connection */
625 fd = sysopen(data, ORDWR);
626 if(fd < 0){
627 werrstr("can't open %s: %r", data);
628 sysclose(cfd);
629 return -1;
630 }
631 if(cfdp)
632 *cfdp = cfd;
633 else
634 sysclose(cfd);
635 return fd;
636 }
637
638 int
sysdial(char * dest,char * local,char * dir,int * cfdp)639 sysdial(char *dest, char *local, char *dir, int *cfdp)
640 {
641 int n, fd, rv;
642 char *p, net[128], clone[NAMELEN+12];
643
644 /* go for a standard form net!... */
645 p = strchr(dest, '!');
646 if(p == 0){
647 snprint(net, sizeof(net), "net!%s", dest);
648 } else {
649 strncpy(net, dest, sizeof(net)-1);
650 net[sizeof(net)-1] = 0;
651 }
652
653 /* call the connection server */
654 fd = sysopen("/net/cs", ORDWR);
655 if(fd < 0){
656 /* no connection server, don't translate */
657 p = strchr(net, '!');
658 *p++ = 0;
659 snprint(clone, sizeof(clone), "/net/%s/clone", net);
660 return call(clone, p, cfdp, dir, local);
661 }
662
663 /*
664 * send dest to connection to translate
665 */
666 if(syswrite(fd, net, strlen(net)) < 0){
667 werrstr("%s: %r", net);
668 sysclose(fd);
669 return -1;
670 }
671
672 /*
673 * loop through each address from the connection server till
674 * we get one that works.
675 */
676 rv = -1;
677 sysseek(fd, 0, 0);
678 while((n = sysread(fd, net, sizeof(net) - 1)) > 0){
679 net[n] = 0;
680 p = strchr(net, ' ');
681 if(p == 0)
682 continue;
683 *p++ = 0;
684 rv = call(net, p, cfdp, dir, local);
685 if(rv >= 0)
686 break;
687 }
688 sysclose(fd);
689 return rv;
690 }
691
692 static int
identtrans(char * addr,char * naddr,int na,char * file,int nf)693 identtrans(char *addr, char *naddr, int na, char *file, int nf)
694 {
695 char *p;
696 char reply[4*NAMELEN];
697
698 /* parse the network */
699 strncpy(reply, addr, sizeof(reply));
700 reply[sizeof(reply)-1] = 0;
701 p = strchr(reply, '!');
702 if(p)
703 *p++ = 0;
704
705 sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply);
706 strncpy(naddr, p, na);
707 naddr[na-1] = 0;
708 return 1;
709 }
710
711 static int
nettrans(char * addr,char * naddr,int na,char * file,int nf)712 nettrans(char *addr, char *naddr, int na, char *file, int nf)
713 {
714 long n;
715 int fd;
716 char *cp;
717 char reply[4*NAMELEN];
718
719 /*
720 * ask the connection server
721 */
722 fd = sysopen("/net/cs", ORDWR);
723 if(fd < 0)
724 return identtrans(addr, naddr, na, file, nf);
725 if(syswrite(fd, addr, strlen(addr)) < 0){
726 sysclose(fd);
727 return -1;
728 }
729 sysseek(fd, 0, 0);
730 n = sysread(fd, reply, sizeof(reply)-1);
731 sysclose(fd);
732 if(n <= 0)
733 return -1;
734 reply[n] = '\0';
735
736 /*
737 * parse the reply
738 */
739 cp = strchr(reply, ' ');
740 if(cp == 0)
741 return -1;
742 *cp++ = 0;
743 strncpy(naddr, cp, na);
744 naddr[na-1] = 0;
745 strncpy(file, reply, nf);
746 file[nf-1] = 0;
747 return 0;
748 }
749
750 int
sysannounce(char * addr,char * dir)751 sysannounce(char *addr, char *dir)
752 {
753 char *cp;
754 int ctl, n, m;
755 char buf[3*NAMELEN];
756 char buf2[3*NAMELEN];
757 char netdir[2*NAMELEN];
758 char naddr[3*NAMELEN];
759
760 /*
761 * translate the address
762 */
763 if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){
764 werrstr("can't translate address");
765 return -1;
766 }
767
768 /*
769 * get a control channel
770 */
771 ctl = sysopen(netdir, ORDWR);
772 if(ctl<0){
773 werrstr("can't open control channel");
774 return -1;
775 }
776 cp = strrchr(netdir, '/');
777 *cp = 0;
778
779 /*
780 * find out which line we have
781 */
782 n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir);
783 m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
784 if(m <= 0) {
785 sysclose(ctl);
786 werrstr("can't read control file");
787 return -1;
788 }
789 buf[n+m] = 0;
790
791 /*
792 * make the call
793 */
794 n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr);
795 if(syswrite(ctl, buf2, n) != n) {
796 sysclose(ctl);
797 werrstr("announcement fails");
798 return -1;
799 }
800
801 strcpy(dir, buf);
802
803 return ctl;
804 }
805
806 int
syslisten(char * dir,char * newdir)807 syslisten(char *dir, char *newdir)
808 {
809 char *cp;
810 int ctl, n, m;
811 char buf[3*NAMELEN];
812
813 /*
814 * open listen, wait for a call
815 */
816 sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir);
817 ctl = sysopen(buf, ORDWR);
818 if(ctl < 0)
819 return -1;
820
821 /*
822 * find out which line we have
823 */
824 strcpy(buf, dir);
825 cp = strrchr(buf, '/');
826 *++cp = 0;
827 n = cp-buf;
828 m = sysread(ctl, cp, sizeof(buf) - n - 1);
829 if(n<=0){
830 sysclose(ctl);
831 return -1;
832 }
833 buf[n+m] = 0;
834
835 strcpy(newdir, buf);
836 return ctl;
837 }
838