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);
121 fdtochan(int fd, int mode, int chkmnt, int iref)
130 if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
138 if(chkmnt && (c->flag&CMSG)) {
144 if(mode<0 || c->mode==ORDWR)
147 if((mode&OTRUNC) && c->mode==OREAD) {
153 if((mode&~OTRUNC) != c->mode) {
165 o &= ~(OTRUNC|OCEXEC|ORCLOSE);
174 sysfd2path(ulong *arg)
178 validaddr(arg[1], arg[2], 1);
180 c = fdtochan(arg[0], -1, 0, 1);
181 snprint((char*)arg[1], arg[2], "%s", chanpath(c));
192 static char *datastr[] = {"data", "data1"};
194 validaddr(arg[0], 2*BY2WD, 1);
196 d = devtab[devno('|', 0)];
197 c[0] = namec("#|", Atodir, 0, 0);
209 if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
211 if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
213 c[0] = d->open(c[0], ORDWR);
214 c[1] = d->open(c[1], ORDWR);
215 if(newfd2(fd, c) < 0)
219 ((long*)arg[0])[0] = fd[0];
220 ((long*)arg[0])[1] = fd[1];
232 * Close after dup'ing, so date > #d/1 works
234 c = fdtochan(arg[0], -1, 0, 1);
238 if(fd<0 || growfd(f, fd)<0) {
271 openmode(arg[1]); /* error check only */
272 validaddr(arg[0], 1, 0);
273 c = namec((char*)arg[0], Aopen, arg[1], 0);
286 fdclose(int fd, int flag)
295 /* can happen for users with shared fd tables */
300 if(c==0 || !(c->flag&flag)){
307 for(i=fd; --i>=0 && f->fd[i]==0; )
317 fdtochan(arg[0], -1, 0, 0);
324 unionread(Chan *c, void *va, long n)
335 /* bring mount in sync with c->uri and c->umc */
336 for(i = 0; mount != nil && i < c->uri; i++)
341 /* Error causes component of union to be skipped */
342 if(mount->to && !waserror()){
344 c->umc = cclone(mount->to);
345 c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
348 nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
349 c->umc->offset += nr;
355 /* Advance to next element */
364 qunlock(&c->umqlock);
377 qunlock(&c->umqlock);
381 dirfixed(uchar *p, uchar *e, Dir *d)
385 len = GBIT16(p)+BIT16SZ;
389 p += BIT16SZ; /* ignore size */
390 d->type = devno(GBIT16(p), 1);
394 d->qid.type = GBIT8(p);
396 d->qid.vers = GBIT32(p);
398 d->qid.path = GBIT64(p);
402 d->atime = GBIT32(p);
404 d->mtime = GBIT32(p);
406 d->length = GBIT64(p);
412 dirname(uchar *p, int *n)
414 p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
415 + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
417 return (char*)p+BIT16SZ;
421 dirsetname(char *name, int len, uchar *p, long n, long maxn)
430 oname = dirname(p, &olen);
433 PBIT16(p, nn-BIT16SZ);
438 memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
439 PBIT16((uchar*)(oname-2), len);
440 memmove(oname, name, len);
445 * Mountfix might have caused the fixed results of the directory read
446 * to overflow the buffer. Catch the overflow in c->dirrock.
449 mountrock(Chan *c, uchar *p, uchar **pe)
456 /* find last directory entry */
458 len = BIT16SZ+GBIT16(p);
465 qlock(&c->rockqlock);
466 if(c->nrock+len > c->mrock){
467 n = ROUND(c->nrock+len, 1024);
469 memmove(r, c->dirrock, c->nrock);
474 memmove(c->dirrock+c->nrock, p, len);
476 qunlock(&c->rockqlock);
483 * Satisfy a directory read with the results saved in c->dirrock.
486 mountrockread(Chan *c, uchar *op, long n, long *nn)
489 uchar *rp, *erp, *ep, *p;
495 /* copy out what we can */
496 qlock(&c->rockqlock);
501 while(rp+BIT16SZ <= erp){
502 dirlen = BIT16SZ+GBIT16(rp);
505 memmove(p, rp, dirlen);
511 qunlock(&c->rockqlock);
517 memmove(c->dirrock, rp, erp-rp);
521 qunlock(&c->rockqlock);
532 * Rewrite the results of a directory read to reflect current
533 * name space bindings and mounts. Specifically, replace
534 * directory entries for bind and mount points with the results
535 * of statting what is mounted there. Except leave the old names.
538 mountfix(Chan *c, uchar *op, long n, long maxn)
554 for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
555 dirlen = dirfixed(p, e, &d);
560 if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
562 * If it's a union directory and the original is
563 * in the union, don't rewrite anything.
565 for(m=mh->mount; m; m=m->next)
566 if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
569 name = dirname(p, &nname);
571 * Do the stat but fix the name. If it fails, leave old entry.
572 * BUG: If it fails because there isn't room for the entry,
573 * what can we do? Nothing, really. Might as well skip it.
581 l = devtab[nc->type]->stat(nc, buf, nbuf);
582 l = dirsetname(name, nname, buf, l, nbuf);
588 * Shift data in buffer to accomodate new entry,
589 * possibly overflowing into rock.
591 rest = e - (p+dirlen);
593 while(p+l+rest > op+maxn){
599 rest = e - (p+dirlen);
603 memmove(p+l, p+dirlen, rest);
609 * Rewrite directory entry.
622 error("oops in rockfix");
628 read(ulong *arg, vlong *offp)
636 validaddr(arg[1], n, 1);
638 c = fdtochan(arg[0], OREAD, 1, 1);
646 * The offset is passed through on directories, normally.
647 * Sysseek complains, but pread is used by servers like exportfs,
648 * that shouldn't need to worry about this issue.
650 * Notice that c->devoffset is the offset that c's dev is seeing.
651 * The number of bytes read on this fd (c->offset) may be different
652 * due to rewritings in rockfix.
654 if(offp == nil) /* use and maintain channel's offset */
661 if(off == 0){ /* rewind to the beginning of the directory */
670 if(c->qid.type & QTDIR){
671 if(mountrockread(c, p, n, &nn)){
672 /* do nothing: mountrockread filled buffer */
674 nn = unionread(c, p, n);
678 nn = devtab[c->type]->read(c, p, n, c->devoffset);
680 nnn = mountfix(c, p, nn, n);
682 nnn = nn = devtab[c->type]->read(c, p, n, off);
698 return read(arg, nil);
707 /* use varargs to guarantee alignment of vlong */
708 va_start(list, arg[2]);
709 v = va_arg(list, vlong);
713 return read(arg, nil);
715 return read(arg, &v);
719 write(ulong *arg, vlong *offp)
725 validaddr(arg[1], arg[2], 0);
727 c = fdtochan(arg[0], OWRITE, 1, 1);
738 if(c->qid.type & QTDIR)
743 if(offp == nil){ /* use and maintain channel's offset */
754 m = devtab[c->type]->write(c, (void*)arg[1], n, off);
756 if(offp == nil && m < n){
769 sys_write(ulong *arg)
771 return write(arg, nil);
775 syspwrite(ulong *arg)
780 /* use varargs to guarantee alignment of vlong */
781 va_start(list, arg[2]);
782 v = va_arg(list, vlong);
786 return write(arg, nil);
788 return write(arg, &v);
795 uchar buf[sizeof(Dir)+100];
804 c = fdtochan(arg[1], -1, 1, 1);
809 if(devtab[c->type]->dc == '|')
818 if((c->qid.type & QTDIR) && off != 0)
826 if(c->qid.type & QTDIR)
828 lock(c); /* lock for read/write update */
829 off = o.v + c->offset;
839 if(c->qid.type & QTDIR)
841 n = devtab[c->type]->stat(c, buf, sizeof buf);
842 if(convM2D(buf, n, &dir, nil) == 0)
843 error("internal error: stat error in seek");
844 off = dir.length + o.v;
853 *(vlong*)arg[0] = off;
863 validaddr(arg[0], BY2V, 1);
888 validstat(uchar *s, int n)
893 if(statcheck(s, n) < 0)
895 /* verify that name entry is acceptable */
896 s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
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.
909 /* name could be '/' */
910 if(strcmp(buf, "/") != 0)
923 s = strrchr(p->s, '/');
936 validaddr(arg[1], l, 1);
937 c = fdtochan(arg[0], -1, 0, 1);
942 l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
956 validaddr(arg[1], l, 1);
957 validaddr(arg[0], 1, 0);
958 c = namec((char*)arg[0], Aaccess, 0, 0);
963 l = devtab[c->type]->stat(c, (uchar*)arg[1], l);
964 name = pathlast(c->path);
966 l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]);
978 validaddr(arg[0], 1, 0);
980 c = namec((char*)arg[0], Atodir, 0, 0);
987 bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
990 Chan *c0, *c1, *ac, *bc;
998 if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
1002 validaddr((ulong)spec, 1, 0);
1003 spec = validnamedup(spec, 1);
1009 if(up->pgrp->noattach)
1013 bc = fdtochan(fd, ORDWR, 0, 1);
1022 ac = fdtochan(afd, ORDWR, 0, 1);
1024 bogus.flags = flag & MCACHE;
1026 bogus.authchan = ac;
1028 ret = devno('M', 0);
1029 c0 = devtab[ret]->attach((char*)&bogus);
1030 poperror(); /* ac bc */
1036 validaddr((ulong)arg0, 1, 0);
1037 c0 = namec(arg0, Abind, 0, 0);
1045 validaddr((ulong)arg1, 1, 0);
1046 c1 = namec(arg1, Amount, 0, 0);
1052 ret = cmount(&c0, c1, flag, spec);
1069 return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
1073 sysmount(ulong *arg)
1075 return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
1079 sys_mount(ulong *arg)
1081 return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
1085 sysunmount(ulong *arg)
1087 Chan *cmount, *cmounted;
1091 validaddr(arg[1], 1, 0);
1092 cmount = namec((char *)arg[1], Amount, 0, 0);
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
1107 validaddr(arg[0], 1, 0);
1108 cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
1110 cunmount(cmount, cmounted);
1119 syscreate(ulong *arg)
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]);
1139 sysremove(ulong *arg)
1143 validaddr(arg[0], 1, 0);
1144 c = namec((char*)arg[0], Aremove, 0, 0);
1146 * Removing mount points is disallowed to avoid surprises
1147 * (which should be removed: the mount point or the mounted Chan?).
1154 c->type = 0; /* see below */
1158 devtab[c->type]->remove(c);
1160 * Remove clunks the fid, but we need to recover the Chan
1161 * so fake it up. rootclose() is known to be a nop.
1170 wstat(Chan *c, uchar *d, int nd)
1181 * Renaming mount points is disallowed to avoid surprises
1182 * (which should be renamed? the mount point or the mounted Chan?).
1184 dirname(d, &namelen);
1186 nameerror(chanpath(c), Eismtpt);
1188 l = devtab[c->type]->wstat(c, d, nd);
1195 syswstat(ulong *arg)
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);
1209 sysfwstat(ulong *arg)
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);
1222 packoldstat(uchar *buf, Dir *d)
1227 /* lay down old stat buffer - grotty code but it's temporary */
1229 strncpy((char*)p, d->name, 28);
1231 strncpy((char*)p, d->uid, 28);
1233 strncpy((char*)p, d->gid, 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 */
1240 PBIT32(p, d->qid.vers);
1244 PBIT32(p, d->atime);
1246 PBIT32(p, d->mtime);
1248 PBIT64(p, d->length);
1256 sys_stat(ulong *arg)
1260 uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1261 char strs[128], *name;
1263 char old[] = "old stat system call - recompile";
1265 validaddr(arg[1], 116, 1);
1266 validaddr(arg[0], 1, 0);
1267 c = namec((char*)arg[0], Aaccess, 0, 0);
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 */
1276 name = pathlast(c->path);
1278 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1279 l = convM2D(buf, l, &d, strs);
1282 packoldstat((uchar*)arg[1], &d);
1290 sys_fstat(ulong *arg)
1295 uchar buf[128]; /* old DIRLEN plus a little should be plenty */
1298 char old[] = "old fstat system call - recompile";
1300 validaddr(arg[1], 116, 1);
1301 c = fdtochan(arg[0], -1, 0, 1);
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 */
1310 name = pathlast(c->path);
1312 l = dirsetname(name, strlen(name), buf, l, sizeof buf);
1313 l = convM2D(buf, l, &d, strs);
1316 packoldstat((uchar*)arg[1], &d);
1326 error("old wstat system call - recompile");
1333 error("old fwstat system call - recompile");