Added explicit errno reporting from error() API.
[akaros.git] / kern / src / ns / sysfile.c
index fc15db5..cc983fe 100644 (file)
@@ -40,37 +40,21 @@ struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt,
        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). */
        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). */
-               set_errno(EBADF);
-               error("Bad FD %d\n", fd);
+               error(EBADF, NULL);
        }
        }
-
        if (chkmnt && (c->flag & CMSG)) {
                if (iref)
                        cclose(c);
        if (chkmnt && (c->flag & CMSG)) {
                if (iref)
                        cclose(c);
-               error(Ebadusefd);
+               error(EBADF, NULL);
        }
        }
-
-       if (mode < 0 || c->mode == ORDWR) {
+       if (mode < 0)
                return c;
                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 ((mode & c->mode) != mode) {
                if (iref)
                        cclose(c);
                if (iref)
                        cclose(c);
-               error(Ebadusefd);
+               error(EBADF, "FD access mode failure: chan mode 0x%x, wanted 0x%x",
+                     c->mode, mode);
        }
        }
-
        return c;
 }
 
        return c;
 }
 
@@ -86,10 +70,12 @@ long kchanio(void *vc, void *buf, int n, int mode)
                return -1;
        }
 
                return -1;
        }
 
-       if (IS_RDONLY(mode))
+       if (mode == O_READ)
                r = devtab[c->type].read(c, buf, n, c->offset);
                r = devtab[c->type].read(c, buf, n, c->offset);
-       else
+       else if (mode == O_WRITE)
                r = devtab[c->type].write(c, buf, n, c->offset);
                r = devtab[c->type].write(c, buf, n, c->offset);
+       else
+               error(EFAIL, "kchanio: use only O_READ xor O_WRITE");
 
        spin_lock(&c->lock);
        c->offset += r;
 
        spin_lock(&c->lock);
        c->offset += r;
@@ -106,21 +92,21 @@ int openmode(uint32_t omode)
        /* this is the old plan9 style.  i think they want to turn exec into read,
         * and strip off anything higher, and just return the RD/WR style bits.  not
         * stuff like ORCLOSE.  the lack of OEXCL might be a bug on their part (it's
        /* this is the old plan9 style.  i think they want to turn exec into read,
         * and strip off anything higher, and just return the RD/WR style bits.  not
         * stuff like ORCLOSE.  the lack of OEXCL might be a bug on their part (it's
-        * the only one of their non-RW-related flags that isn't masked out) */
+        * the only one of their non-RW-related flags that isn't masked out).
+        *
+        * Note that we no longer convert OEXEC/O_EXEC to O_READ, and instead return
+        * just the O_ACCMODE bits. */
        if (o >= (OTRUNC | OCEXEC | ORCLOSE | OEXEC))
        if (o >= (OTRUNC | OCEXEC | ORCLOSE | OEXEC))
-               error(Ebadarg);
+               error(EINVAL, NULL);
        o &= ~(OTRUNC | OCEXEC | ORCLOSE);
        if (o > OEXEC)
        o &= ~(OTRUNC | OCEXEC | ORCLOSE);
        if (o > OEXEC)
-               error(Ebadarg);
+               error(EINVAL, NULL);
        if (o == OEXEC)
                return OREAD;
        return o;
 #endif
        /* no error checking (we have a shitload of flags anyway), and we return the
         * basic access modes (RD/WR/ETC) */
        if (o == OEXEC)
                return OREAD;
        return o;
 #endif
        /* no error checking (we have a shitload of flags anyway), and we return the
         * basic access modes (RD/WR/ETC) */
-       if (omode == O_EXEC) {
-       return O_RDONLY;
-       }
        return omode & O_ACCMODE;
 }
 
        return omode & O_ACCMODE;
 }
 
@@ -179,7 +165,7 @@ int syscreate(char *path, int mode, uint32_t perm)
                return -1;
        }
 
                return -1;
        }
 
-       openmode(mode & ~OEXCL);        /* error check only; OEXCL okay here */
+       openmode(mode & ~O_EXCL);       /* error check only; OEXCL okay here */
        c = namec(path, Acreate, mode, perm);
        if (waserror()) {
                cclose(c);
        c = namec(path, Acreate, mode, perm);
        if (waserror()) {
                cclose(c);
@@ -187,7 +173,7 @@ int syscreate(char *path, int mode, uint32_t perm)
        }
        fd = newfd(c, mode);    /* 9ns mode is the O_FLAGS and perm is glibc mode */
        if (fd < 0)
        }
        fd = newfd(c, mode);    /* 9ns mode is the O_FLAGS and perm is glibc mode */
        if (fd < 0)
