Fix Plan 9 partial write() return values
[akaros.git] / kern / src / ns / sysfile.c
index 11f3639..16cd623 100644 (file)
@@ -79,7 +79,8 @@ struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt,
        if ((mode & c->mode) != mode) {
                if (iref)
                        cclose(c);
        if ((mode & c->mode) != mode) {
                if (iref)
                        cclose(c);
-               error(EBADF, "FD access mode failure: chan mode 0x%x, wanted 0x%x",
+               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;
                      c->mode, mode);
        }
        return c;
@@ -352,52 +353,6 @@ int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
        return m;
 }
 
        return m;
 }
 
-int syspipe(int fd[2])
-{
-       ERRSTACK(1);
-       struct dev *d;
-       struct chan *c[2];
-       static char *names[] = { "data", "data1" };
-
-       d = &devtab[devno("pipe", 0)];
-       c[0] = 0;
-       c[1] = 0;
-       fd[0] = -1;
-       fd[1] = -1;
-       if (waserror()) {
-               /* need to remove from the fd table and make sure the chan is closed
-                * exactly once.  if fd[i] >= 0, then the fd is valid (or it was!) and
-                * the fd table has the only ref (newfd() currently decrefs/consumes the
-                * reference).  cclose() doesn't care if you pass it 0 (like kfree()). */
-               if (fd[0] >= 0)
-                       close_fd(&current->open_files, fd[0]);
-               else
-                       cclose(c[0]);
-               if (fd[1] >= 0)
-                       close_fd(&current->open_files, fd[1]);
-               else
-                       cclose(c[1]);
-               poperror();
-               return -1;
-       }
-       c[0] = namec("#pipe", Atodir, 0, 0);
-       c[1] = cclone(c[0]);
-       if (walk(&c[0], &names[0], 1, FALSE, NULL) < 0)
-               error(EINVAL, ERROR_FIXME);
-       if (walk(&c[1], &names[1], 1, FALSE, NULL) < 0)
-               error(EINVAL, ERROR_FIXME);
-       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)
-               error(-fd[0], ERROR_FIXME);
-       fd[1] = newfd(c[1], 0);
-       if (fd[1] < 0)
-               error(-fd[1], ERROR_FIXME);
-       poperror();
-       return 0;
-}
-
 int sysfwstat(int fd, uint8_t * buf, int n)
 {
        ERRSTACK(2);
 int sysfwstat(int fd, uint8_t * buf, int n)
 {
        ERRSTACK(2);
@@ -567,6 +522,8 @@ int sysopenat(int fromfd, char *path, int vfs_flags)
                 * and give us something new for c.  On error, namec_from will cclose
                 * from. */
                from = fdtochan(&current->open_files, fromfd, -1, FALSE, TRUE);
                 * and give us something new for c.  On error, namec_from will cclose
                 * from. */
                from = fdtochan(&current->open_files, fromfd, -1, FALSE, TRUE);
+               if (!(from->flag & O_PATH))
+                       error(EINVAL, "Cannot openat from a non-O_PATH FD");
                c = namec_from(from, path, Aopen, vfs_flags, 0);
        }
        fd = newfd(c, vfs_flags);
                c = namec_from(from, path, Aopen, vfs_flags, 0);
        }
        fd = newfd(c, vfs_flags);
