Replace most uses of strncpy with strlcpy.
[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 int inumber = 13;
55
56 /* TODO:
57  *  - fix DOTDOT in gen.
58  *  - synchronization!  what needs protection from concurrent use, etc.
59  *      - clean up documentation and whatnot
60  *      - does remove, mkdir, rmdir work?
61  *      - fill this with cpio stuff
62  *      - figure out how to use the page cache
63  */
64
65 /* this gives you some idea of how much I like linked lists. Just make
66  * a big old table. Later on we can put next and prev indices into the
67  * data if we want but, our current kfs is 1-3 levels deep and very small
68  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging
69  * memory a tad easier.
70  */
71 /* Da Rules.
72  * The roottab contains [name, qid, length, perm]. Length means length for files.
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  * Data is [dotdot, ptr, size, *sizep, next]
76  * dotdot is .., ptr is data (for files)
77  * size is # elements (for dirs)
78  * *sizep is a pointer for reasons not understood.
79  * next is the sibling. For a dir, it's the first element after '.'.
80  *      int     dotdot;
81  *      int     child; 
82  *      void    *ptr;
83  *      int     size;
84  *      int     *sizep;
85  * 
86  * entry is empty if type is 0. We look in roottab to determine that. 
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 struct dirtab roottab[MAXFILE] = {
100         {"", {0, 0, QTDIR}, 0, DMDIR | 0777},
101         {"chan", {1, 2, QTDIR}, 0, DMDIR | 0777},
102         {"dev", {2, 3, QTDIR}, 0, DMDIR | 0777},
103         {"fd", {3, 4, QTDIR}, 0, DMDIR | 0777},
104         {"prog", {4, 5, QTDIR}, 0, DMDIR | 0777},
105         {"prof", {5, 6, QTDIR}, 0, DMDIR | 0777},
106         {"net", {6, 7, QTDIR}, 0, DMDIR | 0777},
107         {"net.alt", {7, 8, QTDIR}, 0, DMDIR | 0777},
108         {"nvfs", {8, 9, QTDIR}, 0, DMDIR | 0777},
109         {"env", {9, 10, QTDIR}, 0, DMDIR | 0777},
110         {"root", {10, 11, QTDIR}, 0, DMDIR | 0777},
111         {"srv", {11, 12, QTDIR}, 0, DMDIR | 0777},
112         {"mnt", {12, 13, QTDIR}, 0, DMDIR | 0777},
113         {"proc", {13, 0, QTDIR}, 0, DMDIR | 0777},
114 };
115
116 struct rootdata {
117         int dotdot;
118         int child;
119         void *ptr;
120         int size;
121         int *sizep;
122 };
123
124 struct rootdata rootdata[MAXFILE] = {
125         {0,     1,       &roottab[1],    13,    NULL},
126         {0,     0,       NULL,   0,      NULL},
127         {0,     0,       NULL,   0,      NULL},
128         {0,     0,       NULL,   0,      NULL},
129         {0,     0,       NULL,   0,      NULL},
130         {0,     0,       NULL,   0,      NULL},
131         {0,     0,       NULL,   0,      NULL},
132         {0,     0,       NULL,   0,      NULL},
133         {0,     0,       NULL,   0,      NULL},
134         {0,     0,       NULL,   0,      NULL},
135         {0,     0,       NULL,   0,      NULL},
136         {0,     0,       NULL,   0,      NULL},
137         {0,     0,       NULL,   0,      NULL},
138         {0,     0,       NULL,   0,      NULL},
139 };
140
141 /* this is super useful */
142 void dumprootdev(void)
143 {
144         struct dirtab *r = roottab;
145         struct rootdata *rd = rootdata;
146         int i;
147
148         printk("[       dirtab     ]      name: [pth, ver, typ],   len,        "
149                "perm,  .., chld,       data pointer,  size,       size pointer\n");
150         for (i = 0; i < rootmaxq; i++, r++, rd++) {
151                 if (i && (!r->name[0]))
152                         continue;
153                 printk("[%p]%10s: [%3d, %3d, %3d], %5d, %11o,",
154                            r,
155                            r->name, r->qid.path, r->qid.vers, r->qid.type,
156                            r->length, r->perm);
157                 printk(" %3d, %4d, %p, %5d, %p\n",
158                            rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
159         }
160 }
161
162 static int findempty(void)
163 {
164         int i;
165         for (i = 0; i < rootmaxq; i++) {
166                 if (!roottab[i].qid.type) {
167                         memset(&roottab[i], 0, sizeof(roottab[i]));
168                         return i;
169                 }
170         }
171         return -1;
172 }
173
174 static void freeempty(int i)
175 {
176         roottab[i].qid.type = 0;
177 }
178
179 static int newentry(int parent)
180 {
181         int n = findempty();
182         int sib;
183         if (n < 0)
184                 error(EFAIL, "#root. No more");
185         printd("new entry is %d\n", n);
186         /* add the new one to the head of the linked list.  vers is 'next' */
187         roottab[n].qid.vers = rootdata[parent].child;
188         rootdata[parent].child = n;
189         return n;
190 }
191
192 static int createentry(int dir, char *name, int omode, int perm)
193 {
194         int n = newentry(dir);
195         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
196         roottab[n].length = 0;
197         roottab[n].perm = perm;
198         /* vers is already properly set. */
199         mkqid(&roottab[n].qid, n, roottab[n].qid.vers,
200               perm & DMDIR ? QTDIR : QTFILE);
201         rootdata[n].dotdot = roottab[dir].qid.path;
202         rootdata[dir].ptr = &roottab[n];
203         rootdata[n].size = 0;
204         rootdata[n].sizep = &rootdata[n].size;
205         return n;
206 }
207
208 static void rootinit(void)
209 {
210         /* brho: pretty sure this should only be run once.  putting it in attach
211          * will run it multiple times. */
212         int i;
213         uint32_t len;
214         struct rootdata *r;
215         /* this begins with the root. */
216         for (i = 0;; i++) {
217                 r = &rootdata[i];
218                 if (r->sizep) {
219                         len = *r->sizep;
220                         r->size = len;
221                         roottab[i].length = len;
222                 }
223                 i = roottab[i].qid.vers;
224                 if (!i)
225                         break;
226         }
227 }
228
229 static struct chan *rootattach(char *spec)
230 {
231         struct chan *c;
232         if (*spec)
233                 error(EINVAL, NULL);
234         c = devattach(devname(), spec);
235         mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR);
236         return c;
237 }
238
239 static int
240 rootgen(struct chan *c, char *name,
241                 struct dirtab *tab, int nd, int s, struct dir *dp)
242 {
243         int p, i;
244         struct rootdata *r;
245         int iter;
246         printd("rootgen, path is %d, tap %p, nd %d s %d name %s\n", c->qid.path,
247                tab, nd, s, name);
248
249         if (s == DEVDOTDOT) {
250                 panic("this is busted");
251                 p = rootdata[c->qid.path].dotdot;
252                 // XXX we need to set the vers too.  equiv to mkqid(&c->qid, ...)
253                 c->qid.path = p;
254                 c->qid.type = QTDIR;
255                 name = devname();
256                 if (p != 0) {
257                         /* TODO: what is this doing?  do we want to walk the entire table,
258                          * or are we just walking the siblings of our parent? */
259                         for (i = p;;) {
260                                 if (roottab[i].qid.path == c->qid.path) {
261                                         name = roottab[i].name;
262                                         break;
263                                 }
264                                 i = roottab[i].qid.vers;
265                                 if (!i)
266                                         break;
267                         }
268                 }
269                 devdir(c, c->qid, name, 0, eve, 0777, dp);
270                 return 1;
271         }
272
273         if (c->qid.type != QTDIR) {
274                 /* return ourselved the first time; after that, -1 */
275                 if (s)
276                         return -1;
277                 tab = &roottab[c->qid.path];
278                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
279                 return 1;
280         }
281
282         if (name != NULL) {
283                 int path = c->qid.path;
284                 isdir(c);
285                 tab = &roottab[rootdata[path].child];
286                 /* we're starting at a directory. It might be '.' */
287                 for (iter = 0, i = rootdata[path].child; /* break */; iter++) {
288                         if (strncmp(tab->name, name, KNAMELEN) == 0) {
289                                 printd("Rootgen returns 1 for %s\n", name);
290                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
291                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path,
292                                        dp->qid.vers, dp->qid.type);
293                                 return 1;
294                         }
295                         if (iter > rootmaxq) {
296                                 printk("BUG:");
297                                 dumprootdev();
298                                 printk("name %s\n", name);
299                                 return -1;
300                         }
301                         i = roottab[i].qid.vers;
302                         if (!i)
303                                 break;
304                         tab = &roottab[i];
305                 }
306                 printd("rootgen: :%s: failed at path %d\n", name, path);
307                 return -1;
308         }
309         /* need to gen the file or the contents of the directory we are currently
310          * at.  but i think the tab entries are all over the place.  nd is how
311          * many entries the directory has. */
312         if (s >= nd) {
313                 printd("S OVERFLOW\n");
314                 return -1;
315         }
316         //tab += s;     /* this would only work if our entries were contig in the tab */
317         for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) {
318                 tab = &roottab[i];
319                 if (s-- == 0)
320                         break;
321         }
322         if (!i) {
323                 printd("I OVERFLOW\n");
324                 return -1;
325         }
326         printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name);
327         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
328         return 1;
329 }
330
331 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
332                                                                 int nname)
333 {
334         uint32_t p;
335         if (0){
336                 printk("rootwalk: c %p. :", c);
337                 if (nname){
338                         int i;
339                         for (i = 0; i < nname - 1; i++)
340                                 printk("%s/", name[i]);
341                         printk("%s:\n", name[i]);
342                 }
343         }
344         p = c->qid.path;
345         printd("Start from #%d at %p\n", p, &roottab[p]);
346         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
347 }
348
349 static int rootstat(struct chan *c, uint8_t * dp, int n)
350 {
351         int p = c->qid.path;
352         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
353 }
354
355 static struct chan *rootopen(struct chan *c, int omode)
356 {
357         int p;
358         printd("rootopen: omode %o\n", omode);
359         p = c->qid.path;
360         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
361 }
362
363 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
364 {
365         struct dirtab *r = &roottab[c->qid.path], *newr;
366         struct rootdata *rd = &rootdata[c->qid.path];
367         /* need to filter openmode so that it gets only the access-type bits */
368         omode = openmode(omode);
369         c->mode = openmode(omode);
370         printd("rootcreate: c %p, name %s, omode %o, perm %x\n", 
371                c, name, omode, perm);
372         /* find an empty slot */
373         int path = c->qid.path;
374         int newfile;
375         newfile = createentry(path, name, omode, perm);
376         c->qid = roottab[newfile].qid;  /* need to update c */
377         rd->size++;
378         if (newfile > rootmaxq)
379                 rootmaxq = newfile;
380         printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
381                rootdata[newfile].dotdot, rootmaxq);
382 }
383
384 /*
385  * sysremove() knows this is a nop
386  *              fyi, this isn't true anymore!  they need to set c->type = -1;
387  */
388 static void rootclose(struct chan *c)
389 {
390 }
391
392 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
393 {
394         uint32_t p, len;
395         uint8_t *data;
396
397         p = c->qid.path;
398         if (c->qid.type & QTDIR) {
399                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size,
400                                                   rootgen);
401         }
402         len = rootdata[p].size;
403         if (offset < 0 || offset >= len) {
404                 return 0;
405         }
406         if (offset + n > len)
407                 n = len - offset;
408         data = rootdata[p].ptr;
409         /* we can't really claim it has to be a user address. Lots of
410          * kernel things read directly, e.g. /dev/reboot, #nix, etc.
411          * Address validation should be done in the syscall layer.
412          */
413         memcpy(buf, data + offset, n);
414         return n;
415 }
416
417 /* For now, just kzmalloc the right amount. Later, we should use
418  * pages so mmap will go smoothly. Would be really nice to have a
419  * kpagemalloc ... barret?
420  *              we have kpage_alloc (gives a page) and kpage_alloc_addr (void*)
421  */
422 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
423 {
424         struct rootdata *rd = &rootdata[c->qid.path];
425         struct dirtab *r = &roottab[c->qid.path];
426
427         if (off < 0)
428                 error(EFAIL, "rootwrite: offset < 0!");
429
430         if (off + n > rd->size){
431                 void *p;
432                 p = krealloc(rd->ptr, off + n, KMALLOC_WAIT);
433                 if (! p)
434                         error(EFAIL, "rootwrite: could not grow the file to %d bytes",
435                                   off + n);
436                 rd->ptr = p;
437                 rd->size = off + n;
438         }
439         assert(current);
440         if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0)
441                 error(EFAIL, "%s: bad user addr %p", __FUNCTION__, a);
442
443         return n;
444 }
445
446 static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz)
447 {
448         struct dirtab *file = &roottab[c->qid.path];
449         struct dir *dir;
450         int m_sz;
451
452         /* TODO: some security check, Eperm on error */
453
454         /* common trick in wstats.  we want the dir and any strings in the M.  the
455          * strings are smaller than entire M (strings plus other M).  the strings
456          * will be placed right after the dir (dir[1]) */
457         dir = kzmalloc(sizeof(struct dir) + m_buf_sz, KMALLOC_WAIT);
458         m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]);
459         if (!m_sz) {
460                 kfree(dir);
461                 error(ENODATA, NULL);
462         }
463         /* TODO: handle more things than just the mode */
464         if (!emptystr(dir->name))
465                 printk("[%s] attempted rename of %s to %s\n", __FUNCTION__,
466                        file->name, dir->name);  /* strncpy for this btw */
467         if (dir->mode != ~0UL)
468                 file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0);
469         kfree(dir);
470         return m_sz;
471 }
472
473 struct dev rootdevtab __devtab = {
474         "root",
475         devreset,
476         rootinit,
477         devshutdown,
478         rootattach,
479         rootwalk,
480         rootstat,
481         rootopen,
482         rootcreate,
483         rootclose,
484         rootread,
485         devbread,
486         rootwrite,
487         devbwrite,
488         devremove,
489         rootwstat,
490         devpower,
491         devchaninfo,
492 };