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