void setswapchan(Chan *c) { uchar dirbuf[sizeof(Dir)+100]; Dir d; int n; if(swapimage.c) { if(swapalloc.free != conf.nswap){ cclose(c); error(Einuse); } cclose(swapimage.c); } /* * if this isn't a file, set the swap space * to be at most the size of the partition */ if(devtab[c->type]->dc != L'M'){ n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf); if(n <= 0){ cclose(c); error("stat failed in setswapchan"); } convM2D(dirbuf, n, &d, nil); if(d.length < conf.nswap*BY2PG){ conf.nswap = d.length/BY2PG; swapalloc.top = &swapalloc.swmap[conf.nswap]; swapalloc.free = conf.nswap; } } swapimage.c = c; }
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; }
static void vbecall(Ureg *u) { Proc *up = externup(); Chan *creg, *cmem; uint32_t pa; cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0); if(waserror()){ cclose(cmem); nexterror(); } creg = namec("/dev/realmode", Aopen, ORDWR, 0); if(waserror()){ cclose(creg); nexterror(); } pa = PADDR(RMBUF); cmem->dev->write(cmem, modebuf, sizeof modebuf, pa); u->trap = 0x10; print("vbecall: sizeof u is %d\n", sizeof *u); creg->dev->write(creg, u, sizeof *u, 0); creg->dev->read(creg, u, sizeof *u, 0); if((u->ax&0xFFFF) != 0x004F) error("vesa bios error"); cmem->dev->read(cmem, modebuf, sizeof modebuf, pa); poperror(); cclose(creg); poperror(); cclose(cmem); }
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 _syspipe(int fd[2]) { Chan *c[2]; Dev *d; static char *datastr[] = {"data", "data1"}; d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0); c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ cclose(c[0]); if(c[1]) cclose(c[1]); nexterror(); } c[1] = cclone(c[0]); if(walk(&c[0], datastr+0, 1, 1, nil) < 0) error(Egreg); if(walk(&c[1], datastr+1, 1, 1, nil) < 0) error(Egreg); c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR); if(newfd2(fd, c) < 0) error(Enofd); poperror(); return 0; }
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; }
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; }
/* must call with d qlocked */ static int aoeidentify(Ctlr *d, SDunit *u) { Chan *c; c = nil; if(waserror()){ if(c) cclose(c); iprint("aoeidentify: %s\n", up->errstr); nexterror(); } uprint("%s/ident", d->path); c = namec(up->genbuf, Aopen, OREAD, 0); devtab[c->type]->read(c, d->ident, sizeof d->ident, 0); poperror(); cclose(c); d->feat = 0; d->smart = 0; identify(d, (ushort*)d->ident); memset(u->inquiry, 0, sizeof u->inquiry); u->inquiry[2] = 2; u->inquiry[3] = 2; u->inquiry[4] = sizeof u->inquiry - 4; memmove(u->inquiry+8, d->model, 40); return 0; }
struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt, int iref) { struct chan *c; c = lookup_fd(fdt, fd, iref, FALSE); if (!c) { /* We lost the info about why there was a problem (we used to track file * group closed too, can add that in later). */ error(EBADF, ERROR_FIXME); } if (chkmnt && (c->flag & CMSG)) { if (iref) cclose(c); error(EBADF, ERROR_FIXME); } if (mode < 0) return c; if ((mode & c->mode) != mode) { if (iref) cclose(c); error(EBADF, "FD access mode failure: chan mode 0x%x, wanted 0x%x (opened with 0 instead of O_READ?)", c->mode, mode); } return c; }
static int32_t wstat(Chan* c, uint8_t* p, usize n) { Proc *up = externup(); int32_t l; usize namelen; if(waserror()){ cclose(c); nexterror(); } /* * Renaming mount points is disallowed to avoid surprises * (which should be renamed? the mount point or the mounted Chan?). */ if(c->ismtpt){ dirname(p, &namelen); if(namelen) nameerror(chanpath(c), Eismtpt); } l = c->dev->wstat(c, p, n); poperror(); cclose(c); return l; }
long sysremove(ulong *arg) { Chan *c; validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aremove, 0, 0); /* * Removing mount points is disallowed to avoid surprises * (which should be removed: the mount point or the mounted Chan?). */ if(c->ismtpt){ cclose(c); error(Eismtpt); } if(waserror()){ c->type = 0; /* see below */ cclose(c); nexterror(); } devtab[c->type]->remove(c); /* * Remove clunks the fid, but we need to recover the Chan * so fake it up. rootclose() is known to be a nop. */ c->type = 0; poperror(); cclose(c); return 0; }
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(); }
/* 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 sysunmount(ulong *arg) { Chan *cmount, *cmounted; cmounted = 0; validaddr(arg[1], 1, 0); cmount = namec((char *)arg[1], Amount, 0, 0); if(waserror()) { cclose(cmount); if(cmounted) cclose(cmounted); nexterror(); } if(arg[0]) { /* * This has to be namec(..., Aopen, ...) because * if arg[0] is something like /srv/cs or /fd/0, * opening it is the only way to get at the real * Chan underneath. */ validaddr(arg[0], 1, 0); cmounted = namec((char*)arg[0], Aopen, OREAD, 0); } cunmount(cmount, cmounted); poperror(); cclose(cmount); if(cmounted) cclose(cmounted); return 0; }
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; }
long sysstat(uint32 *arg) { char *name; Chan *c; uint l; uchar *p; l = arg[2]; p = uvalidaddr(arg[1], l, 1); name = uvalidaddr(arg[0], 1, 0); c = namec(name, Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, p, l); name = pathlast(c->path); if(name) l = dirsetname(name, strlen(name), p, l, arg[2]); poperror(); cclose(c); return l; }
long sys_stat(uint32 *arg) { Chan *c; uint l; uchar buf[128]; /* old DIRLEN plus a little should be plenty */ char strs[128], *name, *elem; Dir d; char old[] = "old stat system call - recompile"; uchar *p; p = uvalidaddr(arg[1], 116, 1); name = uvalidaddr(arg[0], 1, 0); c = namec(name, Aaccess, 0, 0); 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); elem = pathlast(c->path); if(elem) l = dirsetname(elem, strlen(elem), buf, l, sizeof buf); l = convM2D(buf, l, &d, strs); if(l == 0) error(old); packoldstat(p, &d); poperror(); cclose(c); 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; }
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; }
struct chan *fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref) { struct chan *c; c = 0; spin_lock(&f->lock); if (f->closed) { spin_unlock(&f->lock); error("File group closed"); } if (fd < 0 || f->maxfd < fd || (c = f->fd[fd]) == 0) { spin_unlock(&f->lock); set_errno(EBADF); error("Bad FD %d\n", fd); } if (iref) chan_incref(c); spin_unlock(&f->lock); if (chkmnt && (c->flag & CMSG)) { if (iref) cclose(c); error(Ebadusefd); } if (mode < 0 || c->mode == ORDWR) { return c; } if ((mode & OTRUNC) && IS_RDONLY(c->mode)) { if (iref) cclose(c); error(Ebadusefd); } /* TODO: this is probably wrong. if you get this from a dev, in the dev's * open, you are probably saving mode directly, without passing it through * openmode. */ if ((mode & ~OTRUNC) != c->mode) { warn("Trunc mode issue: mode %o, mode minus trunc %o, chan mode %o\n", mode, mode & ~OTRUNC, c->mode); if (iref) cclose(c); error(Ebadusefd); } return c; }
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; }
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; }
void sysunmount(Ar0* ar0, ...) { Proc *up = externup(); char *name, *old; Chan *cmount, *cmounted; va_list list; va_start(list, ar0); /* * int unmount(char* name, char* old); */ name = va_arg(list, char*); old = va_arg(list, char*); cmount = namec(validaddr(old, 1, 0), Amount, 0, 0); va_end(list); cmounted = nil; if(name != nil) { if(waserror()) { cclose(cmount); nexterror(); } /* * This has to be namec(..., Aopen, ...) because * if arg[0] is something like /srv/cs or /fd/0, * opening it is the only way to get at the real * Chan underneath. */ cmounted = namec(validaddr(name, 1, 0), Aopen, OREAD, 0); poperror(); } if(waserror()) { cclose(cmount); if(cmounted != nil) cclose(cmounted); nexterror(); } cunmount(cmount, cmounted); cclose(cmount); if(cmounted != nil) cclose(cmounted); poperror(); ar0->i = 0; }
/* * read disk partition tables so that readnvram via factotum * can see them. */ int readparts(char *disk) { Chan *ctl, *data; snprint(buf, sizeof buf, "%s/ctl", disk); ctl = namecopen(buf, ORDWR); snprint(buf2, sizeof buf2, "%s/data", disk); data = namecopen(buf2, OREAD); if (ctl != nil && data != nil) setpartitions(buf2, ctl, data); cclose(ctl); cclose(data); return 0; }
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 SDev* aoeprobe(char *path, SDev *s) { int n, i; char *p; Chan *c; Ctlr *ctlr; if((p = strrchr(path, '/')) == 0) error(Ebadarg); *p = 0; uprint("%s/ctl", path); *p = '/'; c = namec(up->genbuf, Aopen, OWRITE, 0); if(waserror()) { cclose(c); nexterror(); } n = uprint("discover %s", p+1); devtab[c->type]->write(c, up->genbuf, n, 0); poperror(); cclose(c); for(i = 0;; i += Probeintvl) { if(i > Probemax || waserror()) error(Etimedout); tsleep(&up->sleep, return0, 0, Probeintvl); poperror(); uprint("%s/ident", path); if(waserror()) continue; c = namec(up->genbuf, Aopen, OREAD, 0); poperror(); cclose(c); ctlr = newctlr(path); break; } if(s == nil && (s = malloc(sizeof *s)) == nil) return nil; s->ctlr = ctlr; s->ifc = &sdaoeifc; s->nunit = 1; return s; }
void closepgrp(Pgrp *p) { Mhead **h, **e, *f, *next; if(decref(&p->ref) != 0) return; qlock(&p->debug); wlock(&p->ns); p->pgrpid = -1; e = &p->mnthash[MNTHASH]; for(h = p->mnthash; h < e; h++) { for(f = *h; f; f = next) { wlock(&f->lock); cclose(f->from); mountfree(f->mount); f->mount = nil; next = f->hash; wunlock(&f->lock); putmhead(f); } } wunlock(&p->ns); qunlock(&p->debug); free(p); }
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; }
void fdclose(int fd, int flag) { Proc *up = externup(); int i; Chan *c; Fgrp *f; f = up->fgrp; lock(&f->r.l); c = f->fd[fd]; if(c == nil){ /* can happen for users with shared fd tables */ unlock(&f->r.l); return; } if(flag){ if(c == nil || !(c->flag&flag)){ unlock(&f->r.l); return; } } f->fd[fd] = nil; if(fd == f->maxfd) for(i = fd; --i >= 0 && f->fd[i] == 0; ) f->maxfd = i; unlock(&f->r.l); cclose(c); }
int syscreate(char *path, int mode, uint32_t perm) { ERRSTACK(2); int fd; struct chan *c; if (waserror()) { poperror(); return -1; } openmode(mode & ~O_EXCL); /* error check only; OEXCL okay here */ c = namec(path, Acreate, mode, perm); if (waserror()) { cclose(c); nexterror(); } fd = newfd(c, mode); /* 9ns mode is the O_FLAGS and perm is glibc mode */ if (fd < 0) error(-fd, ERROR_FIXME); poperror(); poperror(); return fd; }