/* Could pass in the fdt instead of the proc, but we used to need the to_proc * for now so we can claim a VFS FD. Careful, we don't close the old chan. */ int sys_dup_to(struct proc *from_proc, unsigned int from_fd, struct proc *to_proc, unsigned int to_fd) { ERRSTACK(1); int ret; struct chan *c; if (waserror()) { poperror(); return -1; } c = fdtochan(&from_proc->open_files, from_fd, -1, 0, 1); if (c->qid.type & QTAUTH) { cclose(c); error(EPERM, ERROR_FIXME); } ret = insert_obj_fdt(&to_proc->open_files, c, to_fd, 0, TRUE, FALSE); /* drop the ref from fdtochan. if insert succeeded, there is one other ref * stored in the FDT */ cclose(c); if (ret < 0) error(EFAIL, "Can't insert FD %d into FDG", to_fd); poperror(); return 0; }
long sys_fstat(ulong *arg) { Chan *c; char *name; uint l; uchar buf[128]; /* old DIRLEN plus a little should be plenty */ char strs[128]; Dir d; char old[] = "old fstat system call - recompile"; validaddr(arg[1], 116, 1); c = fdtochan(arg[0], -1, 0, 1); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, sizeof buf); /* buf contains a new stat buf; convert to old. yuck. */ if(l <= BIT16SZ) /* buffer too small; time to face reality */ error(old); name = pathlast(c->path); if(name) l = dirsetname(name, strlen(name), buf, l, sizeof buf); l = convM2D(buf, l, &d, strs); if(l == 0) error(old); packoldstat((uchar*)arg[1], &d); poperror(); cclose(c); return 0; }
void sysfwstat(Ar0* ar0, ...) { Chan *c; int fd; uint8_t *p; usize n; va_list list; va_start(list, ar0); /* * int fwstat(int fd, uchar* edir, int nedir); * should really be * usize wstat(int fd, uchar* edir, usize nedir); * but returning an unsigned is probably too * radical. */ fd = va_arg(list, int); p = va_arg(list, uint8_t*); n = va_arg(list, usize); p = validaddr(p, n, 0); validstat(p, n); c = fdtochan(fd, -1, 1, 1); va_end(list); ar0->l = wstat(c, p, n); }
uintptr sysfversion(va_list list) { uint msize, arglen; char *vers; Chan *c; int fd; fd = va_arg(list, int); msize = va_arg(list, uint); vers = va_arg(list, char*); arglen = va_arg(list, uint); validaddr((uintptr)vers, arglen, 1); /* check there's a NUL in the version string */ if(arglen==0 || memchr(vers, 0, arglen)==0) error(Ebadarg); c = fdtochan(fd, ORDWR, 0, 1); if(waserror()){ cclose(c); nexterror(); } msize = mntversion(c, vers, msize, arglen); cclose(c); poperror(); return msize; }
void sysfversion(Ar0* ar0, va_list list) { Chan *c; char *version; int fd; u32int msize; usize nversion; /* * int fversion(int fd, int bufsize, char *version, int nversion); * should be * usize fversion(int fd, u32int msize, char *version, usize nversion); */ fd = va_arg(list, int); msize = va_arg(list, u32int); version = va_arg(list, char*); nversion = va_arg(list, usize); version = validaddr(version, nversion, 1); /* check there's a NUL in the version string */ if(nversion == 0 || memchr(version, 0, nversion) == nil) error(Ebadarg); c = fdtochan(fd, ORDWR, 0, 1); if(waserror()){ cclose(c); nexterror(); } ar0->u = mntversion(c, msize, version, nversion); cclose(c); poperror(); }
void sysfd2path(Ar0* ar0, ...) { Chan *c; char *buf; int fd; usize nbuf; va_list list; va_start(list, ar0); /* * int fd2path(int fd, char* buf, int nbuf); * should be * int fd2path(int fd, char* buf, usize nbuf); */ fd = va_arg(list, int); buf = va_arg(list, char*); nbuf = va_arg(list, usize); va_end(list); buf = validaddr(buf, nbuf, 1); c = fdtochan(fd, -1, 0, 1); snprint(buf, nbuf, "%s", chanpath(c)); cclose(c); ar0->i = 0; }
int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen) { ERRSTACK(2); int m; struct chan *c; if (waserror()) { poperror(); return -1; } /* check there's a NUL in the version string */ if (arglen == 0 || memchr(vers, 0, arglen) == 0) error(EINVAL, ERROR_FIXME); c = fdtochan(¤t->open_files, fd, O_RDWR, 0, 1); if (waserror()) { cclose(c); nexterror(); } m = mntversion(c, vers, msize, arglen); poperror(); cclose(c); poperror(); return m; }
long sysfversion(ulong *arg) { char *vers; uint arglen, m, msize; Chan *c; msize = arg[1]; vers = (char*)arg[2]; arglen = arg[3]; validaddr(arg[2], arglen, 1); /* check there's a NUL in the version string */ if(arglen==0 || memchr(vers, 0, arglen)==0) error(Ebadarg); c = fdtochan(arg[0], ORDWR, 0, 1); if(waserror()){ cclose(c); nexterror(); } m = mntversion(c, vers, msize, arglen); cclose(c); poperror(); return m; }
static Chan* dupopen(Chan *c, int omode) { Chan *f; int fd, twicefd; if(c->qid.type & QTDIR){ if(omode != 0) error(Eisdir); c->mode = 0; c->flag |= COPEN; c->offset = 0; return c; } if(c->qid.type & QTAUTH) error(Eperm); twicefd = c->qid.path - 1; fd = twicefd/2; if((twicefd & 1)){ /* ctl file */ f = c; f->mode = openmode(omode); f->flag |= COPEN; f->offset = 0; }else{ /* fd file */ f = fdtochan(up->env->fgrp, fd, openmode(omode), 0, 1); cclose(c); } if(omode & OCEXEC) f->flag |= CCEXEC; return f; }
static long dupread(Chan *c, void *va, long n, vlong offset) { char *a = va; char buf[256]; int fd, twicefd; if(c->qid.type == QTDIR) return devdirread(c, a, n, nil, 0, dupgen); twicefd = c->qid.path - 1; fd = twicefd/2; if(twicefd & 1){ c = fdtochan(up->env->fgrp, fd, -1, 0, 1); if(waserror()){ cclose(c); nexterror(); } progfdprint(c, fd, 0, buf, sizeof buf); poperror(); cclose(c); return readstr((ulong)offset, va, n, buf); } panic("dupread"); return 0; }
long _sysclose(int fd) { fdtochan(fd, -1, 0, 0); fdclose(fd, 0); return 0; }
long sysclose(ulong *arg) { fdtochan(arg[0], -1, 0, 0); fdclose(arg[0], 0); return 0; }
static vlong _sysseek(int fd, vlong off, int whence) { Chan *c; uchar buf[sizeof(Dir)+100]; Dir dir; int n; c = fdtochan(fd, -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } if(devtab[c->type]->dc == '|') error(Eisstream); switch(whence){ case 0: if((c->qid.type & QTDIR) && off != 0) error(Eisdir); if(off < 0) error(Enegoff); c->offset = off; break; case 1: if(c->qid.type & QTDIR) error(Eisdir); lock(&c->ref.lk); /* lock for read/write update */ off = off + c->offset; if(off < 0) error(Enegoff); c->offset = off; unlock(&c->ref.lk); break; case 2: if(c->qid.type & QTDIR) error(Eisdir); n = devtab[c->type]->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); off = dir.length + off; if(off < 0) error(Enegoff); c->offset = off; break; default: error(Ebadarg); } c->uri = 0; c->dri = 0; cclose(c); poperror(); return off; }
long sysfd2path(ulong *arg) { Chan *c; validaddr(arg[1], arg[2], 1); c = fdtochan(arg[0], -1, 0, 1); snprint((char*)arg[1], arg[2], "%s", chanpath(c)); cclose(c); return 0; }
static int64_t sseek(int fd, int64_t offset, int whence) { Proc *up = externup(); Chan *c; uint8_t buf[sizeof(Dir)+100]; Dir dir; int n; c = fdtochan(fd, -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } if(c->dev->dc == '|') error(Eisstream); switch(whence){ case 0: if((c->qid.type & QTDIR) && offset != 0LL) error(Eisdir); c->offset = offset; break; case 1: if(c->qid.type & QTDIR) error(Eisdir); lock(&c->r.l); /* lock for read/write update */ offset += c->offset; c->offset = offset; unlock(&c->r.l); break; case 2: if(c->qid.type & QTDIR) error(Eisdir); n = c->dev->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); offset += dir.length; c->offset = offset; break; default: error(Ebadarg); } c->uri = 0; c->dri = 0; cclose(c); poperror(); return offset; }
long sysfwstat(ulong *arg) { Chan *c; uint l; l = arg[2]; validaddr(arg[1], l, 0); validstat((uchar*)arg[1], l); c = fdtochan(arg[0], -1, 1, 1); return wstat(c, (uchar*)arg[1], l); }
long sysfwstat(uint32 *arg) { Chan *c; uint l; uchar *p; l = arg[2]; p = uvalidaddr(arg[1], l, 0); validstat(p, l); c = fdtochan(arg[0], -1, 1, 1); return wstat(c, p, l); }
long sysfd2path(uint32 *arg) { Chan *c; char *buf; buf = uvalidaddr(arg[1], arg[2], 1); c = fdtochan(arg[0], -1, 0, 1); snprint(buf, arg[2], "%s", chanpath(c)); cclose(c); return 0; }
static long dowrite(uint32 *arg, vlong *offp) { Chan *c; long m, n; vlong off; uchar *p; p = uvalidaddr(arg[1], arg[2], 0); n = 0; c = fdtochan(arg[0], OWRITE, 1, 1); if(waserror()) { if(offp == nil){ lock(&c->ref.lk); c->offset -= n; unlock(&c->ref.lk); } cclose(c); nexterror(); } if(c->qid.type & QTDIR) error(Eisdir); n = arg[2]; if(offp == nil){ /* use and maintain channel's offset */ lock(&c->ref.lk); off = c->offset; c->offset += n; unlock(&c->ref.lk); }else off = *offp; if(off < 0) error(Enegoff); m = devtab[c->type]->write(c, p, n, off); if(offp == nil && m < n){ lock(&c->ref.lk); c->offset -= n - m; unlock(&c->ref.lk); } poperror(); cclose(c); return m; }
long _sysfd2path(int fd, char *buf, uint nbuf) { Chan *c; c = fdtochan(fd, -1, 0, 1); if(c->name == nil) snprint(buf, nbuf, "<null>"); else snprint(buf, nbuf, "%s", c->name->s); cclose(c); return 0; }
void sysdup(Ar0* ar0, ...) { Proc *up = externup(); int nfd, ofd; Chan *nc, *oc; Fgrp *f; va_list list; va_start(list, ar0); /* * int dup(int oldfd, int newfd); * * Close after dup'ing, so date > #d/1 works */ ofd = va_arg(list, int); oc = fdtochan(ofd, -1, 0, 1); nfd = va_arg(list, int); va_end(list); if(nfd != -1){ f = up->fgrp; lock(&f->r.l); if(nfd < 0 || growfd(f, nfd) < 0) { unlockfgrp(f); cclose(oc); error(Ebadfd); } if(nfd > f->maxfd) f->maxfd = nfd; nc = f->fd[nfd]; f->fd[nfd] = oc; unlockfgrp(f); if(nc != nil) cclose(nc); }else{ if(waserror()) { cclose(oc); nexterror(); } nfd = newfd(oc); if(nfd < 0) error(Enofd); poperror(); } ar0->i = nfd; }
static long kwrite(int fd, void *buf, long nn, vlong *offp) { Chan *c; long m, n; vlong off; n = 0; c = fdtochan(fd, OWRITE, 1, 1); if(waserror()) { if(offp == nil){ lock(&c->ref.lk); c->offset -= n; unlock(&c->ref.lk); } cclose(c); nexterror(); } if(c->qid.type & QTDIR) error(Eisdir); n = nn; if(offp == nil){ /* use and maintain channel's offset */ lock(&c->ref.lk); off = c->offset; c->offset += n; unlock(&c->ref.lk); }else off = *offp; if(off < 0) error(Enegoff); m = devtab[c->type]->write(c, buf, n, off); if(offp == nil && m < n){ lock(&c->ref.lk); c->offset -= n - m; unlock(&c->ref.lk); } poperror(); cclose(c); return m; }
static Chan * devlogfskopen(char *name, char *suffix, int mode) { Chan *c; char *fn; int fd; fn = estrconcat(name, suffix, 0); fd = kopen(fn, mode); logfsfreemem(fn); if (fd < 0) error(up->env->errstr); c = fdtochan(up->env->fgrp, fd, mode, 0, 1); kclose(fd); return c; }
int kfgrpclose(Fgrp *f, int fd) { if(waserror()) return -1; /* * Take no reference on the chan because we don't really need the * data structure, and are calling fdtochan only for error checks. * fdclose takes care of processes racing through here. */ fdtochan(f, fd, -1, 0, 0); fdclose(f, fd); poperror(); return 0; }
void sysfauth(Ar0* ar0, va_list list) { Chan *c, *ac; char *aname; int fd; /* * int fauth(int fd, char *aname); */ fd = va_arg(list, int); aname = va_arg(list, char*); aname = validaddr(aname, 1, 0); aname = validnamedup(aname, 1); if(waserror()){ free(aname); nexterror(); } c = fdtochan(fd, ORDWR, 0, 1); if(waserror()){ cclose(c); nexterror(); } ac = mntauth(c, aname); /* at this point ac is responsible for keeping c alive */ cclose(c); poperror(); /* c */ free(aname); poperror(); /* aname */ if(waserror()){ cclose(ac); nexterror(); } fd = newfd(ac); if(fd < 0) error(Enofd); poperror(); /* ac */ /* always mark it close on exec */ ac->flag |= CCEXEC; ar0->i = fd; }
static int32_t write(int fd, void *p, int32_t n, int64_t off, int ispwrite) { Proc *up = externup(); int32_t r; Chan *c; r = n; p = validaddr(p, n, 0); n = 0; c = fdtochan(fd, OWRITE, 1, 1); if(waserror()) { if(!ispwrite){ lock(&c->r.l); c->offset -= n; unlock(&c->r.l); } cclose(c); nexterror(); } if(c->qid.type & QTDIR) error(Eisdir); n = r; if(off == ~0LL){ /* use and maintain channel's offset */ lock(&c->r.l); off = c->offset; c->offset += n; unlock(&c->r.l); } r = c->dev->write(c, p, n, off); if(!ispwrite && r < n){ lock(&c->r.l); c->offset -= n - r; unlock(&c->r.l); } poperror(); cclose(c); return r; }
long sysfstat(ulong *arg) { Chan *c; uint l; l = arg[2]; validaddr(arg[1], l, 1); c = fdtochan(arg[0], -1, 0, 1); if(waserror()) { cclose(c); nexterror(); } l = devtab[c->type]->stat(c, (uchar*)arg[1], l); poperror(); cclose(c); return l; }
long _sysfstat(int fd, void *buf, long n) { Chan *c; uint l; l = n; validaddr(buf, l, 1); c = fdtochan(fd, -1, 0, 1); if(waserror()) { cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, l); poperror(); cclose(c); return l; }
void sysclose(Ar0* ar0, ...) { int fd; va_list list; va_start(list, ar0); /* * int close(int fd); */ fd = va_arg(list, int); va_end(list); fdtochan(fd, -1, 0, 0); fdclose(fd, 0); ar0->i = 0; }
static long kread(int fd, void *buf, long n, vlong *offp) { int dir; Chan *c; vlong off; c = fdtochan(fd, OREAD, 1, 1); if(waserror()) { cclose(c); nexterror(); } dir = c->qid.type&QTDIR; /* * The offset is passed through on directories, normally. sysseek complains but * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue. */ if(offp == nil) /* use and maintain channel's offset */ off = c->offset; else off = *offp; if(off < 0) error(Enegoff); if(dir && c->umh) n = unionread(c, buf, n); else n = devtab[c->type]->read(c, buf, n, off); if(offp == nil){ lock(&c->ref.lk); c->offset += n; unlock(&c->ref.lk); } poperror(); cclose(c); return n; }