rootdev with a bit fewer errors.
[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 '.'. 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  *      void    *ptr;
38  *      int     size;
39  *      int     *sizep;
40  * 
41  * entry is empty if type is 0. We look in roottab to determine that. 
42 */
43 /* we pack the qid as follows: path is the index, vers is ., and type is type */
44 struct dirtab roottab[MAXFILE] = {
45         {"",    {0, 1, QTDIR},   0,     0777},
46         {"chan",{1, 2, QTDIR},   0,     0777},
47         {"dev", {2, 3, QTDIR},   0,     0777},
48         {"fd",  {3, 4, QTDIR},   0,     0777},
49         {"prog",{4, 5, QTDIR},   0,     0777},
50         {"prof",{5, 6, QTDIR},   0,     0777},
51         {"net", {6, 7, QTDIR},   0,     0777},
52         {"net.alt",{7, 8, QTDIR},0,     0777},
53         {"nvfs",{8, 9, QTDIR},   0,     0777},
54         {"env", {9, 10, QTDIR},  0,     0777},
55         {"root",{10, 11, QTDIR},         0,     0777},
56         {"srv", {11, 12, QTDIR},         0,     0777},
57         /* not courtesy of mkroot */
58         {"mnt", {12, 0, QTDIR},  0,     0777},
59 };
60
61 struct rootdata
62 {
63         int     dotdot;
64         void    *ptr;
65         int     size;
66         int     *sizep;
67 };
68
69 struct rootdata rootdata[MAXFILE] = {
70         {0,      &roottab[1],    12,    NULL},
71         {0,      NULL,   0,      NULL},
72         {0,      NULL,   0,      NULL},
73         {0,      NULL,   0,      NULL},
74         {0,      NULL,   0,      NULL},
75         {0,      NULL,   0,      NULL},
76         {0,      NULL,   0,      NULL},
77         {0,      NULL,   0,      NULL},
78         {0,      NULL,   0,      NULL},
79         {0,      NULL,   0,      NULL},
80         {0,      NULL,   0,      NULL},
81         {0,      NULL,   0,      NULL},
82         {0,      NULL,   0,      NULL},
83 };
84
85 void dumprootdev(void)
86 {
87         struct dirtab *r = roottab;
88         struct rootdata *rd = rootdata;
89         int i;
90
91         for(i = 0; i < rootmaxq; i++, r++, rd++){
92                 if (i && (! r->name[0]))
93                         continue;
94                 printk("%s: [%d, %d, %d], %d, %o; ",
95                        r->name, r->qid.path, r->qid.vers, r->qid.type,
96                        r->length, r->perm);
97                 printk("dotdot %d, ptr %p, size %d, sizep %p\n", 
98                        rd->dotdot, rd->ptr, rd->size, rd->sizep);
99         }
100 }
101
102 static int findempty(void)
103 {
104         int i;
105         for(i = 0; i < rootmaxq; i++){
106                 if (!roottab[i].qid.type)
107                         return i;
108         }
109         memset(&roottab[i], 0, sizeof(roottab[i]));
110         return -1;
111 }
112
113 static void freeempty(int i)
114 {
115         roottab[i].qid.type = 0;
116 }
117
118 static int newentry(int old)
119 {
120         int n = findempty();
121         if (n < 0)
122                 error("#r. No more");
123         printk("new entry is %d\n", n);
124         dumprootdev();
125         roottab[n].qid.vers = roottab[old].qid.vers;
126         roottab[old].qid.vers = n;
127         dumprootdev();
128         return n;
129 }
130
131 static int createentry(int dir, char *name, int length, int perm)
132 {
133         int n = newentry(dir);
134         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
135         roottab[n].length;
136         roottab[n].perm = perm;
137         /* vers is already properly set. */
138         mkqid(&roottab[n].qid, n, roottab[n].qid.vers, perm&DMDIR ? QTDIR : 'f');
139         rootdata[n].dotdot = roottab[dir].qid.path;
140         rootdata[n].ptr = &roottab[n];
141         rootdata[n].size = 0;
142         rootdata[n].sizep = &rootdata[n].size;
143         dumprootdev();
144         return n;
145 }
146
147 static struct chan*
148 rootattach(char *spec)
149 {
150         int i;
151         uint32_t len;
152         struct rootdata *r;
153
154         if(*spec)
155                 error(Ebadspec);
156         /* this begins with the root. */
157         for (i = 0; ;i++){
158                 r = &rootdata[i];
159                 if (r->sizep){
160                         len = *r->sizep;
161                         r->size = len;
162                         roottab[i].length = len;
163                 }
164                 i = roottab[i].qid.vers;
165                 if (! i)
166                         break;
167         }
168         return devattach('r', spec);
169 }
170
171 static int
172 rootgen(struct chan *c, char *name,
173         struct dirtab *tab, int nd, int s, struct dir *dp)
174 {
175         int p, i;
176         struct rootdata *r;
177         int iter;
178
179         if(s == DEVDOTDOT){
180                 p = rootdata[c->qid.path].dotdot;
181                 c->qid.path = p;
182                 c->qid.type = QTDIR;
183                 name = "#r";
184                 if(p != 0){
185                         for(i = 0; ;){
186                                 if(roottab[i].qid.path == c->qid.path){
187                                         name = roottab[i].name;
188                                         break;
189                                 }
190                                 i = roottab[i].qid.vers;
191                                 if (! i)
192                                         break;
193                         }
194                 }
195                 devdir(c, c->qid, name, 0, eve, 0777, dp);
196                 return 1;
197         }
198
199         if(name != NULL){
200                 int path = c->qid.path;
201                 isdir(c);
202                 tab = &roottab[path];
203                 /* we're starting at a directory. It might be '.' */
204                 for(iter = 0, i=path; ; iter++){
205                         if(strcmp(tab->name, name) == 0){
206                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
207                                 return 1;
208                         }
209                         if (iter > rootmaxq){
210                                 printk("BUG:");
211                                 dumprootdev();
212                                 printk("name %s\n", name);
213                                 return -1;
214                         }
215                         i = roottab[i].qid.vers;
216                         if (! i)
217                                 break;
218                         tab = &roottab[i];
219                 }
220                 return -1;
221         }
222
223         if(s >= nd)
224                 return -1;
225         tab += s;
226
227         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
228         return 1;
229 }
230
231 static struct walkqid*
232 rootwalk(struct chan *c, struct chan *nc, char **name, int nname)
233 {
234         uint32_t p;
235         if (0){
236                 printk("rootwalk: c %p. ", c);
237                 if (nname){
238                         int i;
239                         for(i = 0; i < nname-1; i++)
240                                 printk("%s/", name[i]);
241                         printk("%s", name[i]);
242                 }
243         }
244         p = c->qid.path;
245         if(nname == 0)
246                 p = rootdata[p].dotdot;
247         return devwalk(c, nc, name, nname, rootdata[p].ptr, rootdata[p].size, rootgen);
248 }
249
250 static int
251 rootstat(struct chan *c, uint8_t *dp, int n)
252 {
253         int p;
254
255         p = rootdata[c->qid.path].dotdot;
256         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
257 }
258
259 static struct chan*
260 rootopen(struct chan *c, int omode)
261 {
262         int p;
263
264         p = rootdata[c->qid.path].dotdot;
265         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
266 }
267
268 static void
269 rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
270 {
271         struct dirtab *r = &roottab[c->qid.path], *newr;
272         struct rootdata *rd = &rootdata[c->qid.path];
273         if (1)printk("rootcreate: c %p, name %s, omode %o, perm %x\n", 
274                c, name, omode, perm);
275         /* find an empty slot */
276         //wlock(&root)
277         int path = c->qid.path;
278         int newfile;
279         newfile = createentry(path, name, omode, perm);
280         rd->size++;
281         if (newfile > rootmaxq)
282                 rootmaxq = newfile;
283         if (1) printk("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
284                   rootdata[newfile].dotdot, rootmaxq);
285 }
286
287 /*
288  * sysremove() knows this is a nop
289  */
290 static void      
291 rootclose(struct chan *c)
292 {
293 }
294
295 static long      
296 rootread(struct chan *c, void *buf, long n, int64_t offset)
297 {
298         uint32_t p, len;
299         uint8_t *data;
300
301         p = c->qid.path;
302         if(c->qid.type & QTDIR)
303                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size, rootgen);
304         len = rootdata[p].size;
305         if(offset < 0 || offset >= len)
306                 return 0;
307         if(offset+n > len)
308                 n = len - offset;
309         data = rootdata[p].ptr;
310         memmove(buf, data+offset, n);
311         return n;
312 }
313
314
315 static long      
316 rootwrite(struct chan *c, void *a, long n, int64_t off)
317 {
318         error(Eperm);
319         return 0;
320 }
321
322 struct dev rootdevtab __devtab = {
323         'r',
324         "root",
325         devreset,
326         devinit,
327         devshutdown,
328         rootattach,
329         rootwalk,
330         rootstat,
331         rootopen,
332         rootcreate,
333         rootclose,
334         rootread,
335         devbread,
336         rootwrite,
337         devbwrite,
338         devremove,
339         devwstat,
340         devpower,
341         devchaninfo,
342 };