@@ -604,7 +561,7 @@ long unionread(struct chan *c, void *va, long n)
                        /* normally we want to discard the error, but for our ghetto kdirent
                         * hack, we need to repeat unionread if we saw a ENODATA */
                        if (waserror()) {
                        /* normally we want to discard the error, but for our ghetto kdirent
                         * hack, we need to repeat unionread if we saw a ENODATA */
                        if (waserror()) {
-                               if (!strcmp(current_errstr(), errno_to_string(ENODATA))) {
+                               if (get_errno() == ENODATA) {
                                        runlock(&m->lock);
                                        qunlock(&c->umqlock);
                                        nexterror();
                                        runlock(&m->lock);
                                        qunlock(&c->umqlock);
                                        nexterror();
@@ -686,7 +643,7 @@ static long rread(int fd, void *va, long n, int64_t * offp)
                /* expecting only one dirent at a time, o/w we're busted */
                assert(n >= sizeof(struct kdirent));
                if (!c->buf) {
                /* expecting only one dirent at a time, o/w we're busted */
                assert(n >= sizeof(struct kdirent));
                if (!c->buf) {
-                       c->buf=kmalloc(DIRREADSIZE, KMALLOC_WAIT);
+                       c->buf = kmalloc(DIRREADSIZE, MEM_WAIT);
                        c->bufused = 0;
                }
                /* Attempt to extract an M, in case there was some already */
                        c->bufused = 0;
                }
                /* Attempt to extract an M, in case there was some already */
@@ -839,12 +796,6 @@ int64_t sysseek(int fd, int64_t off, int whence)
                cclose(c);
                nexterror();
        }
                cclose(c);
                nexterror();
        }
-
-       /* TODO: WTF is this?  Is pipe magically the only device that isn't
-        * seekable? */
-       if (!strcmp(devtab[c->type].name, "pipe"))
-               error(EINVAL, ERROR_FIXME);
-
        switch (whence) {
                case 0:
                        if (c->qid.type & QTDIR) {
        switch (whence) {
                case 0:
                        if (c->qid.type & QTDIR) {
@@ -899,7 +850,7 @@ int64_t sysseek(int fd, int64_t off, int whence)
 
 void validstat(uint8_t * s, int n, int slashok)
 {
 
 void validstat(uint8_t * s, int n, int slashok)
 {
-       
+
        int m;
        char buf[64];
 
        int m;
        char buf[64];
 
@@ -951,10 +902,10 @@ int sysfstat(int fd, uint8_t *buf, int n)
 
 int sysfstatakaros(int fd, struct kstat *ks)
 {
 
 int sysfstatakaros(int fd, struct kstat *ks)
 {
-       
+
        int n = 4096;
        uint8_t *buf;
        int n = 4096;
        uint8_t *buf;
-       buf = kmalloc(n, KMALLOC_WAIT);
+       buf = kmalloc(n, MEM_WAIT);
        n = sysfstat(fd, buf, n);
        if (n > 0) {
                convM2kstat(buf, n, ks);
        n = sysfstat(fd, buf, n);
        if (n > 0) {
                convM2kstat(buf, n, ks);
@@ -990,10 +941,10 @@ int sysstat(char *path, uint8_t *buf, int n)
 
 int sysstatakaros(char *path, struct kstat *ks)
 {
 
 int sysstatakaros(char *path, struct kstat *ks)
 {
-       
+
        int n = 4096;
        uint8_t *buf;
        int n = 4096;
        uint8_t *buf;
-       buf = kmalloc(n, KMALLOC_WAIT);
+       buf = kmalloc(n, MEM_WAIT);
        n = sysstat(path, buf, n);
        if (n > 0) {
                convM2kstat(buf, n, ks);
        n = sysstat(path, buf, n);
        if (n > 0) {
                convM2kstat(buf, n, ks);
@@ -1068,7 +1019,7 @@ static long rwrite(int fd, void *va, long n, int64_t * offp)
        cclose(c);
 
        poperror();
        cclose(c);
 
        poperror();
-       return n;
+       return m;
 }
 
 long syswrite(int fd, void *va, long n)
 }
 
 long syswrite(int fd, void *va, long n)
@@ -1189,7 +1140,7 @@ struct dir *sysdirfstat(int fd)
 
 int sysdirwstat(char *name, struct dir *dir)
 {
 
 int sysdirwstat(char *name, struct dir *dir)
 {
-       
+
        uint8_t *buf;
        int r;
 
        uint8_t *buf;
        int r;
 
@@ -1203,7 +1154,7 @@ int sysdirwstat(char *name, struct dir *dir)
 
 int sysdirfwstat(int fd, struct dir *dir)
 {
 
 int sysdirfwstat(int fd, struct dir *dir)
 {
-       
+
        uint8_t *buf;
        int r;
 
        uint8_t *buf;
        int r;
 
@@ -1217,7 +1168,7 @@ int sysdirfwstat(int fd, struct dir *dir)
 
 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
 {
 
 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
 {
-       
+
        char *s;
        long ss, i, n, nn, m = 0;
 
        char *s;
        long ss, i, n, nn, m = 0;
 
@@ -1312,19 +1263,18 @@ int sysiounit(int fd)
 
 void print_chaninfo(struct chan *c)
 {
 
 void print_chaninfo(struct chan *c)
 {
-       
-       char buf[64] = { 0 };
+
+       char buf[128] = { 0 };
        bool has_dev = c->type != -1;
        bool has_dev = c->type != -1;
-       if (has_dev && !devtab[c->type].chaninfo) {
-               printk("Chan type %d has no chaninfo!\n", c->type);
-               has_dev = FALSE;
-       }
-       printk("Chan pathname: %s ref %d, Dev: %s, Devinfo: %s",
+       bool has_chaninfo = has_dev && devtab[c->type].chaninfo;
+
+       printk("Chan flags: %p, pathname: %s, ref: %d, Dev: %s, Devinfo: %s",
+                  c->flag,
                   c->name ? c->name->s : "no cname",
                   kref_refcnt(&c->ref),
                   has_dev ? devtab[c->type].name : "no dev",
                   c->name ? c->name->s : "no cname",
                   kref_refcnt(&c->ref),
                   has_dev ? devtab[c->type].name : "no dev",
-                  has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "");
-       if (!has_dev)
+                  has_chaninfo ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "");
+       if (!has_chaninfo)
                printk("qid.path: %p\n", c->qid.path);
        printk("\n");
 }
                printk("qid.path: %p\n", c->qid.path);
        printk("\n");
 }
@@ -1334,7 +1284,7 @@ void print_chaninfo(struct chan *c)
  * the pgrp. */
 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
 {
  * the pgrp. */
 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
 {
-       
+
        struct kref *new_dot_ref;
        ERRSTACK(1);
        if (waserror()) {
        struct kref *new_dot_ref;
        ERRSTACK(1);
        if (waserror()) {
@@ -1433,22 +1383,35 @@ static bool cexternal_flags_differ(int set1, int set2, int flags)
 
 int fd_setfl(int fd, int flags)
 {
 
 int fd_setfl(int fd, int flags)
 {
-       ERRSTACK(1);
+       ERRSTACK(2);
        struct chan *c;
        struct chan *c;
+       int ret = 0;
 
        if (waserror()) {
                poperror();
                return -1;
        }
        c = fdtochan(&current->open_files, fd, -1, 0, 1);
 
        if (waserror()) {
                poperror();
                return -1;
        }
        c = fdtochan(&current->open_files, fd, -1, 0, 1);
+       if (waserror()) {
+               cclose(c);
+               nexterror();
+       }
        if (cexternal_flags_differ(flags, c->flag, O_CLOEXEC)) {
                /* TODO: The whole CCEXEC / O_CLOEXEC on 9ns needs work */
                error(EINVAL, "can't toggle O_CLOEXEC with setfl");
        }
        if (cexternal_flags_differ(flags, c->flag, O_CLOEXEC)) {
                /* TODO: The whole CCEXEC / O_CLOEXEC on 9ns needs work */
                error(EINVAL, "can't toggle O_CLOEXEC with setfl");
        }
+       if (cexternal_flags_differ(flags, c->flag, O_REMCLO))
+               error(EINVAL, "can't toggle O_REMCLO with setfl");
        if (cexternal_flags_differ(flags, c->flag, O_PATH))
                error(EINVAL, "can't toggle O_PATH with setfl");
        if (cexternal_flags_differ(flags, c->flag, O_PATH))
                error(EINVAL, "can't toggle O_PATH with setfl");
+       /* Devices can do various prep work, including RPCs to other servers (#mnt)
+        * for a chan_ctl operation.  If they want to not support the new flags,
+        * they can throw an error. */
+       if (devtab[c->type].chan_ctl)
+               ret = devtab[c->type].chan_ctl(c, flags & CEXTERNAL_FLAGS);
        c->flag = (c->flag & ~CEXTERNAL_FLAGS) | (flags & CEXTERNAL_FLAGS);
        c->flag = (c->flag & ~CEXTERNAL_FLAGS) | (flags & CEXTERNAL_FLAGS);
+       poperror();
        cclose(c);
        poperror();
        cclose(c);
        poperror();
-       return 0;
+       return ret;
 }
 }