-               error(Enofd);
+               error(fd, NULL);
        poperror();
 
        poperror();
        poperror();
 
        poperror();
@@ -207,12 +193,12 @@ int sysdup(int old)
        c = fdtochan(&current->open_files, old, -1, 0, 1);
        if (c->qid.type & QTAUTH) {
                cclose(c);
        c = fdtochan(&current->open_files, old, -1, 0, 1);
        if (c->qid.type & QTAUTH) {
                cclose(c);
-               error(Eperm);
+               error(EPERM, NULL);
        }
        fd = newfd(c, 0);
        if (fd < 0) {
                cclose(c);
        }
        fd = newfd(c, 0);
        if (fd < 0) {
                cclose(c);
-               error(Enofd);
+               error(fd, NULL);
        }
        poperror();
        return fd;
        }
        poperror();
        return fd;
@@ -234,14 +220,14 @@ int sys_dup_to(struct proc *from_proc, unsigned int from_fd,
        c = fdtochan(&from_proc->open_files, from_fd, -1, 0, 1);
        if (c->qid.type & QTAUTH) {
                cclose(c);
        c = fdtochan(&from_proc->open_files, from_fd, -1, 0, 1);
        if (c->qid.type & QTAUTH) {
                cclose(c);
-               error(Eperm);
+               error(EPERM, NULL);
        }
        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)
        }
        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("Can't insert FD %d into FDG", to_fd);
+               error(EFAIL, "Can't insert FD %d into FDG", to_fd);
        poperror();
        return 0;
 }
        poperror();
        return 0;
 }
@@ -262,7 +248,7 @@ char *sysfd2path(int fd)
                s = kzmalloc(c->name->len + 1, 0);
                if (s == NULL) {
                        cclose(c);
                s = kzmalloc(c->name->len + 1, 0);
                if (s == NULL) {
                        cclose(c);
-                       error(Enomem);
+                       error(ENOMEM, NULL);
                }
                memmove(s, c->name->s, c->name->len + 1);
        }
                }
                memmove(s, c->name->s, c->name->len + 1);
        }
@@ -282,7 +268,7 @@ int sysfauth(int fd, char *aname)
        }
 
        validname(aname, 0);
        }
 
        validname(aname, 0);
-       c = fdtochan(&current->open_files, fd, ORDWR, 0, 1);
+       c = fdtochan(&current->open_files, fd, O_RDWR, 0, 1);
        if (waserror()) {
                cclose(c);
                nexterror();
        if (waserror()) {
                cclose(c);
                nexterror();
@@ -301,7 +287,7 @@ int sysfauth(int fd, char *aname)
 
        fd = newfd(ac, 0);
        if (fd < 0)
 
        fd = newfd(ac, 0);
        if (fd < 0)
-               error(Enofd);
+               error(fd, NULL);
        poperror();     /* ac */
 
        poperror();
        poperror();     /* ac */
 
        poperror();
@@ -322,9 +308,9 @@ int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
 
        /* check there's a NUL in the version string */
        if (arglen == 0 || memchr(vers, 0, arglen) == 0)
 
        /* check there's a NUL in the version string */
        if (arglen == 0 || memchr(vers, 0, arglen) == 0)
-               error(Ebadarg);
+               error(EINVAL, NULL);
 
 
-       c = fdtochan(&current->open_files, fd, ORDWR, 0, 1);
+       c = fdtochan(&current->open_files, fd, O_RDWR, 0, 1);
        if (waserror()) {
                cclose(c);
                nexterror();
        if (waserror()) {
                cclose(c);
                nexterror();
@@ -346,8 +332,8 @@ int syspipe(int fd[2])
        struct chan *c[2];
        static char *names[] = { "data", "data1" };
 
        struct chan *c[2];
        static char *names[] = { "data", "data1" };
 
-       d = &devtab[devno('|', 0)];
-       c[0] = namec("#|", Atodir, 0, 0);
+       d = &devtab[devno("pipe", 0)];
+       c[0] = 0;
        c[1] = 0;
        fd[0] = -1;
        fd[1] = -1;
        c[1] = 0;
        fd[0] = -1;
        fd[1] = -1;
@@ -367,19 +353,20 @@ int syspipe(int fd[2])
                poperror();
                return -1;
        }
                poperror();
                return -1;
        }
+       c[0] = namec("#pipe", Atodir, 0, 0);
        c[1] = cclone(c[0]);
        c[1] = cclone(c[0]);
-       if (walk(&c[0], &names[0], 1, 1, NULL) < 0)
-               error(Egreg);
-       if (walk(&c[1], &names[1], 1, 1, NULL) < 0)
-               error(Egreg);
-       c[0] = d->open(c[0], ORDWR);
-       c[1] = d->open(c[1], ORDWR);
+       if (walk(&c[0], &names[0], 1, FALSE, NULL) < 0)
+               error(EINVAL, NULL);
+       if (walk(&c[1], &names[1], 1, FALSE, NULL) < 0)
+               error(EINVAL, NULL);
+       c[0] = d->open(c[0], O_RDWR);
+       c[1] = d->open(c[1], O_RDWR);
        fd[0] = newfd(c[0], 0);
        if (fd[0] < 0)
        fd[0] = newfd(c[0], 0);
        if (fd[0] < 0)
-               error(Enofd);
+               error(fd[0], NULL);
        fd[1] = newfd(c[1], 0);
        if (fd[1] < 0)
        fd[1] = newfd(c[1], 0);
        if (fd[1] < 0)
-               error(Enofd);
+               error(fd[1], NULL);
        poperror();
        return 0;
 }
        poperror();
        return 0;
 }
