devroot: Fix stat and clean up rootgen.
[akaros.git] / kern / drivers / dev / root.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 #include <umem.h>
43
44 struct dev rootdevtab;
45
46 static char *devname(void)
47 {
48         return rootdevtab.name;
49 }
50
51 /* make it a power of 2 and nobody gets hurt */
52 #define MAXFILE 1024
53 int rootmaxq = MAXFILE;
54
55 /* TODO:
56  *  - synchronization!  what needs protection from concurrent use, etc.
57  *      - clean up documentation and whatnot
58  *      - does remove, mkdir, rmdir work?
59  *      - fill this with cpio stuff
60  *      - figure out how to use the page cache
61  *      - atime/ctime/mtime/etctime
62  */
63
64 /* this gives you some idea of how much I like linked lists. Just make
65  * a big old table. Later on we can put next and prev indices into the
66  * data if we want but, our current kfs is 1-3 levels deep and very small
67  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging
68  * memory a tad easier.
69  */
70 /* Da Rules.
71  * The roottab contains [name, qid, length, perm].
72  * Length is filesize for files, # children/elements for dirs
73  * Qid is [path, vers, type]. Path is me. vers is next. Type is QTDIR for dir
74  * and QTFILE for file and 0 for empty.
75  *
76  * We have rootdata to help out with a couple things, notably storing the 'data'
77  * of the object (file or dir) and the first child index/qid.path for
78  * directories.
79  *
80  * Data is [dotdot, child, ptr]
81  * dotdot is ..
82  * ptr is data for files, first child for dirs.
83  * child is the qid.path of the first child of a directory.
84  * Possibly 0 == no child.
85  * To find the next sibling (in a directory), look at roottab[i].qid.vers.
86  */
87
88 /* we pack the qid as follows: path is the index, vers is ., and type is type */
89
90 /* Inferno seems to want to: perm |= DMDIR.  It gets checked in other places.
91  * NxM didn't want this, IIRC.
92  *
93  * Also note that "" (/, #root, whatever) has no vers/next/sibling.
94  *
95  * If you want to add new entries, add it to the roottab such that the linked
96  * list of indexes is a cycle (change the last current one), then add an entry
97  * to rootdata, and then change the first rootdata entry to have another entry.
98  * Yeah, it's a pain in the ass.
99  *
100  * To add subdirectories, or any child of a directory, the files (e.g. env_dir1)
101  * go in roottab.  Children of a parent are linked with their vers (note
102  * env_dir1 points to env_dir2), and the last item's vers = 0.  These files need
103  * their dotdot set in rootdata to the qid of their parent.  The directory that
104  * has children needs its child pointer set to the first qid in the list, and
105  * its data pointer must point to the roottab entry for the child.  This also
106  * means that all child entries in roottab for a parent must be contiguous.
107  *
108  * Yeah, it's a pain in the ass.  And, given this structure, it probably can't
109  * grow dynamically (I think we assume roottab[i] = entry for qid.path all over
110  * the place - imagine what happens if we wanted to squeeze in a new entry). */
111 struct dirtab roottab[MAXFILE] = {
112         {"",                            { 0,  0, QTDIR}, 13, DMDIR | 0777},
113         {"chan",                        { 1,  2, QTDIR},  0, DMDIR | 0777},
114         {"dev",                         { 2,  3, QTDIR},  0, DMDIR | 0777},
115         {"fd",                          { 3,  4, QTDIR},  0, DMDIR | 0777},
116         {"prog",                        { 4,  5, QTDIR},  0, DMDIR | 0777},
117         {"prof",                        { 5,  6, QTDIR},  0, DMDIR | 0777},
118         {"net",                         { 6,  7, QTDIR},  0, DMDIR | 0777},
119         {"net.alt",                     { 7,  8, QTDIR},  0, DMDIR | 0777},
120         {"nvfs",                        { 8,  9, QTDIR},  0, DMDIR | 0777},
121         {"env",                         { 9, 10, QTDIR},  2, DMDIR | 0777},
122         {"root",                        {10, 11, QTDIR},  0, DMDIR | 0777},
123         {"srv",                         {11, 12, QTDIR},  0, DMDIR | 0777},
124         {"mnt",                         {12, 13, QTDIR},  0, DMDIR | 0777},
125         {"proc",                        {13,  0, QTDIR},  0, DMDIR | 0777},
126         {"env_dir1",            {14, 15, QTDIR},  0, DMDIR | 0777},
127         {"env_dir2",            {15,  0, QTDIR},  0, DMDIR | 0777},
128 };
129
130 struct rootdata {
131         int dotdot;
132         int child;
133         void *ptr;
134 };
135
136 struct rootdata rootdata[MAXFILE] = {
137         {0,     1,       &roottab[1]},
138         {0,     0,       NULL},
139         {0,     0,       NULL},
140         {0,     0,       NULL},
141         {0,     0,       NULL},
142         {0,     0,       NULL},
143         {0,     0,       NULL},
144         {0,     0,       NULL},
145         {0,     0,       NULL},
146         {0,     14,      &roottab[14]},
147         {0,     0,       NULL},
148         {0,     0,       NULL},
149         {0,     0,       NULL},
150         {0,     0,       NULL},
151         {9,     0,       NULL},
152         {9,     0,       NULL},
153 };
154
155 /* this is super useful */
156 void dumprootdev(void)
157 {
158         struct dirtab *r = roottab;
159         struct rootdata *rd = rootdata;
160         int i;
161
162         printk("[       dirtab     ]                          name: [pth, ver, typ],   len,        perm,  .., chld,       data pointer\n");
163         for (i = 0; i < rootmaxq; i++, r++, rd++) {
164                 if (i && (!r->name[0]))
165                         continue;
166                 printk("[%p]%30s: [%3d, %3d, %3d], %5d, %11o,",
167                            r,
168                            r->name, r->qid.path, r->qid.vers, r->qid.type,
169                            r->length, r->perm);
170                 printk(" %3d, %4d, %p\n", rd->dotdot, rd->child, rd->ptr);
171         }
172 }
173
174 static int findempty(void)
175 {
176         int i;
177         for (i = 0; i < rootmaxq; i++) {
178                 if (!roottab[i].qid.type) {
179                         memset(&roottab[i], 0, sizeof(roottab[i]));
180                         return i;
181                 }
182         }
183         return -1;
184 }
185
186 static void freeempty(int i)
187 {
188         roottab[i].qid.type = 0;
189 }
190
191 static int newentry(int parent)
192 {
193         int n = findempty();
194         int sib;
195         if (n < 0)
196                 error(EFAIL, "#root. No more");
197         printd("new entry is %d\n", n);
198         /* add the new one to the head of the linked list.  vers is 'next' */
199         roottab[n].qid.vers = rootdata[parent].child;
200         rootdata[parent].child = n;
201         return n;
202 }
203
204 static int createentry(int dir, char *name, int omode, int perm)
205 {
206         int n = newentry(dir);
207         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
208         roottab[n].length = 0;
209         roottab[n].perm = perm;
210         /* vers is already properly set. */
211         mkqid(&roottab[n].qid, n, roottab[n].qid.vers,
212               perm & DMDIR ? QTDIR : QTFILE);
213         rootdata[n].dotdot = roottab[dir].qid.path;
214         rootdata[dir].ptr = &roottab[n];
215         return n;
216 }
217
218 static void rootinit(void)
219 {
220 }
221
222 static struct chan *rootattach(char *spec)
223 {
224         struct chan *c;
225         if (*spec)
226                 error(EINVAL, ERROR_FIXME);
227         c = devattach(devname(), spec);
228         mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR);
229         return c;
230 }
231
232 /* rootgen is unlike other gens when it comes to the dirtab (tab) and ntab (nd).
233  * We actually are a linked list of entries that happen to be in a table.  We
234  * can figure out where to start based on the chan's qid.path and start the gen
235  * from there.  So we don't need the 'tab' from dev.  Likewise, for directories,
236  * we can figure out nd - our length in the dirtab. */
237 static int rootgen(struct chan *c, char *name, struct dirtab *tab_unused,
238                    int nd_unused, int s, struct dir *dp)
239 {
240         int p, i;
241         struct rootdata *r;
242         int iter;
243         struct dirtab *tab;
244
245         printd("rootgen from %s, for %s, s %d\n", roottab[c->qid.path].name, name,
246                s);
247         if (s == DEVDOTDOT) {
248                 p = rootdata[c->qid.path].dotdot;
249                 c->qid = roottab[p].qid;
250                 name = roottab[p].name;
251                 devdir(c, c->qid, name, 0, eve.name, 0777, dp);
252                 return 1;
253         }
254
255         if (c->qid.type != QTDIR) {
256                 /* return ourselved the first time; after that, -1 */
257                 if (s)
258                         return -1;
259                 tab = &roottab[c->qid.path];
260                 devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp);
261                 return 1;
262         }
263
264         if (name != NULL) {
265                 int path = c->qid.path;
266                 isdir(c);
267                 tab = &roottab[rootdata[path].child];
268                 /* we're starting at a directory. It might be '.' */
269                 for (iter = 0, i = rootdata[path].child; /* break */; iter++) {
270                         if (strncmp(tab->name, name, KNAMELEN) == 0) {
271                                 printd("Rootgen returns 1 for %s\n", name);
272                                 devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm,
273                                        dp);
274                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path,
275                                        dp->qid.vers, dp->qid.type);
276                                 return 1;
277                         }
278                         if (iter > rootmaxq) {
279                                 printk("BUG:");
280                                 dumprootdev();
281                                 printk("name %s\n", name);
282                                 return -1;
283                         }
284                         i = roottab[i].qid.vers;
285                         if (!i)
286                                 break;
287                         tab = &roottab[i];
288                 }
289                 printd("rootgen: :%s: failed at path %d\n", name, path);
290                 return -1;
291         }
292         /* Note we do not provide a "direct gen" for directories, which normally I'd
293          * do here.  If we do, that will confuse devdirread, which expects us to
294          * list our children, not ourselves.  stat() wants a "direct gen", e.g. for
295          * ls -l or stat of a directory.  We can handle that in rootstat(). */
296         if (s >= roottab[c->qid.path].length)
297                 return -1;
298         for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) {
299                 tab = &roottab[i];
300                 if (s-- == 0)
301                         break;
302         }
303         if (!i) {
304                 warn("#root overflowed 'i', probably a bug");
305                 return -1;
306         }
307         printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name);
308         devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp);
309         return 1;
310 }
311
312 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
313                                                                 int nname)
314 {
315         return devwalk(c, nc, name, nname, NULL, 0, rootgen);
316 }
317
318 /* Instead of using devstat, we use our own.  This allows us to have stats on
319  * directories.  devstat() just fakes it.  Note that gen cannot return a direct
320  * gen for a directory, since that would break devdirread(). */
321 static int rootstat(struct chan *c, uint8_t * dp, int n)
322 {
323         struct dir dir[1];
324         ssize_t ret;
325         struct dirtab *entry = &roottab[c->qid.path];
326
327         /* TODO: this assumes eve is the user, which is what synthetic devices do.
328          * Likewise, it sets atime/mtime like a synth device.  There might be other
329          * weird things, like qid.type and mode. */
330         devdir(c, entry->qid, entry->name, entry->length, eve.name, entry->perm,
331                dir);
332         ret = convD2M(dir, dp, n);
333         if (!ret)
334                 error(EFAIL, "#root failed to convert stat object to M");
335         return ret;
336 }
337
338 static struct chan *rootopen(struct chan *c, int omode)
339 {
340         return devopen(c, omode, NULL, 0, rootgen);
341 }
342
343 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
344 {
345         struct dirtab *r = &roottab[c->qid.path], *newr;
346         struct rootdata *rd = &rootdata[c->qid.path];
347         /* need to filter openmode so that it gets only the access-type bits */
348         omode = openmode(omode);
349         c->mode = openmode(omode);
350         printd("rootcreate: c %p, name %s, omode %o, perm %x\n",
351                c, name, omode, perm);
352         /* find an empty slot */
353         int path = c->qid.path;
354         int newfile;
355         newfile = createentry(path, name, omode, perm);
356         c->qid = roottab[newfile].qid;  /* need to update c */
357         r->length++;
358         if (newfile > rootmaxq)
359                 rootmaxq = newfile;
360         printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
361                rootdata[newfile].dotdot, rootmaxq);
362 }
363
364 /*
365  * sysremove() knows this is a nop
366  *              fyi, this isn't true anymore!  they need to set c->type = -1;
367  */
368 static void rootclose(struct chan *c)
369 {
370 }
371
372 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
373 {
374         uint32_t p, len;
375         uint8_t *data;
376
377         p = c->qid.path;
378         if (c->qid.type & QTDIR)
379                 return devdirread(c, buf, n, NULL, 0, rootgen);
380         len = roottab[p].length;
381         if (offset < 0 || offset >= len) {
382                 return 0;
383         }
384         if (offset + n > len)
385                 n = len - offset;
386         data = rootdata[p].ptr;
387         /* we can't really claim it has to be a user address. Lots of
388          * kernel things read directly, e.g. /dev/reboot, #nix, etc.
389          * Address validation should be done in the syscall layer.
390          */
391         memcpy(buf, data + offset, n);
392         return n;
393 }
394
395 /* For now, just kzmalloc the right amount. Later, we should use
396  * pages so mmap will go smoothly. Would be really nice to have a
397  * kpagemalloc ... barret?
398  *              we have kpage_alloc (gives a page) and kpage_alloc_addr (void*)
399  */
400 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
401 {
402         struct rootdata *rd = &rootdata[c->qid.path];
403         struct dirtab *r = &roottab[c->qid.path];
404
405         if (off < 0)
406                 error(EFAIL, "rootwrite: offset < 0!");
407
408         if (off + n > r->length) {
409                 void *p;
410                 p = krealloc(rd->ptr, off + n, MEM_WAIT);
411                 if (! p)
412                         error(EFAIL, "rootwrite: could not grow the file to %d bytes",
413                                   off + n);
414                 rd->ptr = p;
415                 r->length = off + n;
416         }
417         assert(current);
418         if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0)
419                 error(EFAIL, "%s: bad user addr %p", __FUNCTION__, a);
420
421         return n;
422 }
423
424 static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz)
425 {
426         struct dirtab *file = &roottab[c->qid.path];
427         struct dir *dir;
428         int m_sz;
429
430         /* TODO: some security check, Eperm on error */
431
432         /* common trick in wstats.  we want the dir and any strings in the M.  the
433          * strings are smaller than entire M (strings plus other M).  the strings
434          * will be placed right after the dir (dir[1]) */
435         dir = kzmalloc(sizeof(struct dir) + m_buf_sz, MEM_WAIT);
436         m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]);
437         if (!m_sz) {
438                 kfree(dir);
439                 error(ENODATA, ERROR_FIXME);
440         }
441         /* TODO: handle more things than just the mode */
442         if (!emptystr(dir->name))
443                 printk("[%s] attempted rename of %s to %s\n", __FUNCTION__,
444                        file->name, dir->name);  /* strncpy for this btw */
445         if (dir->mode != ~0UL)
446                 file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0);
447         kfree(dir);
448         return m_sz;
449 }
450
451 struct dev rootdevtab __devtab = {
452         .name = "root",
453         .reset = devreset,
454         .init = rootinit,
455         .shutdown = devshutdown,
456         .attach = rootattach,
457         .walk = rootwalk,
458         .stat = rootstat,
459         .open = rootopen,
460         .create = rootcreate,
461         .close = rootclose,
462         .read = rootread,
463         .bread = devbread,
464         .write = rootwrite,
465         .bwrite = devbwrite,
466         .remove = devremove,
467         .wstat = rootwstat,
468         .power = devpower,
469         .chaninfo = devchaninfo,
470 };