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