Lindent pass
[akaros.git] / kern / drivers / dev / root.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /* courtesy of the inferno mkroot script. */
17 /* make it a power of 2 and nobody gets hurt */
18 #define MAXFILE 1024
19 int rootmaxq = MAXFILE;
20 int inumber = 13;
21 /* this gives you some idea of how much I like linked lists. Just make
22  * a big old table. Later on we can put next and prev indices into the
23  * data if we want but, our current kfs is 1-3 levels deep and very small
24  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging
25  * memory a tad easier.
26  */
27 /* Da Rules.
28  * The roottab contains [name, qid, length, perm]. Length means length for files.
29  * Qid is [path, vers, type]. Path is me. vers is next. Type is 'd' for dir
30  * and 'f' for file and 0 for empty.
31  * Data is [dotdot, ptr, size, *sizep, next]
32  * dotdot is .., ptr is data (for files)
33  * size is # elements (for dirs)
34  * *sizep is a pointer for reasons not understood.
35  * next is the sibling. For a dir, it's the first element after '.'.
36  *      int     dotdot;
37  *      int     child; 
38  *      void    *ptr;
39  *      int     size;
40  *      int     *sizep;
41  * 
42  * entry is empty if type is 0. We look in roottab to determine that. 
43 */
44 /* we pack the qid as follows: path is the index, vers is ., and type is type */
45 struct dirtab roottab[MAXFILE] = {
46         {"", {0, 1, QTDIR}, 0, 0777},
47         {"chan", {1, 2, QTDIR}, 0, 0777},
48         {"dev", {2, 3, QTDIR}, 0, 0777},
49         {"fd", {3, 4, QTDIR}, 0, 0777},
50         {"prog", {4, 5, QTDIR}, 0, 0777},
51         {"prof", {5, 6, QTDIR}, 0, 0777},
52         {"net", {6, 7, QTDIR}, 0, 0777},
53         {"net.alt", {7, 8, QTDIR}, 0, 0777},
54         {"nvfs", {8, 9, QTDIR}, 0, 0777},
55         {"env", {9, 10, QTDIR}, 0, 0777},
56         {"root", {10, 11, QTDIR}, 0, 0777},
57         {"srv", {11, 12, QTDIR}, 0, 0777},
58         /* not courtesy of mkroot */
59         {"mnt", {12, 0, QTDIR}, 0, 0777},
60 };
61
62 struct rootdata {
63         int dotdot;
64         int child;
65         void *ptr;
66         int size;
67         int *sizep;
68 };
69
70 struct rootdata rootdata[MAXFILE] = {
71         {0, 0, &roottab[1], 12, NULL},
72         {0, 0, NULL, 0, NULL},
73         {0, 0, NULL, 0, NULL},
74         {0, 0, NULL, 0, NULL},
75         {0, 0, NULL, 0, NULL},
76         {0, 0, NULL, 0, NULL},
77         {0, 0, NULL, 0, NULL},
78         {0, 0, NULL, 0, NULL},
79         {0, 0, NULL, 0, NULL},
80         {0, 0, NULL, 0, NULL},
81         {0, 0, NULL, 0, NULL},
82         {0, 0, NULL, 0, NULL},
83         {0, 0, NULL, 0, NULL},
84 };
85
86 void dumprootdev(void)
87 {
88         struct dirtab *r = roottab;
89         struct rootdata *rd = rootdata;
90         int i;
91
92         for (i = 0; i < rootmaxq; i++, r++, rd++) {
93                 if (i && (!r->name[0]))
94                         continue;
95                 printk("[%p]%s: [%d, %d, %d], %d, %o; ",
96                            r,
97                            r->name, r->qid.path, r->qid.vers, r->qid.type,
98                            r->length, r->perm);
99                 printk("dotdot %d, child %d, ptr %p, size %d, sizep %p\n",
100                            rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
101         }
102 }
103
104 static int findempty(void)
105 {
106         int i;
107         for (i = 0; i < rootmaxq; i++) {
108                 if (!roottab[i].qid.type) {
109                         return i;
110                 }
111         }
112         memset(&roottab[i], 0, sizeof(roottab[i]));
113         return -1;
114 }
115
116 static void freeempty(int i)
117 {
118         roottab[i].qid.type = 0;
119 }
120
121 static int newentry(int old)
122 {
123         int n = findempty();
124         int sib;
125         if (n < 0)
126                 error("#r. No more");
127         printk("new entry is %d\n", n);
128         sib = rootdata[old].child;
129         if (sib) {
130                 roottab[n].qid.vers = roottab[sib].qid.vers;
131                 roottab[sib].qid.vers = n;
132         }
133         rootdata[old].child = n;
134         return n;
135 }
136
137 static int createentry(int dir, char *name, int length, int perm)
138 {
139         int n = newentry(dir);
140         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
141         roottab[n].length;
142         roottab[n].perm = perm;
143         /* vers is already properly set. */
144         mkqid(&roottab[n].qid, n, roottab[n].qid.vers, perm & DMDIR ? QTDIR : 'f');
145         rootdata[n].dotdot = roottab[dir].qid.path;
146         rootdata[dir].ptr = &roottab[n];
147         rootdata[n].size = 0;
148         rootdata[n].sizep = &rootdata[n].size;
149         return n;
150 }
151
152 static struct chan *rootattach(char *spec)
153 {
154         int i;
155         uint32_t len;
156         struct rootdata *r;
157
158         if (*spec)
159                 error(Ebadspec);
160         /* this begins with the root. */
161         for (i = 0;; i++) {
162                 r = &rootdata[i];
163                 if (r->sizep) {
164                         len = *r->sizep;
165                         r->size = len;
166                         roottab[i].length = len;
167                 }
168                 i = roottab[i].qid.vers;
169                 if (!i)
170                         break;
171         }
172         return devattach('r', spec);
173 }
174
175 static int
176 rootgen(struct chan *c, char *name,
177                 struct dirtab *tab, int nd, int s, struct dir *dp)
178 {
179         int p, i;
180         struct rootdata *r;
181         int iter;
182         printk("rootgen, path is %d, tap %p, nd %d s %d\n",
183                    rootdata[c->qid.path].dotdot, tab, nd, s);
184
185         if (s == DEVDOTDOT) {
186                 printk("rootgen, DEVDOTDOT\n");
187                 p = rootdata[c->qid.path].dotdot;
188                 c->qid.path = p;
189                 c->qid.type = QTDIR;
190                 name = "#r";
191                 if (p != 0) {
192                         for (i = p;;) {
193                                 if (roottab[i].qid.path == c->qid.path) {
194                                         name = roottab[i].name;
195                                         break;
196                                 }
197                                 i = roottab[i].qid.vers;
198                                 if (!i)
199                                         break;
200                         }
201                 }
202                 devdir(c, c->qid, name, 0, eve, 0777, dp);
203                 return 1;
204         }
205
206         if (name != NULL) {
207                 int path = c->qid.path;
208                 isdir(c);
209                 tab = &roottab[path];
210                 /* we're starting at a directory. It might be '.' */
211                 for (iter = 0, i = path;; iter++) {
212                         if (strcmp(tab->name, name) == 0) {
213                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
214                                 return 1;
215                         }
216                         if (iter > rootmaxq) {
217                                 printk("BUG:");
218                                 dumprootdev();
219                                 printk("name %s\n", name);
220                                 return -1;
221                         }
222                         i = roottab[i].qid.vers;
223                         if (!i)
224                                 break;
225                         tab = &roottab[i];
226                 }
227                 return -1;
228         }
229
230         if (s >= nd) {
231                 return -1;
232         }
233         tab += s;
234
235         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
236         return 1;
237 }
238
239 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
240                                                                 int nname)
241 {
242         uint32_t p;
243         if (0) {
244                 printk("rootwalk: c %p. ", c);
245                 if (nname) {
246                         int i;
247                         for (i = 0; i < nname - 1; i++)
248                                 printk("%s/", name[i]);
249                         printk("%s", name[i]);
250                 }
251         }
252         p = c->qid.path;
253         if (nname == 0)
254                 p = rootdata[p].dotdot;
255         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
256 }
257
258 static int rootstat(struct chan *c, uint8_t * dp, int n)
259 {
260         int p;
261
262         p = rootdata[c->qid.path].dotdot;
263         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
264 }
265
266 static struct chan *rootopen(struct chan *c, int omode)
267 {
268         int p;
269
270         p = rootdata[c->qid.path].dotdot;
271         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
272 }
273
274 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
275 {
276         struct dirtab *r = &roottab[c->qid.path], *newr;
277         struct rootdata *rd = &rootdata[c->qid.path];
278         if (1)
279                 printk("rootcreate: c %p, name %s, omode %o, perm %x\n",
280                            c, name, omode, perm);
281         /* find an empty slot */
282         //wlock(&root)
283         int path = c->qid.path;
284         int newfile;
285         newfile = createentry(path, name, omode, perm);
286         rd->size++;
287         if (newfile > rootmaxq)
288                 rootmaxq = newfile;
289         if (1)
290                 printk("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name,
291                            newfile, rootdata[newfile].dotdot, rootmaxq);
292 }
293
294 /*
295  * sysremove() knows this is a nop
296  */
297 static void rootclose(struct chan *c)
298 {
299 }
300
301 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
302 {
303         uint32_t p, len;
304         uint8_t *data;
305
306         p = c->qid.path;
307         if (c->qid.type & QTDIR) {
308                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size,
309                                                   rootgen);
310         }
311         len = rootdata[p].size;
312         if (offset < 0 || offset >= len) {
313                 return 0;
314         }
315         if (offset + n > len)
316                 n = len - offset;
317         data = rootdata[p].ptr;
318         memmove(buf, data + offset, n);
319         return n;
320 }
321
322 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
323 {
324         error(Eperm);
325         return 0;
326 }
327
328 struct dev rootdevtab __devtab = {
329         'r',
330         "root",
331         devreset,
332         devinit,
333         devshutdown,
334         rootattach,
335         rootwalk,
336         rootstat,
337         rootopen,
338         rootcreate,
339         rootclose,
340         rootread,
341         devbread,
342         rootwrite,
343         devbwrite,
344         devremove,
345         devwstat,
346         devpower,
347         devchaninfo,
348 };