@@ -415,7 +402,7 @@ long bindmount(struct chan *c, char *old, int flag, char *spec)
        struct chan *c1;
 
        if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER))
        struct chan *c1;
 
        if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER))
-               error(Ebadarg);
+               error(EINVAL, NULL);
 
        c1 = namec(old, Amount, 0, 0);
        if (waserror()) {
 
        c1 = namec(old, Amount, 0, 0);
        if (waserror()) {
@@ -478,14 +465,14 @@ int sysmount(int fd, int afd, char *old, int flags, char *spec)
                poperror();
                return -1;
        }
                poperror();
                return -1;
        }
-       bc.c = fdtochan(&current->open_files, fd, ORDWR, 0, 1);
+       bc.c = fdtochan(&current->open_files, fd, O_RDWR, 0, 1);
        if (afd >= 0)
        if (afd >= 0)
-               ac.c = fdtochan(&current->open_files, afd, ORDWR, 0, 1);
+               ac.c = fdtochan(&current->open_files, afd, O_RDWR, 0, 1);
        mntparam.chan = bc.c;
        mntparam.authchan = ac.c;
        mntparam.spec = spec;
        mntparam.flags = flags;
        mntparam.chan = bc.c;
        mntparam.authchan = ac.c;
        mntparam.spec = spec;
        mntparam.flags = flags;
-       c0.c = devtab[devno('M', 0)].attach((char *)&mntparam);
+       c0.c = devtab[devno("mnt", 0)].attach((char *)&mntparam);
 
        r = bindmount(c0.c, old, flags, spec);
        poperror();
 
        r = bindmount(c0.c, old, flags, spec);
        poperror();
@@ -523,7 +510,7 @@ int sysunmount(char *src_path, char *onto_path)
                 * opening it is the only way to get at the real
                 * Chan underneath.
                 */
                 * opening it is the only way to get at the real
                 * Chan underneath.
                 */
-               cmounted.c = namec(src_path, Aopen, OREAD, 0);
+               cmounted.c = namec(src_path, Aopen, O_READ, 0);
        }
 
        cunmount(cmount.c, cmounted.c);
        }
 
        cunmount(cmount.c, cmounted.c);
@@ -533,32 +520,40 @@ int sysunmount(char *src_path, char *onto_path)
        return 0;
 }
 
        return 0;
 }
 
