2 #include "../port/lib.h"
6 #include "../port/error.h"
9 * The sys*() routines needn't poperror() as they return directly to syscall().
21 pprint("warning: process exceeds %d file descriptors\n", ex);
25 growfd(Fgrp *f, int fd) /* fd is always >= 0 */
27 Chan **newfd, **oldfd;
31 if(fd >= f->nfd+DELTAFD)
32 return -1; /* out of range */
34 * Unbounded allocation is unwise; besides, there are only 16 bits
39 print("no free file descriptors\n");
42 newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
46 memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
51 if(fd/100 > f->maxfd/100)
52 f->exceed = (fd/100)*100;
59 * this assumes that the fgrp is locked
62 findfreefd(Fgrp *f, int start)
66 for(fd=start; fd<f->nfd; fd++)
69 if(fd >= f->nfd && growfd(f, fd) < 0)
82 fd = findfreefd(f, 0);
95 newfd2(int fd[2], Chan *c[2])
101 fd[0] = findfreefd(f, 0);
106 fd[1] = findfreefd(f, fd[0]+1);
120 fdtochan(int fd, int mode, int chkmnt, int iref)
129 if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==nil) {
137 if(chkmnt && (c->flag&CMSG)) {
143 if(mode<0 || c->mode==ORDWR)
146 if((mode&OTRUNC) && c->mode==OREAD) {
152 if((mode&~OTRUNC) != c->mode) {
163 o &= ~(OTRUNC|OCEXEC|ORCLOSE);
172 sysfd2path(va_list list)
179 fd = va_arg(list, int);
180 buf = va_arg(list, char*);
181 len = va_arg(list, uint);
182 validaddr((uintptr)buf, len, 1);
183 c = fdtochan(fd, -1, 0, 1);
184 snprint(buf, len, "%s", chanpath(c));
190 syspipe(va_list list)
192 static char *datastr[] = {"data", "data1"};
196 ufd = va_arg(list, int*);
197 validaddr((uintptr)ufd, sizeof(fd), 1);
198 evenaddr((uintptr)ufd);
200 ufd[0] = ufd[1] = fd[0] = fd[1] = -1;
201 c[0] = namec("#|", Atodir, 0, 0);
210 if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
212 if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
214 c[0] = devtab[c[0]->type]->open(c[0], ORDWR);
215 c[1] = devtab[c[1]->type]->open(c[1], ORDWR);
216 if(newfd2(fd, c) < 0)
231 fd = va_arg(list, int);
234 * Close after dup'ing, so date > #d/1 works
236 c = fdtochan(fd, -1, 0, 1);
237 fd = va_arg(list, int);
240 if(fd<0 || growfd(f, fd)<0) {
267 sysopen(va_list list)
274 name = va_arg(list, char*);
275 mode = va_arg(list, ulong);
276 openmode(mode); /* error check only */
277 validaddr((uintptr)name, 1, 0);
278 c = namec(name, Aopen, mode, 0);
291 fdclose(int fd, int flag)
297 c = fd <= f->maxfd ? f->fd[fd] : nil;
298 if(c == nil || (flag != 0 && (c->flag&flag) == 0)){
304 while(fd > 0 && f->fd[fd] == nil)
312 sysclose(va_list list)
316 fd = va_arg(list, int);
317 fdtochan(fd, -1, 0, 0);
323 unionread(Chan *c, void *va, long n)
334 /* bring mount in sync with c->uri and c->umc */
335 for(i = 0; mount != nil && i < c->uri; i++)
340 /* Error causes component of union to be skipped */
341 if(mount->to != nil && !waserror()){
343 c->umc = cclone(mount->to);
344 c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
347 nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
348 c->umc->offset += nr;
354 /* Advance to next element */
363 qunlock(&c->umqlock);
376 qunlock(&c->umqlock);
380 dirfixed(uchar *p, uchar *e, Dir *d)
384 len = GBIT16(p)+BIT16SZ;
388 p += BIT16SZ; /* ignore size */
389 d->type = devno(GBIT16(p), 1);
393 d->qid.type = GBIT8(p);
395 d->qid.vers = GBIT32(p);
397 d->qid.path = GBIT64(p);
401 d->atime = GBIT32(p);
403 d->mtime = GBIT32(p);
405 d->length = GBIT64(p);
411 dirname(uchar *p, int *n)
413 p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
414 + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
416 return (char*)p+BIT16SZ;
420 dirsetname(char *name, int len, uchar *p, long n, long maxn)
429 oname = dirname(p, &olen);
432 PBIT16(p, nn-BIT16SZ);
437 memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
438 PBIT16((uchar*)(oname-2), len);
439 memmove(oname, name, len);
444 * Mountfix might have caused the fixed results of the directory read
445 * to overflow the buffer. Catch the overflow in c->dirrock.
448 mountrock(Chan *c, uchar *p, uchar **pe)
455 /* find last directory entry */
457 len = BIT16SZ+GBIT16(p);
464 qlock(&c->rockqlock);
465 if(c->nrock+len > c->mrock){
466 n = ROUND(c->nrock+len, 1024);
468 memmove(r, c->dirrock, c->nrock);
473 memmove(c->dirrock+c->nrock, p, len);
475 qunlock(&c->rockqlock);
482 * Satisfy a directory read with the results saved in c->dirrock.
485 mountrockread(Chan *c, uchar *op, long n, long *nn)
488 uchar *rp, *erp, *ep, *p;
494 /* copy out what we can */
495 qlock(&c->rockqlock);
500 while(rp+BIT16SZ <= erp){
501 dirlen = BIT16SZ+GBIT16(rp);
504 memmove(p, rp, dirlen);
510 qunlock(&c->rockqlock);
516 memmove(c->dirrock, rp, erp-rp);
520 qunlock(&c->rockqlock);
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.
537 mountfix(Chan *c, uchar *op, long n, long maxn)
553 for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
554 dirlen = dirfixed(p, e, &d);
559 if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
561 * If it's a union directory and the original is
562 * in the union, don't rewrite anything.
564 for(m = mh->mount; m != nil; m = m->next)
565 if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
568 name = dirname(p, &nname);
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.
580 l = devtab[nc->type]->stat(nc, buf, nbuf);
581 l = dirsetname(name, nname, buf, l, nbuf);
587 * Shift data in buffer to accomodate new entry,
588 * possibly overflowing into rock.
590 rest = e - (p+dirlen);
592 while(p+l+rest > op+maxn){
598 rest = e - (p+dirlen);
602 memmove(p+l, p+dirlen, rest);
608 * Rewrite directory entry.
621 error("oops in rockfix");
627 read(int fd, uchar *p, long n, vlong *offp)
633 validaddr((uintptr)p, n, 1);
634 c = fdtochan(fd, OREAD, 1, 1);
642 * The offset is passed through on directories, normally.
643 * Sysseek complains, but pread is used by servers like exportfs,
644 * that shouldn't need to worry about this issue.
646 * Notice that c->devoffset is the offset that c's dev is seeing.
647 * The number of bytes read on this fd (c->offset) may be different
648 * due to rewritings in rockfix.
650 if(offp == nil) /* use and maintain channel's offset */
657 if(off == 0){ /* rewind to the beginning of the directory */
658 if(offp == nil || (c->qid.type & QTDIR)){
666 if(c->qid.type & QTDIR){
667 if(mountrockread(c, p, n, &nn)){
668 /* do nothing: mountrockread filled buffer */
669 }else if(c->umh != nil)
670 nn = unionread(c, p, n);
674 nn = devtab[c->type]->read(c, p, n, c->devoffset);
676 nnn = mountfix(c, p, nn, n);
678 nnn = nn = devtab[c->type]->read(c, p, n, off);
680 if(offp == nil || (c->qid.type & QTDIR)){
693 sys_read(va_list list)
699 fd = va_arg(list, int);
700 buf = va_arg(list, void*);
701 len = va_arg(list, long);
702 return (uintptr)read(fd, buf, len, nil);
706 syspread(va_list list)
713 fd = va_arg(list, int);
714 buf = va_arg(list, void*);
715 len = va_arg(list, long);
716 off = va_arg(list, vlong);
721 return (uintptr)read(fd, buf, len, offp);
725 write(int fd, void *buf, long len, vlong *offp)
731 validaddr((uintptr)buf, len, 0);
733 c = fdtochan(fd, OWRITE, 1, 1);
744 if(c->qid.type & QTDIR)
749 if(offp == nil){ /* use and maintain channel's offset */
760 m = devtab[c->type]->write(c, buf, n, off);
761 if(offp == nil && m < n){
773 sys_write(va_list list)
779 fd = va_arg(list, int);
780 buf = va_arg(list, void*);
781 len = va_arg(list, long);
782 return (uintptr)write(fd, buf, len, nil);
786 syspwrite(va_list list)
793 fd = va_arg(list, int);
794 buf = va_arg(list, void*);
795 len = va_arg(list, long);
796 off = va_arg(list, vlong);
801 return (uintptr)write(fd, buf, len, offp);
805 sseek(int fd, vlong o, int type)
808 uchar buf[sizeof(Dir)+100];
813 c = fdtochan(fd, -1, 1, 1);
818 if(devtab[c->type]->dc == L'|')
825 if((c->qid.type & QTDIR) && off != 0)
833 if(c->qid.type & QTDIR)
835 lock(c); /* lock for read/write update */
846 if(c->qid.type & QTDIR)
848 n = devtab[c->type]->stat(c, buf, sizeof buf);
849 if(convM2D(buf, n, &dir, nil) == 0)
850 error("internal error: stat error in seek");
851 off = dir.length + o;
868 sysseek(va_list list)
873 v = va_arg(list, vlong*);
874 evenaddr((uintptr)v);
875 validaddr((uintptr)v, sizeof(vlong), 1);
877 fd = va_arg(list, int);
878 n = va_arg(list, vlong);
879 t = va_arg(list, int);
881 *v = sseek(fd, n, t);
887 sysoseek(va_list list)
892 fd = va_arg(list, int);
893 n = va_arg(list, long);
894 t = va_arg(list, int);
895 return (uintptr)sseek(fd, n, t);
899 validstat(uchar *s, int n)
904 if(statcheck(s, n) < 0)
906 /* verify that name entry is acceptable */
907 s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
909 * s now points at count for first string.
910 * if it's too long, let the server decide; this is
911 * only for his protection anyway. otherwise
912 * we'd have to allocate and waserror.
920 /* name could be '/' */
921 if(strcmp(buf, "/") != 0)
934 s = strrchr(p->s, '/');
941 sysfstat(va_list list)
948 fd = va_arg(list, int);
949 s = va_arg(list, uchar*);
950 l = va_arg(list, uint);
951 validaddr((uintptr)s, l, 1);
953 c = fdtochan(fd, -1, 0, 1);
958 l = devtab[c->type]->stat(c, s, l);
965 sysstat(va_list list)
972 name = va_arg(list, char*);
973 s = va_arg(list, uchar*);
974 l = va_arg(list, uint);
975 validaddr((uintptr)s, l, 1);
976 validaddr((uintptr)name, 1, 0);
977 c = namec(name, Aaccess, 0, 0);
982 r = devtab[c->type]->stat(c, s, l);
983 name = pathlast(c->path);
985 r = dirsetname(name, strlen(name), s, r, l);
993 syschdir(va_list list)
998 name = va_arg(list, char*);
999 validaddr((uintptr)name, 1, 0);
1000 c = namec(name, Atodir, 0, 0);
1007 bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, int flag, char* spec)
1010 Chan *c0, *c1, *ac, *bc;
1012 if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
1016 validaddr((uintptr)spec, 1, 0);
1017 spec = validnamedup(spec, 1);
1023 if(up->pgrp->noattach)
1027 bc = fdtochan(fd, ORDWR, 0, 1);
1036 ac = fdtochan(afd, ORDWR, 0, 1);
1038 c0 = mntattach(bc, ac, spec, flag&MCACHE);
1039 poperror(); /* ac bc */
1045 validaddr((uintptr)arg0, 1, 0);
1046 c0 = namec(arg0, Abind, 0, 0);
1054 validaddr((uintptr)arg1, 1, 0);
1055 c1 = namec(arg1, Amount, 0, 0);
1061 ret = cmount(&c0, c1, flag, spec);
1076 sysbind(va_list list)
1081 arg0 = va_arg(list, char*);
1082 arg1 = va_arg(list, char*);
1083 flag = va_arg(list, int);
1084 return (uintptr)bindmount(0, -1, -1, arg0, arg1, flag, nil);
1088 sysmount(va_list list)
1094 fd = va_arg(list, int);
1095 afd = va_arg(list, int);
1096 arg1 = va_arg(list, char*);
1097 flag = va_arg(list, int);
1098 spec = va_arg(list, char*);
1099 return (uintptr)bindmount(1, fd, afd, nil, arg1, flag, spec);
1103 sys_mount(va_list list)
1109 fd = va_arg(list, int);
1110 arg1 = va_arg(list, char*);
1111 flag = va_arg(list, int);
1112 spec = va_arg(list, char*);
1113 return (uintptr)bindmount(1, fd, -1, nil, arg1, flag, spec);
1117 sysunmount(va_list list)
1119 Chan *cmount, *cmounted;
1122 name = va_arg(list, char*);
1123 old = va_arg(list, char*);
1126 validaddr((uintptr)old, 1, 0);
1127 cmount = namec(old, Amount, 0, 0);
1136 * This has to be namec(..., Aopen, ...) because
1137 * if arg[0] is something like /srv/cs or /fd/0,
1138 * opening it is the only way to get at the real
1141 validaddr((uintptr)name, 1, 0);
1142 cmounted = namec(name, Aopen, OREAD, 0);
1144 cunmount(cmount, cmounted);
1153 syscreate(va_list list)
1159 name = va_arg(list, char*);
1160 mode = va_arg(list, int);
1161 perm = va_arg(list, int);
1162 openmode(mode&~OEXCL); /* error check only; OEXCL okay here */
1163 validaddr((uintptr)name, 1, 0);
1164 c = namec(name, Acreate, mode, perm);
1177 sysremove(va_list list)
1182 name = va_arg(list, char*);
1183 validaddr((uintptr)name, 1, 0);
1184 c = namec(name, Aremove, 0, 0);
1186 * Removing mount points is disallowed to avoid surprises
1187 * (which should be removed: the mount point or the mounted Chan?).
1194 c->type = 0; /* see below */
1198 devtab[c->type]->remove(c);
1200 * Remove clunks the fid, but we need to recover the Chan
1201 * so fake it up. rootclose() is known to be a nop.
1210 wstat(Chan *c, uchar *d, int nd)
1221 * Renaming mount points is disallowed to avoid surprises
1222 * (which should be renamed? the mount point or the mounted Chan?).
1224 dirname(d, &namelen);
1226 nameerror(chanpath(c), Eismtpt);
1228 l = devtab[c->type]->wstat(c, d, nd);
1235 syswstat(va_list list)
1242 name = va_arg(list, char*);
1243 s = va_arg(list, uchar*);
1244 l = va_arg(list, uint);
1245 validaddr((uintptr)s, l, 0);
1247 validaddr((uintptr)name, 1, 0);
1248 c = namec(name, Aaccess, 0, 0);
1249 return (uintptr)wstat(c, s, l);
1253 sysfwstat(va_list list)
1260 fd = va_arg(list, int);
1261 s = va_arg(list, uchar*);
1262 l = va_arg(list, uint);
1263 validaddr((uintptr)s, l, 0);
1265 c = fdtochan(fd, -1, 1, 1);
1266 return (uintptr)wstat(c, s, l);
1270 packoldstat(uchar *buf, Dir *d)
1275 /* lay down old stat buffer - grotty code but it's temporary */
1277 strncpy((char*)p, d->name, 28);
1279 strncpy((char*)p, d->uid, 28);
1281 strncpy((char*)p, d->gid, 28);
1283 q = (ulong)d->qid.path & ~DMDIR; /* make sure doesn't accidentally look like directory */
1284 if(d->qid.type & QTDIR) /* this is the real test of a new directory */
1288 PBIT32(p, d->qid.vers);
1292 PBIT32(p, d->atime);
1294 PBIT32(p, d->mtime);
1296 PBIT64(p, d->length);
1304 sys_stat(va_list list)
1306 static char old[] = "old stat system call - recompile";
1309 uchar *s, buf[128]; /* old DIRLEN plus a little should be plenty */
1310 char strs[128], *name;
1313 name = va_arg(list, char*);
1314 s = va_arg(list, uchar*);
1315 validaddr((uintptr)s, 116, 1);
1316 validaddr((uintptr)name, 1, 0);
1317 c = namec(name, Aaccess, 0, 0);
1322 l = devtab[c->type]->stat(c, buf, sizeof buf);
1323 /* buf contains a new stat buf; convert to old. yuck. */
1324 if(l <= BIT16SZ) /* buffer too small; time to face reality */
1326 name = pathlast(c->path);
1328 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1329 l = convM2D(buf, l, &d, strs);
1340 sys_fstat(va_list list)
1342 static char old[] = "old fstat system call - recompile";
1346 uchar *s, buf[128]; /* old DIRLEN plus a little should be plenty */
1351 fd = va_arg(list, int);
1352 s = va_arg(list, uchar*);
1353 validaddr((uintptr)s, 116, 1);
1354 c = fdtochan(fd, -1, 0, 1);
1359 l = devtab[c->type]->stat(c, buf, sizeof buf);
1360 /* buf contains a new stat buf; convert to old. yuck. */
1361 if(l <= BIT16SZ) /* buffer too small; time to face reality */
1363 name = pathlast(c->path);
1365 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1366 l = convM2D(buf, l, &d, strs);
1379 error("old wstat system call - recompile");
1386 error("old fwstat system call - recompile");