Add the Inferno license to files we got from Inferno
[akaros.git] / kern / src / ns / dev.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42
43 extern uint32_t kerndate;
44 extern char *eve;
45
46 void mkqid(struct qid *q, int64_t path, uint32_t vers, int type)
47 {
48         q->type = type;
49         q->vers = vers;
50         q->path = path;
51 }
52
53 int devno(const char *name, int user)
54 {
55         int i;
56
57         for (i = 0; &devtab[i] < __devtabend; i++) {
58                 if (!strcmp(devtab[i].name, name))
59                         return i;
60         }
61         if (user == 0)
62                 panic("Lookup of dev :%s: failed", name);
63
64         return -1;
65 }
66
67 void
68 devdir(struct chan *c, struct qid qid, char *n,
69            int64_t length, char *user, long perm, struct dir *db)
70 {
71         db->name = n;
72         if (c->flag & CMSG)
73                 qid.type |= QTMOUNT;
74         db->qid = qid;
75         db->type = c->type;     /* used to use the dev's dc here */
76         db->dev = c->dev;
77         db->mode = perm;
78         db->mode |= qid.type << 24;
79         db->atime = seconds();
80         db->mtime = kerndate;
81         db->length = length;
82         db->uid = user;
83         db->gid = eve;
84         db->muid = user;
85 }
86
87 /*
88  * the zeroth element of the table MUST be the directory itself for ..
89  * Any entry with qid vers of -1 will return 0, indicating that the value is
90  * valid but there is nothing there continue walk.
91  * TODO(gvdl): Update akaros devgen man page.
92 */
93 int
94 devgen(struct chan *c, char *unused_char_p_t, struct dirtab *tab, int ntab,
95            int i, struct dir *dp)
96 {
97         if (tab == 0)
98                 return -1;
99         if (i != DEVDOTDOT) {
100                 /* skip over the first element, that for . itself */
101                 i++;
102                 if (i >= ntab)
103                         return -1;
104                 tab += i;
105         }
106         int ret = (tab->qid.vers == -1)? 0 : 1;
107         if (ret)
108                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
109         return ret;
110 }
111
112 void devreset(void)
113 {
114 }
115
116 void devinit(void)
117 {
118 }
119
120 void devshutdown(void)
121 {
122 }
123
124 struct chan *devattach(const char *name, char *spec)
125 {
126         struct chan *c;
127         char *buf;
128         size_t buflen;
129
130         c = newchan();
131         mkqid(&c->qid, 0, 0, QTDIR);
132         c->type = devno(name, 0);
133         if (spec == NULL)
134                 spec = "";
135         /* 1 for #, 1 for ., 1 for \0 */
136         buflen = strlen(name) + strlen(spec) + 3;
137         buf = kzmalloc(buflen, KMALLOC_WAIT);
138         snprintf(buf, sizeof(buf), "#%s.%s", name, spec);
139         c->name = newcname(buf);
140         kfree(buf);
141         return c;
142 }
143
144 struct chan *devclone(struct chan *c)
145 {
146         struct chan *nc;
147
148         /* In plan 9, you couldn't clone an open chan.  We're allowing it, possibly
149          * foolishly.  The new chan is a non-open, "kernel internal" chan.  Note
150          * that c->flag isn't set, for instance.  c->mode is, which might be a
151          * problem.  The newchan should eventually have a device's open called on
152          * it, at which point it upgrades from a kernel internal chan to one that
153          * can refer to an object in the device (e.g. grab a refcnt on a
154          * conversation in #ip).
155          *
156          * Either we allow devclones of open chans, or O_PATH walks do not open a
157          * file.  It's nice to allow the device to do something for O_PATH, but
158          * perhaps that is not critical.  However, if we can't clone an opened chan,
159          * then we can *only* openat from an FD that is O_PATH, which is not the
160          * spec (and not as useful). */
161         if ((c->flag & COPEN) && !(c->flag & O_PATH))
162                 panic("clone of non-O_PATH open file type %s\n", devtab[c->type].name);
163
164         nc = newchan();
165         nc->type = c->type;
166         nc->dev = c->dev;
167         nc->mode = c->mode;
168         nc->qid = c->qid;
169         nc->offset = c->offset;
170         nc->umh = NULL;
171         nc->mountid = c->mountid;
172         nc->aux = c->aux;
173         nc->mqid = c->mqid;
174         nc->mcp = c->mcp;
175         return nc;
176 }
177
178 struct walkqid *devwalk(struct chan *c,
179                                                 struct chan *nc, char **name, int nname,
180                                                 struct dirtab *tab, int ntab, Devgen * gen)
181 {
182         ERRSTACK(1);
183         int i, j;
184         volatile int alloc;                     /* to keep waserror from optimizing this out */
185         struct walkqid *wq;
186         char *n;
187         struct dir dir;
188
189         if (nname > 0)
190                 isdir(c);
191
192         alloc = 0;
193         wq = kzmalloc(sizeof(struct walkqid) + nname * sizeof(struct qid),
194                                   KMALLOC_WAIT);
195         if (waserror()) {
196                 if (alloc && wq->clone != NULL)
197                         cclose(wq->clone);
198                 kfree(wq);
199                 poperror();
200                 return NULL;
201         }
202         if (nc == NULL) {
203                 nc = devclone(c);
204                 /* inferno was setting this to 0, assuming it was devroot.  lining up
205                  * with chanrelease and newchan */
206                 nc->type = -1;  /* device doesn't know about this channel yet */
207                 alloc = 1;
208         }
209         wq->clone = nc;
210
211         dir.qid.path = 0;
212         for (j = 0; j < nname; j++) {
213                 if (!(nc->qid.type & QTDIR)) {
214                         if (j == 0)
215                                 error(ENOTDIR, NULL);
216                         goto Done;
217                 }
218                 n = name[j];
219                 if (strcmp(n, ".") == 0) {
220 Accept:
221                         wq->qid[wq->nqid++] = nc->qid;
222                         continue;
223                 }
224                 if (strcmp(n, "..") == 0) {
225                         (*gen) (nc, NULL, tab, ntab, DEVDOTDOT, &dir);
226                         nc->qid = dir.qid;
227                         goto Accept;
228                 }
229                 /*
230                  * Ugly problem: If we're using devgen, make sure we're
231                  * walking the directory itself, represented by the first
232                  * entry in the table, and not trying to step into a sub-
233                  * directory of the table, e.g. /net/net. Devgen itself
234                  * should take care of the problem, but it doesn't have
235                  * the necessary information (that we're doing a walk).
236                  */
237                 if (gen == devgen && nc->qid.path != tab[0].qid.path)
238                         goto Notfound;
239                 dir.qid.path = 0;
240                 for (i = 0;; i++) {
241                         switch ((*gen) (nc, n, tab, ntab, i, &dir)) {
242                                 case -1:
243                                         printd("DEVWALK -1, i was %d, want path %p\n", i,
244                                                    c->qid.path);
245 Notfound:
246                                         if (j == 0)
247                                                 error(ENOENT, NULL);
248                                         set_error(ENOENT, NULL);
249                                         goto Done;
250                                 case 0:
251                                         printd("DEVWALK continue, i was %d\n", i);
252                                         continue;
253                                 case 1:
254                                         printd
255                                                 ("DEVWALK gen returns path %p name %s, want path %p\n",
256                                                  dir.qid.path, dir.name, c->qid.path);
257                                         if (strcmp(n, dir.name) == 0) {
258                                                 nc->qid = dir.qid;
259                                                 goto Accept;
260                                         }
261                                         continue;
262                         }
263                 }
264         }
265         /*
266          * We processed at least one name, so will return some data.
267          * If we didn't process all nname entries succesfully, we drop
268          * the cloned channel and return just the Qids of the walks.
269          */
270 Done:
271         poperror();
272         if (wq->nqid < nname) {
273                 if (alloc)
274                         cclose(wq->clone);
275                 wq->clone = NULL;
276         } else if (wq->clone) {
277                 /* attach cloned channel to same device */
278                 wq->clone->type = c->type;
279         }
280         return wq;
281 }
282
283 int
284 devstat(struct chan *c, uint8_t * db, int n,
285                 struct dirtab *tab, int ntab, Devgen * gen)
286 {
287         int i;
288         struct dir dir;
289         char *p, *elem;
290
291         dir.qid.path = 0;
292         for (i = 0;; i++)
293                 switch ((*gen) (c, NULL, tab, ntab, i, &dir)) {
294                         case -1:
295                                 if (c->qid.type & QTDIR) {
296                                         printd("DEVSTAT got a dir: %llu\n", c->qid.path);
297                                         if (c->name == NULL)
298                                                 elem = "???";
299                                         else if (strcmp(c->name->s, "/") == 0)
300                                                 elem = "/";
301                                         else
302                                                 for (elem = p = c->name->s; *p; p++)
303                                                         if (*p == '/')
304                                                                 elem = p + 1;
305                                         devdir(c, c->qid, elem, 0, eve, DMDIR | 0555, &dir);
306                                         n = convD2M(&dir, db, n);
307                                         if (n == 0)
308                                                 error(EINVAL, NULL);
309                                         return n;
310                                 }
311                                 printd("DEVSTAT fails:%s %llu\n", devtab[c->type].name,
312                                            c->qid.path);
313                                 error(ENOENT, NULL);
314                         case 0:
315                                 printd("DEVSTAT got 0\n");
316                                 break;
317                         case 1:
318                                 printd("DEVSTAT gen returns path %p name %s, want path %p\n",
319                                            dir.qid.path, dir.name, c->qid.path);
320                                 if (c->qid.path == dir.qid.path) {
321                                         if (c->flag & CMSG)
322                                                 dir.mode |= DMMOUNT;
323                                         n = convD2M(&dir, db, n);
324                                         if (n == 0)
325                                                 error(EINVAL, NULL);
326                                         return n;
327                                 }
328                                 break;
329                 }
330 }
331
332 long
333 devdirread(struct chan *c, char *d, long n,
334                    struct dirtab *tab, int ntab, Devgen * gen)
335 {
336         long m, dsz;
337         /* this is gross. Make it 2 so we have room at the end for
338          * bad things.
339          */
340         struct dir dir[4];
341
342         dir[0].qid.path = 0;
343         for (m = 0; m < n; c->dri++) {
344                 switch ((*gen) (c, NULL, tab, ntab, c->dri, &dir[0])) {
345                         case -1:
346                                 printd("DEVDIRREAD got -1, asked for s = %d\n", c->dri);
347                                 return m;
348
349                         case 0:
350                                 printd("DEVDIRREAD got 0, asked for s = %d\n", c->dri);
351                                 break;
352
353                         case 1:
354                                 printd("DEVDIRREAD got 1, asked for s = %d\n", c->dri);
355                                 dsz = convD2M(&dir[0], (uint8_t *) d, n - m);
356                                 if (dsz <= BIT16SZ) {   /* <= not < because this isn't stat; read is stuck */
357                                         if (m == 0)
358                                                 error(ENODATA, NULL);
359                                         return m;
360                                 }
361                                 m += dsz;
362                                 d += dsz;
363                                 break;
364                 }
365         }
366
367         return m;
368 }
369
370 /*
371  * error(EPERM, NULL) if open permission not granted for up->env->user.
372  */
373 void devpermcheck(char *fileuid, uint32_t perm, int omode)
374 {
375         int rwx;
376         /* select user, group, or other from the traditional rwxrwxrwx, shifting
377          * into the upper-most position */
378         if (strcmp(current->user, fileuid) == 0)
379                 perm <<= 0;
380         else if (strcmp(current->user, eve) == 0)
381                 perm <<= 3;
382         else
383                 perm <<= 6;
384         /* translate omode into things like S_IRUSR (just one set of rwx------).
385          * Plan 9 originally only returned 0400 0200 0600 and 0100 here; it didn't
386          * seem to handle O_EXEC being mixed readable or writable. */
387         rwx = omode_to_rwx(omode);
388         if ((rwx & perm) != rwx)
389                 error(EPERM, "devpermcheck(%s, 0%o, 0%o) failed", fileuid, perm, omode);
390 }
391
392 struct chan *devopen(struct chan *c, int omode, struct dirtab *tab, int ntab,
393                                          Devgen * gen)
394 {
395         int i;
396         struct dir dir;
397
398         dir.qid.path = 0;
399         for (i = 0;; i++) {
400                 switch ((*gen) (c, NULL, tab, ntab, i, &dir)) {
401                         case -1:
402                                 goto Return;
403                         case 0:
404                                 break;
405                         case 1:
406                                 if (c->qid.path == dir.qid.path) {
407                                         devpermcheck(dir.uid, dir.mode, omode);
408                                         goto Return;
409                                 }
410                                 break;
411                 }
412         }
413 Return:
414         c->offset = 0;
415         if ((c->qid.type & QTDIR) && (omode & O_WRITE))
416                 error(EACCES, "Tried opening dir with non-read-only mode %o", omode);
417         c->mode = openmode(omode);
418         c->flag |= COPEN;
419         return c;
420 }
421
422 void
423 devcreate(struct chan *c, char *unused_char_p_t, int unused_int, uint32_t u)
424 {
425         error(EPERM, NULL);
426 }
427
428 struct block *devbread(struct chan *c, long n, uint32_t offset)
429 {
430         ERRSTACK(1);
431         struct block *bp;
432
433         bp = allocb(n);
434         if (bp == 0)
435                 error(ENOMEM, NULL);
436         if (waserror()) {
437                 freeb(bp);
438                 nexterror();
439         }
440         bp->wp += devtab[c->type].read(c, bp->wp, n, offset);
441         poperror();
442         return bp;
443 }
444
445 long devbwrite(struct chan *c, struct block *bp, uint32_t offset)
446 {
447         ERRSTACK(1);
448         long n;
449
450         if (waserror()) {
451                 freeb(bp);
452                 nexterror();
453         }
454         n = devtab[c->type].write(c, bp->rp, BLEN(bp), offset);
455         poperror();
456         freeb(bp);
457
458         return n;
459 }
460
461 void devremove(struct chan *c)
462 {
463         error(EPERM, NULL);
464 }
465
466 int devwstat(struct chan *c, uint8_t * unused_uint8_p_t, int i)
467 {
468         error(EPERM, NULL);
469         return 0;
470 }
471
472 void devpower(int i)
473 {
474         error(EPERM, NULL);
475 }
476
477 #if 0
478 int devconfig(int unused_int, char *c, DevConf *)
479 {
480         error(EPERM, NULL);
481         return 0;
482 }
483 #endif
484
485 char *devchaninfo(struct chan *chan, char *ret, size_t ret_l)
486 {
487         snprintf(ret, ret_l, "qid.path: %p, qid.type: %02x", chan->qid.path,
488                          chan->qid.type);
489         return ret;
490 }
491
492 /*
493  * check that the name in a wstat is plausible
494  */
495 void validwstatname(char *name)
496 {
497         validname(name, 0);
498         if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
499                 error(EINVAL, NULL);
500 }
501
502 struct dev *devbyname(char *name)
503 {
504         int i;
505
506         for (i = 0; &devtab[i] < __devtabend; i++)
507                 if (strcmp(devtab[i].name, name) == 0)
508                         return &devtab[i];
509         return NULL;
510 }