-int sysopen(char *path, int vfs_flags)
+int sysopenat(int fromfd, char *path, int vfs_flags)
 {
 {
-       ERRSTACK(2);
+       ERRSTACK(1);
        int fd;
        int fd;
-       struct chan *c;
+       struct chan *c = 0, *from = 0;
 
        if (waserror()) {
 
        if (waserror()) {
+               cclose(c);
                poperror();
                return -1;
        }
                poperror();
                return -1;
        }
-
        openmode(vfs_flags);    /* error check only */
        openmode(vfs_flags);    /* error check only */
-       c = namec(path, Aopen, vfs_flags, 0);
-       if (waserror()) {
-               cclose(c);
-               nexterror();
+       if ((path[0] == '/') || (fromfd == AT_FDCWD)) {
+               c = namec(path, Aopen, vfs_flags, 0);
+       } else {
+               /* We don't cclose from.  namec_from will convert it to the new chan
+                * during the walk process (c).  It'll probably close from internally,
+                * and give us something new for c.  On error, namec_from will cclose
+                * from. */
+               from = fdtochan(&current->open_files, fromfd, -1, FALSE, TRUE);
+               c = namec_from(from, path, Aopen, vfs_flags, 0);
        }
        fd = newfd(c, vfs_flags);
        if (fd < 0)
        }
        fd = newfd(c, vfs_flags);
        if (fd < 0)
-               error(Enofd);
-       poperror();
-
+               error(fd, NULL);
        poperror();
        return fd;
 }
 
        poperror();
        return fd;
 }
 
+int sysopen(char *path, int vfs_flags)
+{
+       return sysopenat(AT_FDCWD, path, vfs_flags);
+}
+
 long unionread(struct chan *c, void *va, long n)
 {
        ERRSTACK(1);
 long unionread(struct chan *c, void *va, long n)
 {
        ERRSTACK(1);
@@ -591,7 +586,8 @@ long unionread(struct chan *c, void *va, long n)
                        } else {
                                if (c->umc == NULL) {
                                        c->umc = cclone(mount->to);
                        } else {
                                if (c->umc == NULL) {
                                        c->umc = cclone(mount->to);
-                                       c->umc = devtab[c->umc->type].open(c->umc, OREAD);
+                                       c->umc = devtab[c->umc->type].open(c->umc,
+                                                                          O_READ);
                                }
 
                                nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
                                }
 
                                nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
@@ -643,14 +639,14 @@ static long rread(int fd, void *va, long n, int64_t * offp)
                return -1;
        }
 
                return -1;
        }
 
-       c = fdtochan(&current->open_files, fd, OREAD, 1, 1);
+       c = fdtochan(&current->open_files, fd, O_READ, 1, 1);
        if (waserror()) {
                cclose(c);
                nexterror();
        }
 
        if (n < 0)
        if (waserror()) {
                cclose(c);
                nexterror();
        }
 
        if (n < 0)
-               error(Etoosmall);
+               error(EINVAL, NULL);
 
        dir = c->qid.type & QTDIR;
 
 
        dir = c->qid.type & QTDIR;
 
@@ -694,7 +690,7 @@ static long rread(int fd, void *va, long n, int64_t * offp)
                } else
                        off = *offp;
                if (off < 0)
                } else
                        off = *offp;
                if (off < 0)
