Remove uses of errno_to_string()
[akaros.git] / kern / src / ns / chan.c
index 3bd93bc..c488d1a 100644 (file)
@@ -1,4 +1,31 @@
-// INFERNO
+/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+ * Portions Copyright © 1997-1999 Vita Nuova Limited
+ * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+ *                                (www.vitanuova.com)
+ * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+ *
+ * Modified for the Akaros operating system:
+ * Copyright (c) 2013-2014 The Regents of the University of California
+ * Copyright (c) 2013-2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
 #include <vfs.h>
 #include <kfs.h>
 #include <slab.h>
@@ -89,16 +116,20 @@ void chandevreset(void)
 {
        int i;
 
-       for (i = 0; &devtab[i] < __devtabend; i++)
-               devtab[i].reset();
+       for (i = 0; &devtab[i] < __devtabend; i++) {
+               if (devtab[i].reset)
+                       devtab[i].reset();
+       }
 }
 
 void chandevinit(void)
 {
        int i;
 
-       for (i = 0; &devtab[i] < __devtabend; i++)
-               devtab[i].init();
+       for (i = 0; &devtab[i] < __devtabend; i++) {
+               if (devtab[i].init)
+                       devtab[i].init();
+       }
 }
 
 void chandevshutdown(void)
@@ -107,8 +138,10 @@ void chandevshutdown(void)
 
        /* shutdown in reverse order */
        for (i = 0; &devtab[i] < __devtabend; i++) ;
-       for (i--; i >= 0; i--)
-               devtab[i].shutdown();
+       for (i--; i >= 0; i--) {
+               if (devtab[i].shutdown)
+                       devtab[i].shutdown();
+       }
 }
 
 static void chan_release(struct kref *kref)
@@ -373,7 +406,7 @@ int cmount(struct chan *new, struct chan *old, int flag, char *spec)
        struct mount *nm, *f, *um, **h;
 
        if (QTDIR & (old->qid.type ^ new->qid.type))
-               error(Emount);
+               error(EINVAL, ERROR_FIXME);
 
        if (old->umh)
                printd("cmount old extra umh\n");
@@ -381,7 +414,7 @@ int cmount(struct chan *new, struct chan *old, int flag, char *spec)
        order = flag & MORDER;
 
        if ((old->qid.type & QTDIR) == 0 && order != MREPL)
-               error(Emount);
+               error(EINVAL, ERROR_FIXME);
 
        mh = new->umh;
 
@@ -403,7 +436,7 @@ int cmount(struct chan *new, struct chan *old, int flag, char *spec)
         */
        if ((flag & MCREATE) && mh && mh->mount
                && (mh->mount->next || !(mh->mount->mflag & MCREATE)))
-               error(Emount);
+               error(EEXIST, ERROR_FIXME);
 
        pg = current->pgrp;
        wlock(&pg->ns);
@@ -506,7 +539,7 @@ void cunmount(struct chan *mnt, struct chan *mounted)
 
        if (m == 0) {
                wunlock(&pg->ns);
-               error(Eunmount);
+               error(ENOENT, ERROR_FIXME);
        }
 
        wlock(&m->lock);
@@ -545,7 +578,7 @@ void cunmount(struct chan *mnt, struct chan *mounted)
        }
        wunlock(&m->lock);
        wunlock(&pg->ns);
-       error(Eunion);
+       error(ENOENT, ERROR_FIXME);
 }
 
 struct chan *cclone(struct chan *c)
@@ -555,7 +588,7 @@ struct chan *cclone(struct chan *c)
 
        wq = devtab[c->type].walk(c, NULL, NULL, 0);
        if (wq == NULL)
-               error("clone failed");
+               error(EFAIL, "clone failed");
        nc = wq->clone;
        kfree(wq);
        nc->name = c->name;
@@ -655,7 +688,6 @@ struct chan *undomount(struct chan *c, struct cname *name)
  * Either walks all the way or not at all.  No partial results in *cp.
  * *nerror is the number of names to display in an error message.
  */
-static char Edoesnotexist[] = "does not exist";
 int walk(struct chan **cp, char **names, int nnames, bool can_mount, int *nerror)
 {
        int dev, dotdot, i, n, nhave, ntry, type;
@@ -687,7 +719,7 @@ int walk(struct chan **cp, char **names, int nnames, bool can_mount, int *nerror
                                *nerror = nhave;
                        cnameclose(cname);
                        cclose(c);
-                       set_errstr(Enotdir);
+                       set_error(ENOTDIR, ERROR_FIXME);
                        if (mh != NULL)
                                putmhead(mh);
                        return -1;
@@ -763,11 +795,11 @@ int walk(struct chan **cp, char **names, int nnames, bool can_mount, int *nerror
                                        if (wq->nqid == 0 || (wq->qid[wq->nqid - 1].type & QTDIR)) {
                                                if (nerror)
                                                        *nerror = nhave + wq->nqid + 1;
-                                               set_errstr(Edoesnotexist);
+                                               set_error(ENOENT, "walk failed");
                                        } else {
                                                if (nerror)
                                                        *nerror = nhave + wq->nqid;
-                                               set_errstr(Enotdir);
+                                               set_error(ENOTDIR, "walk failed");
                                        }
                                        kfree(wq);
                                        if (mh != NULL)
@@ -838,7 +870,7 @@ struct chan *createdir(struct chan *c, struct mhead *m)
                        return nc;
                }
        }
-       error(Enocreate);
+       error(EPERM, ERROR_FIXME);
        poperror();
        return 0;
 }
