Closer.
[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 {
64         int     dotdot;
65         int     child;
66         void    *ptr;
67         int     size;
68         int     *sizep;
69 };
70
71 struct rootdata rootdata[MAXFILE] = {
72         {0,     0,       &roottab[1],    12,    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         {0,     0,       NULL,   0,      NULL},
85 };
86
87 void dumprootdev(void)
88 {
89         struct dirtab *r = roottab;
90         struct rootdata *rd = rootdata;
91         int i;
92
93         for(i = 0; i < rootmaxq; i++, r++, rd++){
94                 if (i && (! r->name[0]))
95                         continue;
96                 printk("[%p]%s: [%d, %d, %d], %d, %o; ",
97                        r,
98                        r->name, r->qid.path, r->qid.vers, r->qid.type,
99                        r->length, r->perm);
100                 printk("dotdot %d, child %d, ptr %p, size %d, sizep %p\n", 
101                        rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
102         }
103 }
104
105 static int findempty(void)
106 {
107         int i;
108         for(i = 0; i < rootmaxq; i++){
109                 if (!roottab[i].qid.type) {
110                         return i;
111                 }
112         }
113         memset(&roottab[i], 0, sizeof(roottab[i]));
114         return -1;
115 }
116
117 static void freeempty(int i)
118 {
119         roottab[i].qid.type = 0;
120 }
121
122 static int newentry(int old)
123 {
124         int n = findempty();
125         int sib;
126         if (n < 0)
127                 error("#r. No more");
128         printk("new entry is %d\n", n);
129         sib = rootdata[old].child;
130         if (sib){
131                 roottab[n].qid.vers = roottab[sib].qid.vers;
132                 roottab[sib].qid.vers = n;
133         }
134         rootdata[old].child = n;
135         return n;
136 }
137
138 static int createentry(int dir, char *name, int length, int perm)
139 {
140         int n = newentry(dir);
141         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
142         roottab[n].length;
143         roottab[n].perm = perm;
144         /* vers is already properly set. */
145         mkqid(&roottab[n].qid, n, roottab[n].qid.vers, perm&DMDIR ? QTDIR : 'f');
146         rootdata[n].dotdot = roottab[dir].qid.path;
147         rootdata[dir].ptr = &roottab[n];
148         rootdata[n].size = 0;
149         rootdata[n].sizep = &rootdata[n].size;
150         return n;
151 }
152
153 static struct chan*
154 rootattach(char *spec)
155 {
156         int i;
157         uint32_t len;
158         struct rootdata *r;
159
160         if(*spec)
161                 error(Ebadspec);
162         /* this begins with the root. */
163         for (i = 0; ;i++){
164                 r = &rootdata[i];
165                 if (r->sizep){
166                         len = *r->sizep;
167                         r->size = len;
168                         roottab[i].length = len;
169                 }
170                 i = roottab[i].qid.vers;
171                 if (! i)
172                         break;
173         }
174         return devattach('r', spec);
175 }
176
177 static int
178 rootgen(struct chan *c, char *name,
179         struct dirtab *tab, int nd, int s, struct dir *dp)
180 {
181         int p, i;
182         struct rootdata *r;
183         int iter;
184         printk("rootgen, path is %d, tap %p, nd %d s %d\n", rootdata[c->qid.path].dotdot, 
185                tab, nd, s);
186
187         if(s == DEVDOTDOT){
188                 printk("rootgen, DEVDOTDOT\n");
189                 p = rootdata[c->qid.path].dotdot;
190                 c->qid.path = p;
191                 c->qid.type = QTDIR;
192                 name = "#r";
193                 if(p != 0){
194                         for(i = p; ;){
195                                 if(roottab[i].qid.path == c->qid.path){
196                                         name = roottab[i].name;
197                                         break;
198                                 }
199                                 i = roottab[i].qid.vers;
200                                 if (! i)
201                                         break;
202                         }
203                 }
204                 devdir(c, c->qid, name, 0, eve, 0777, dp);
205                 return 1;
206         }
207
208         if(name != NULL){
209                 int path = c->qid.path;
210                 isdir(c);
211                 tab = &roottab[path];
212                 /* we're starting at a directory. It might be '.' */
213                 for(iter = 0, i=path; ; iter++){
214                         if(strcmp(tab->name, name) == 0){
215                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
216                                 return 1;
217                         }
218                         if (iter > rootmaxq){
219                                 printk("BUG:");
220                                 dumprootdev();
221                                 printk("name %s\n", name);
222                                 return -1;
223                         }
224                         i = roottab[i].qid.vers;
225                         if (! i)
226                                 break;
227                         tab = &roottab[i];
228                 }
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*
242 rootwalk(struct chan *c, struct chan *nc, char **name, 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", name[i]);
252                 }
253         }
254         p = c->qid.path;
255         if(nname == 0)
256                 p = rootdata[p].dotdot;
257         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
258 }
259
260 static int
261 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*
270 rootopen(struct chan *c, int omode)
271 {
272         int p;
273
274         p = rootdata[c->qid.path].dotdot;
275         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
276 }
277
278 static void
279 rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
280 {
281         struct dirtab *r = &roottab[c->qid.path], *newr;
282         struct rootdata *rd = &rootdata[c->qid.path];
283         if (1)printk("rootcreate: c %p, name %s, omode %o, perm %x\n", 
284                c, name, omode, perm);
285         /* find an empty slot */
286         //wlock(&root)
287         int path = c->qid.path;
288         int newfile;
289         newfile = createentry(path, name, omode, perm);
290         rd->size++;
291         if (newfile > rootmaxq)
292                 rootmaxq = newfile;
293         if (1) printk("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
294                   rootdata[newfile].dotdot, rootmaxq);
295 }
296
297 /*
298  * sysremove() knows this is a nop
299  */
300 static void      
301 rootclose(struct chan *c)
302 {
303 }
304
305 static long      
306 rootread(struct chan *c, void *buf, long n, int64_t offset)
307 {
308         uint32_t p, len;
309         uint8_t *data;
310
311         p = c->qid.path;
312         if(c->qid.type & QTDIR) {
313                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size, rootgen);
314         }
315         len = rootdata[p].size;
316         if(offset < 0 || offset >= len) {
317                 return 0;
318         }
319         if(offset+n > len)
320                 n = len - offset;
321         data = rootdata[p].ptr;
322         memmove(buf, data+offset, n);
323         return n;
324 }
325
326
327 static long      
328 rootwrite(struct chan *c, void *a, long n, int64_t off)
329 {
330         error(Eperm);
331         return 0;
332 }
333
334 struct dev rootdevtab __devtab = {
335         'r',
336         "root",
337         devreset,
338         devinit,
339         devshutdown,
340         rootattach,
341         rootwalk,
342         rootstat,
343         rootopen,
344         rootcreate,
345         rootclose,
346         rootread,
347         devbread,
348         rootwrite,
349         devbwrite,
350         devremove,
351         devwstat,
352         devpower,
353         devchaninfo,
354 };