-                       error(Enegoff);
+                       error(EINVAL, NULL);
                if (off == 0) {
                        if (offp == NULL) {
                                spin_lock(&c->lock);
                if (off == 0) {
                        if (offp == NULL) {
                                spin_lock(&c->lock);
@@ -751,7 +747,7 @@ void read_exactly_n(struct chan *c, void *vp, long n)
                nn = devtab[c->type].read(c, p, n, c->offset);
                printd("readn: Got %d@%lld\n", nn, c->offset);
                if (nn == 0)
                nn = devtab[c->type].read(c, p, n, c->offset);
                printd("readn: Got %d@%lld\n", nn, c->offset);
                if (nn == 0)
-                       error("%s: wanted %d, got %d", Eshort, want, total);
+                       error(EFAIL, "%s: wanted %d, got %d", Eshort, want, total);
                spin_lock(&c->lock);
                c->offset += nn;
                spin_unlock(&c->lock);
                spin_lock(&c->lock);
                c->offset += nn;
                spin_unlock(&c->lock);
@@ -817,17 +813,19 @@ int64_t sysseek(int fd, int64_t off, int whence)
                nexterror();
        }
 
                nexterror();
        }
 
-       if (devtab[c->type].dc == '|')
-               error(Eisstream);
+       /* TODO: WTF is this?  Is pipe magically the only device that isn't
+        * seekable? */
+       if (!strcmp(devtab[c->type].name, "pipe"))
+               error(EINVAL, NULL);
 
        switch (whence) {
                case 0:
                        if (c->qid.type & QTDIR) {
                                if (off != 0)
 
        switch (whence) {
                case 0:
                        if (c->qid.type & QTDIR) {
                                if (off != 0)
-                                       error(Eisdir);
+                                       error(EISDIR, NULL);
                                unionrewind(c);
                        } else if (off < 0)
                                unionrewind(c);
                        } else if (off < 0)
-                               error(Enegoff);
+                               error(EINVAL, NULL);
                        spin_lock(&c->lock);    /* lock for int64_t assignment */
                        c->offset = off;
                        spin_unlock(&c->lock);
                        spin_lock(&c->lock);    /* lock for int64_t assignment */
                        c->offset = off;
                        spin_unlock(&c->lock);
@@ -835,12 +833,12 @@ int64_t sysseek(int fd, int64_t off, int whence)
 
                case 1:
                        if (c->qid.type & QTDIR)
 
                case 1:
                        if (c->qid.type & QTDIR)
-                               error(Eisdir);
+                               error(EISDIR, NULL);
                        spin_lock(&c->lock);    /* lock for read/write update */
                        off += c->offset;
                        if (off < 0) {
                                spin_unlock(&c->lock);
                        spin_lock(&c->lock);    /* lock for read/write update */
                        off += c->offset;
                        if (off < 0) {
                                spin_unlock(&c->lock);
-                               error(Enegoff);
+                               error(EINVAL, NULL);
                        }
                        c->offset = off;
                        spin_unlock(&c->lock);
                        }
                        c->offset = off;
                        spin_unlock(&c->lock);
@@ -848,21 +846,21 @@ int64_t sysseek(int fd, int64_t off, int whence)
 
                case 2:
                        if (c->qid.type & QTDIR)
 
                case 2:
                        if (c->qid.type & QTDIR)
-                               error(Eisdir);
+                               error(EISDIR, NULL);
                        dir = chandirstat(c);
                        if (dir == NULL)
                        dir = chandirstat(c);
                        if (dir == NULL)
-                               error("internal error: stat error in seek");
+                               error(EFAIL, "internal error: stat error in seek");
                        off += dir->length;
                        kfree(dir);
                        if (off < 0)
                        off += dir->length;
                        kfree(dir);
                        if (off < 0)
-                               error(Enegoff);
+                               error(EINVAL, NULL);
                        spin_lock(&c->lock);    /* lock for read/write update */
                        c->offset = off;
                        spin_unlock(&c->lock);
                        break;
 
                default:
                        spin_lock(&c->lock);    /* lock for read/write update */
                        c->offset = off;
                        spin_unlock(&c->lock);
                        break;
 
                default:
-                       error(Ebadarg);
+                       error(EINVAL, NULL);
                        break;
        }
        poperror();
                        break;
        }
        poperror();
@@ -879,7 +877,7 @@ void validstat(uint8_t * s, int n, int slashok)
        char buf[64];
 
        if (statcheck(s, n) < 0)
        char buf[64];
 
        if (statcheck(s, n) < 0)
-               error(Ebadstat);
+               error(EINVAL, NULL);
        /* verify that name entry is acceptable */
        s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
        /*
        /* verify that name entry is acceptable */
        s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
        /*
@@ -990,24 +988,24 @@ static long rwrite(int fd, void *va, long n, int64_t * offp)
                poperror();
                return -1;
        }
                poperror();
                return -1;
        }
-       c = fdtochan(&current->open_files, fd, OWRITE, 1, 1);
+       c = fdtochan(&current->open_files, fd, O_WRITE, 1, 1);
        if (waserror()) {
                cclose(c);
                nexterror();
        }
        if (c->qid.type & QTDIR)
        if (waserror()) {
                cclose(c);
                nexterror();
        }
        if (c->qid.type & QTDIR)
-               error(Eisdir);
+               error(EISDIR, NULL);
 
        if (n < 0)
 
        if (n < 0)
-               error(Etoosmall);
+               error(EINVAL, NULL);
 
        if (offp == NULL) {
                /* append changes the offset to the end, and even if we fail later, this
                 * change will persist */
 
        if (offp == NULL) {
                /* append changes the offset to the end, and even if we fail later, this
                 * change will persist */
-               if (c->flag & CAPPEND) {
+               if (c->flag & O_APPEND) {
                        dir = chandirstat(c);
                        if (!dir)
                        dir = chandirstat(c);
                        if (!dir)
-                               error("internal error: stat error in append write");
+                               error(EFAIL, "internal error: stat error in append write");
                        spin_lock(&c->lock);    /* legacy lock for int64 assignment */
                        c->offset = dir->length;
                        spin_unlock(&c->lock);
                        spin_lock(&c->lock);    /* legacy lock for int64 assignment */
                        c->offset = dir->length;
                        spin_unlock(&c->lock);
@@ -1029,7 +1027,7 @@ static long rwrite(int fd, void *va, long n, int64_t * offp)
                nexterror();
        }
        if (off < 0)
                nexterror();
        }
        if (off < 0)
-               error(Enegoff);
+               error(EINVAL, NULL);
        m = devtab[c->type].write(c, va, n, off);
        poperror();
 
        m = devtab[c->type].write(c, va, n, off);
        poperror();
 
@@ -1215,11 +1213,11 @@ static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
        }
 
        if (i != ts)
        }
 
        if (i != ts)
-               error("bad directory format");
+               error(EFAIL, "bad directory format");
 
        *d = kzmalloc(n * sizeof(**d) + ss, 0);
        if (*d == NULL)
 
        *d = kzmalloc(n * sizeof(**d) + ss, 0);
        if (*d == NULL)
-               error(Enomem);
+               error(ENOMEM, NULL);
 
        /*
         * then convert all buffers
 
        /*
         * then convert all buffers
@@ -1231,7 +1229,7 @@ static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
                if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
                        kfree(*d);
                        *d = NULL;
                if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
                        kfree(*d);
                        *d = NULL;
-                       error("bad directory entry");
+                       error(EFAIL, "bad directory entry");
                }
                nn++;
                s += m;
                }
                nn++;
                s += m;
@@ -1253,7 +1251,7 @@ long sysdirread(int fd, struct kdirent **d)
        }
        buf = kzmalloc(DIRREADLIM, 0);
        if (buf == NULL)
        }
        buf = kzmalloc(DIRREADLIM, 0);
        if (buf == NULL)
-               error(Enomem);
+               error(ENOMEM, NULL);
        if (waserror()) {
                kfree(buf);
                nexterror();
        if (waserror()) {
                kfree(buf);
                nexterror();
@@ -1327,11 +1325,11 @@ int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
                 * switch_to() also loads the cr3. */
                new_proc->pgrp = newpgrp();
                old_current = switch_to(new_proc);
                 * switch_to() also loads the cr3. */
                new_proc->pgrp = newpgrp();
                old_current = switch_to(new_proc);
-               new_proc->slash = namec("#r", Atodir, 0, 0);
+               new_proc->slash = namec("#root", Atodir, 0, 0);
                if (!new_proc->slash)
                        panic("no root device");
                switch_back(new_proc, old_current);
                if (!new_proc->slash)
                        panic("no root device");
                switch_back(new_proc, old_current);
-               /* Want the name to be "/" instead of "#r" */
+               /* Want the name to be "/" instead of "#root" */
                cnameclose(new_proc->slash->name);
                new_proc->slash->name = newcname("/");
                new_proc->dot = cclone(new_proc->slash);
                cnameclose(new_proc->slash->name);
                new_proc->slash->name = newcname("/");
                new_proc->dot = cclone(new_proc->slash);
@@ -1425,14 +1423,10 @@ int fd_setfl(int fd, int flags)
        c = fdtochan(&current->open_files, fd, -1, 0, 1);
        if (cexternal_flags_differ(flags, c->flag, O_CLOEXEC)) {
                /* TODO: The whole CCEXEC / O_CLOEXEC on 9ns needs work */
        c = fdtochan(&current->open_files, fd, -1, 0, 1);
        if (cexternal_flags_differ(flags, c->flag, O_CLOEXEC)) {
                /* TODO: The whole CCEXEC / O_CLOEXEC on 9ns needs work */
-               set_errno(EINVAL);
-               error("can't toggle O_CLOEXEC with setfl");
-       }
-       if (cexternal_flags_differ(flags, c->flag, O_NONBLOCK)) {
-               /* If we want to let them toggle NONBLOCK, it'd require a device op */
-               set_errno(EINVAL);
-               error("can't set O_NONBLOCK, use a device-specific ctl command");
+               error(EINVAL, "can't toggle O_CLOEXEC with setfl");
        }
        }
+       if (cexternal_flags_differ(flags, c->flag, O_PATH))
+               error(EINVAL, "can't toggle O_PATH with setfl");
        c->flag = (c->flag & ~CEXTERNAL_FLAGS) | (flags & CEXTERNAL_FLAGS);
        cclose(c);
        poperror();
        c->flag = (c->flag & ~CEXTERNAL_FLAGS) | (flags & CEXTERNAL_FLAGS);
        cclose(c);
        poperror();