@@ -957,94 +989,24 @@ void *memrchr(void *va, int c, long n)
  *
  * Acreatechan will never open. It will do all the tests and return a chan
  * for the directory where an open will succeed.
- */
-struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
+ *
+ * The classic namec() is broken into a front end to get the starting point and
+ * a __namec_from, which does the guts of the lookup.  */
+static struct chan *__namec_from(struct chan *c, char *aname, int amode,
+                                 int omode, uint32_t perm, bool can_mount)
 {
        ERRSTACK(2);
-       int n, prefix, len, t, nomount, npath;
-       struct chan *c, *cnew;
+       int len, npath;
+       struct chan *cnew;
        struct cname *cname;
        Elemlist e;
        struct mhead *m;
        char tmperrbuf[ERRMAX];
        int saved_errno;
-       char *name, *devname, *devspec;
-       bool can_mount = TRUE;
        // Rune r;
 
        static_assert(!(CINTERNAL_FLAGS & CEXTERNAL_FLAGS));
 
-       name = aname;
-       if (name[0] == '\0')
-               error("empty file name");
-       validname(name, 1);
-       /*
-        * Find the starting off point (the current slash, the root of
-        * a device tree, or the current dot) as well as the name to
-        * evaluate starting there.
-        */
-       switch (name[0]) {
-               case '/':
-                       c = current->slash;
-                       if (!c)
-                               panic("no slash!");
-                       chan_incref(c);
-                       break;
-
-               case '#':
-                       can_mount = FALSE;
-                       devname = get_cur_genbuf();
-                       devname[0] = '\0';
-                       n = 0;
-                       name++; /* drop the # */
-                       while ((*name != '\0') && (*name != '/')) {
-                               if (n >= GENBUF_SZ - 1)
-                                       error(Efilename);
-                               devname[n++] = *name++;
-                       }
-                       devname[n] = '\0';
-                       /* for a name #foo.spec, devname = foo\0, devspec = spec\0.
-                        * genbuf contains foo\0spec\0.  for no spec, devspec = \0 */
-                       devspec = strchr(devname, '.');
-                       if (devspec) {
-                               *devspec = '\0';
-                               devspec++;
-                       } else {
-                               devspec = &devname[n];
-                       }
-                       if (!strcmp(devname, "mnt"))
-                               error(Enoattach);
-                       /* TODO: deal with this "nodevs" business. */
-                       #if 0
-                       /*
-                        *  the nodevs exceptions are
-                        *  |  it only gives access to pipes you create
-                        *  e  this process's environment
-                        *  s  private file2chan creation space
-                        *  D private secure sockets name space
-                        *  a private TLS name space
-                        */
-                       if (current->pgrp->nodevs &&
-                               //          (utfrune("|esDa", r) == NULL
-                               ((strchr("|esDa", get_cur_genbuf()[1]) == NULL)
-                                || (get_cur_genbuf()[1] == 's' // || r == 's'
-                                        && get_cur_genbuf()[n] != '\0')))
-                               error(Enoattach);
-                       #endif
-                       t = devno(devname, 1);
-                       if (t == -1)
-                               error("Unknown #device %s (spec %s)", devname, devspec);
-                       c = devtab[t].attach(devspec);
-                       break;
-               default:
-                       c = current->dot;
-                       if (!c)
-                               panic("no dot!");
-                       chan_incref(c);
-                       break;
-       }
-       prefix = name - aname;
-
        e.name = NULL;
        e.elems = NULL;
        e.off = NULL;
@@ -1054,14 +1016,14 @@ struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
                kfree(e.name);
                kfree(e.elems);
                kfree(e.off);
-//dumpmount();
+               //dumpmount();
                nexterror();
        }
 
        /*
         * Build a list of elements in the path.
         */
