Finally! at least the hierarchy is right
[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,     1,       &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         printd("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 = 0;
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         printd("rootgen, path is %d, tap %p, nd %d s %d name %s\n", c->qid.path,
183                tab, nd, s, name);
184
185         if(s == DEVDOTDOT){
186                 p = rootdata[c->qid.path].dotdot;
187                 c->qid.path = p;
188                 c->qid.type = QTDIR;
189                 name = "#r";
190                 if (p != 0) {
191                         for (i = p;;) {
192                                 if (roottab[i].qid.path == c->qid.path) {
193                                         name = roottab[i].name;
194                                         break;
195                                 }
196                                 i = roottab[i].qid.vers;
197                                 if (!i)
198                                         break;
199                         }
200                 }
201                 devdir(c, c->qid, name, 0, eve, 0777, dp);
202                 return 1;
203         }
204
205         if (name != NULL) {
206                 int path = c->qid.path;
207                 isdir(c);
208                 tab = &roottab[rootdata[path].child];
209                 /* we're starting at a directory. It might be '.' */
210                 for(iter = 0, i=path; ; iter++){
211                         if(strcmp(tab->name, name) == 0){
212                                 printd("Rootgen returns 1 for %s\n", name);
213                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
214                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path, c->qid.vers, c->qid.type);
215                                 return 1;
216                         }
217                         if (iter > rootmaxq) {
218                                 printk("BUG:");
219                                 dumprootdev();
220                                 printk("name %s\n", name);
221                                 return -1;
222                         }
223                         i = roottab[i].qid.vers;
224                         if (!i)
225                                 break;
226                         tab = &roottab[i];
227                 }
228                 printd("rootgen: :%s: failed at path %d\n", name, path);
229                 return -1;
230         }
231
232         if (s >= nd) {
233                 return -1;
234         }
235         tab += s;
236
237         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
238         return 1;
239 }
240
241 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
242                                                                 int nname)
243 {
244         uint32_t p;
245         if (0){
246                 printk("rootwalk: c %p. :", c);
247                 if (nname){
248                         int i;
249                         for (i = 0; i < nname - 1; i++)
250                                 printk("%s/", name[i]);
251                         printk("%s:\n", name[i]);
252                 }
253         }
254         p = c->qid.path;
255         if((nname == 0) && 0)
256                 p = rootdata[p].dotdot;
257         printd("Start from #%d at %p\n", p, &roottab[p]);
258         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
259 }
260
261 static int rootstat(struct chan *c, uint8_t * dp, int n)
262 {
263         int p;
264
265         p = rootdata[c->qid.path].dotdot;
266         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
267 }
268
269 static struct chan *rootopen(struct chan *c, int omode)
270 {
271         int p;
272
273         p = c->qid.path;
274         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
275 }
276
277 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
278 {
279         struct dirtab *r = &roottab[c->qid.path], *newr;
280         struct rootdata *rd = &rootdata[c->qid.path];
281         if (0)printk("rootcreate: c %p, name %s, omode %o, perm %x\n", 
282                c, name, omode, perm);
283         /* find an empty slot */
284         int path = c->qid.path;
285         int newfile;
286         newfile = createentry(path, name, omode, perm);
287         rd->size++;
288         if (newfile > rootmaxq)
289                 rootmaxq = newfile;
290         if (0) printk("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
291                   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 };