-       parsename(name, &e);
+       parsename(aname, &e);
 
        /*
         * On create, ....
@@ -1070,33 +1032,33 @@ struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
                /* perm must have DMDIR if last element is / or /. */
                if (e.mustbedir && !(perm & DMDIR)) {
                        npath = e.ARRAY_SIZEs;
-                       strncpy(tmperrbuf, "create without DMDIR", sizeof(tmperrbuf));
+                       strlcpy(tmperrbuf, "create without DMDIR", sizeof(tmperrbuf));
                        goto NameError;
                }
 
                /* don't try to walk the last path element just yet. */
                if (e.ARRAY_SIZEs == 0)
-                       error(Eexist);
+                       error(EEXIST, ERROR_FIXME);
                e.ARRAY_SIZEs--;
        }
 
        if (walk(&c, e.elems, e.ARRAY_SIZEs, can_mount, &npath) < 0) {
                if (npath < 0 || npath > e.ARRAY_SIZEs) {
                        printd("namec %s walk error npath=%d\n", aname, npath);
-                       error("walk failed");
+                       error(EFAIL, "walk failed");
                }
 NameError:
                if (current_errstr()[0]) {
                        /* errstr is set, we'll just stick with it and error out */
                        longjmp(&get_cur_errbuf()->jmpbuf, 1);
                } else {
-                       error("Name to chan lookup failed");
+                       error(EFAIL, "Name to chan lookup failed");
                }
                /* brho: skipping the namec custom error string business, since it hides
                 * the underlying failure.  implement this if you want the old stuff. */
 #if 0
-               strncpy(tmperrbuf, current->errstr, sizeof(tmperrbuf));
-               len = prefix + e.off[npath];
+               strlcpy(tmperrbuf, current->errstr, sizeof(tmperrbuf));
+               len = prefix + e.off[npath]; // prefix was name - aname, the start pt
                if (len < ERRMAX / 3 || (name = memrchr(aname, '/', len)) == NULL
                        || name == aname)
                        snprintf(get_cur_genbuf(), sizeof current->genbuf, "%.*s", len,
@@ -1111,13 +1073,13 @@ NameError:
 
        if (e.mustbedir && !(c->qid.type & QTDIR)) {
                npath = e.ARRAY_SIZEs;
-               strncpy(tmperrbuf, "not a directory", sizeof(tmperrbuf));
+               strlcpy(tmperrbuf, "not a directory", sizeof(tmperrbuf));
                goto NameError;
        }
 
        if ((amode == Aopen) && (omode & O_EXEC) && (c->qid.type & QTDIR)) {
                npath = e.ARRAY_SIZEs;
-               error("cannot exec directory");
+               error(EFAIL, "cannot exec directory");
        }
 
        switch (amode) {
@@ -1182,7 +1144,7 @@ Open:
                                         * probably saving mode directly, without passing it through
                                         * openmode. */
                                        if (c->mode & O_TRUNC)
-                                               error("Device %s open failed to clear O_TRUNC",
+                                               error(EFAIL, "Device %s open failed to clear O_TRUNC",
                                                      devtab[c->type].name);
                                        break;
                        }
@@ -1194,7 +1156,7 @@ Open:
                         * so one may mount on / or . and see the effect.
                         */
                        if (!(c->qid.type & QTDIR))
-                               error(Enotdir);
+                               error(ENOTDIR, ERROR_FIXME);
                        break;
 
                case Amount:
@@ -1221,7 +1183,7 @@ Open:
                        e.ARRAY_SIZEs++;
                        if (walk(&c, e.elems + e.ARRAY_SIZEs - 1, 1, can_mount, NULL) == 0) {
                                if (omode & O_EXCL)
-                                       error(Eexist);
+                                       error(EEXIST, ERROR_FIXME);
                                omode |= O_TRUNC;
                                goto Open;
                        }
@@ -1315,14 +1277,15 @@ Open:
                        poperror();     /* matching the if(!waserror) */
 
                        /* save error, so walk doesn't clobber our existing errstr */
-                       strncpy(tmperrbuf, current_errstr(), MAX_ERRSTR_LEN);
+                       strlcpy(tmperrbuf, current_errstr(), sizeof(tmperrbuf));
                        saved_errno = get_errno();
                        /* note: we depend that walk does not error */
                        if (walk(&c, e.elems + e.ARRAY_SIZEs - 1, 1, can_mount, NULL) < 0) {
                                set_errno(saved_errno);
-                               error(tmperrbuf);       /* report the error we had originally */
+                               /* Report the error we had originally */
+                               error(EFAIL, tmperrbuf);
                        }
-                       strncpy(current_errstr(), tmperrbuf, MAX_ERRSTR_LEN);
+                       strlcpy(current_errstr(), tmperrbuf, MAX_ERRSTR_LEN);
                        omode |= O_TRUNC;
                        goto Open;
 
@@ -1333,9 +1296,9 @@ Open:
        poperror();
 
        if (e.ARRAY_SIZEs > 0)
-               strncpy(get_cur_genbuf(), e.elems[e.ARRAY_SIZEs - 1], GENBUF_SZ);
+               strlcpy(get_cur_genbuf(), e.elems[e.ARRAY_SIZEs - 1], GENBUF_SZ);
        else
-               strncpy(get_cur_genbuf(), ".", GENBUF_SZ);
+               strlcpy(get_cur_genbuf(), ".", GENBUF_SZ);
 
        kfree(e.name);
        kfree(e.elems);
@@ -1344,6 +1307,97 @@ Open:
        return c;
 }
 
+struct chan *namec(char *name, int amode, int omode, uint32_t perm)
+{
+       bool can_mount = TRUE;
+       struct chan *c;
+       char *devname, *devspec;
+       int n, devtype;
+
+       if (name[0] == '\0')
+               error(EFAIL, "empty file name");
+       validname(name, 1);
+       /*
+        * Find the starting off point (the current slash, the root of
+        * a device tree, or the current dot) as well as the name to
+        * evaluate starting there.
+        */
+       switch (name[0]) {
+               case '/':
+                       c = current->slash;
+                       if (!c)
+                               panic("no slash!");
+                       chan_incref(c);
+                       break;
+
+               case '#':
+                       can_mount = FALSE;
+                       devname = get_cur_genbuf();
+                       devname[0] = '\0';
+                       n = 0;
+                       name++; /* drop the # */
+                       while ((*name != '\0') && (*name != '/')) {
+                               if (n >= GENBUF_SZ - 1)
+                                       error(ENAMETOOLONG, ERROR_FIXME);
+                               devname[n++] = *name++;
+                       }
+                       devname[n] = '\0';
+                       /* for a name #foo.spec, devname = foo\0, devspec = spec\0.
+                        * genbuf contains foo\0spec\0.  for no spec, devspec = \0 */
+                       devspec = strchr(devname, '.');
+                       if (devspec) {
+                               *devspec = '\0';
+                               devspec++;
+                       } else {
+                               devspec = &devname[n];
+                       }
+                       if (!strcmp(devname, "mnt"))
+                               error(EINVAL, ERROR_FIXME);
+                       /* TODO: deal with this "nodevs" business. */
+                       #if 0
+                       /*
+                        *  the nodevs exceptions are
+                        *  |  it only gives access to pipes you create
+                        *  e  this process's environment
+                        *  s  private file2chan creation space
+                        *  D private secure sockets name space
+                        *  a private TLS name space
+                        */
+                       if (current->pgrp->nodevs &&
+                               //          (utfrune("|esDa", r) == NULL
+                               ((strchr("|esDa", get_cur_genbuf()[1]) == NULL)
+                                || (get_cur_genbuf()[1] == 's' // || r == 's'
+                                        && get_cur_genbuf()[n] != '\0')))
+                               error(EINVAL, ERROR_FIXME);
+                       #endif
+                       devtype = devno(devname, 1);
+                       if (devtype == -1)
+                               error(EFAIL, "Unknown #device %s (spec %s)", devname, devspec);
+                       c = devtab[devtype].attach(devspec);
+                       break;
+               default:
+                       /* this case also covers \0 */
+                       c = current->dot;
+                       if (!c)
+                               panic("no dot!");
+                       chan_incref(c);
+                       break;
+       }
+       return __namec_from(c, name, amode, omode, perm, can_mount);
+}
+
+struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
+                        uint32_t perm)
+{
+       if (name[0] == '\0') {
+               /* Our responsibility to cclose 'c' on our error */
+               cclose(c);
+               error(EFAIL, "empty file name");
+       }
+       validname(name, 1);
+       return __namec_from(c, name, amode, omode, perm, TRUE);
+}
+
 /*
  * name is valid. skip leading / and ./ as much as possible
  */
@@ -1383,7 +1437,7 @@ void validname(char *aname, int slashok)
        ename = memchr(name, 0, (1 << 16));
 
        if (ename == NULL || ename - name >= (1 << 16))
-               error("name too long");
+               error(EINVAL, "Name too long");
 
        while (*name) {
                /* all characters above '~' are ok */
@@ -1393,11 +1447,11 @@ void validname(char *aname, int slashok)
                        name += chartorune(&r, name);
 #endif
                if (c >= 0x7f) {
-                       error("Akaros doesn't do UTF-8");
+                       error(EFAIL, "Akaros doesn't do UTF-8");
                } else {
                        if (isfrog[c])
                                if (!slashok || c != '/') {
-                                       error("%s: %s (%p), at char %c", Ebadchar, aname, aname, c);
+                                       error(EINVAL, "%s (%p), at char %c", aname, aname, c);
                                }
                        name++;
                }
@@ -1408,7 +1462,7 @@ void isdir(struct chan *c)
 {
        if (c->qid.type & QTDIR)
                return;
-       error(Enotdir);
+       error(ENOTDIR, ERROR_FIXME);
 }
 
 /*