b23ecdfa9e6f16917bfe2e5c8f40e95258ea3127
[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 /* we pack the qid as follows: path is the index, vers is ., and type is type */
28 struct dirtab roottab[MAXFILE] = {
29         {"",    {0, 0, QTDIR},   0,     0777},
30         {"chan",        {1, 0, QTDIR},   0,     0777},
31         {"dev", {2, 0, QTDIR},   0,     0777},
32         {"fd",  {3, 0, QTDIR},   0,     0777},
33         {"prog",        {4, 0, QTDIR},   0,     0777},
34         {"prof",        {5, 0, QTDIR},   0,     0777},
35         {"net", {6, 0, QTDIR},   0,     0777},
36         {"net.alt",     {7, 0, QTDIR},   0,     0777},
37         {"nvfs",        {8, 0, QTDIR},   0,     0777},
38         {"env", {9, 0, QTDIR},   0,     0777},
39         {"root",        {10, 0, QTDIR},  0,     0777},
40         {"srv", {11, 0, QTDIR},  0,     0777},
41         /* not courtesy of mkroot */
42         {"mnt", {12, 0, QTDIR},  0,     0777},
43 };
44
45 struct rootdata
46 {
47         int     dotdot;
48         void    *ptr;
49         int     size;
50         int     *sizep;
51 };
52
53 struct rootdata rootdata[MAXFILE] = {
54         {0,      &roottab[1],    12,    NULL},
55         {0,      NULL,   0,      NULL},
56         {0,      NULL,   0,      NULL},
57         {0,      NULL,   0,      NULL},
58         {0,      NULL,   0,      NULL},
59         {0,      NULL,   0,      NULL},
60         {0,      NULL,   0,      NULL},
61         {0,      NULL,   0,      NULL},
62         {0,      NULL,   0,      NULL},
63         {0,      NULL,   0,      NULL},
64         {0,      NULL,   0,      NULL},
65         {0,      NULL,   0,      NULL},
66         {0,      NULL,   0,      NULL},
67 };
68
69 static struct chan*
70 rootattach(char *spec)
71 {
72         int i;
73         uint32_t len;
74         struct rootdata *r;
75
76         if(*spec)
77                 error(Ebadspec);
78         for (i = 0; i < rootmaxq; i++){
79                 r = &rootdata[i];
80                 if (r->sizep){
81                         len = *r->sizep;
82                         r->size = len;
83                         roottab[i].length = len;
84                 }
85         }
86         return devattach('r', spec);
87 }
88
89 static int
90 rootgen(struct chan *c, char *name,
91         struct dirtab *tab, int nd, int s, struct dir *dp)
92 {
93         int p, i;
94         struct rootdata *r;
95
96         if(s == DEVDOTDOT){
97                 p = rootdata[c->qid.path].dotdot;
98                 c->qid.path = p;
99                 c->qid.type = QTDIR;
100                 name = "#r";
101                 if(p != 0){
102                         for(i = 0; i < rootmaxq; i++)
103                                 if(roottab[i].qid.path == c->qid.path){
104                                         name = roottab[i].name;
105                                         break;
106                                 }
107                 }
108                 devdir(c, c->qid, name, 0, eve, 0777, dp);
109                 return 1;
110         }
111
112         if(name != NULL){
113                 int path = c->qid.path;
114                 isdir(c);
115                 r = &rootdata[path];
116                 tab = r->ptr;
117                 /* it's almost always at or after your current spot. */
118                 for(i=0; i<r->size; i++, tab++)
119                         if(strcmp(tab->name, name) == 0){
120                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
121                                 return 1;
122                         }
123                 /* well we tried. */
124                 /* Round up the usual suspects. Search every level. */
125                 /* luckily this is pretty fast. */
126                 tab = roottab;
127                 r = rootdata;
128                 for(i=0; i<path; i++, tab++, r++)
129                         if(tab->name && (roottab[r->dotdot].qid.path == c->qid.path) &&
130                            (strcmp(tab->name, name) == 0)){
131                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
132                                 return 1;
133                         }
134                 return -1;
135         }
136
137         if(s >= nd)
138                 return -1;
139         tab += s;
140
141         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
142         return 1;
143 }
144
145 static struct walkqid*
146 rootwalk(struct chan *c, struct chan *nc, char **name, int nname)
147 {
148         uint32_t p;
149         if (0){
150                 printk("rootwalk: c %p. ", c);
151                 if (nname){
152                         int i;
153                         for(i = 0; i < nname-1; i++)
154                                 printk("%s/", name[i]);
155                         printk("%s", name[i]);
156                 }
157         }
158         p = c->qid.path;
159         if(nname == 0)
160                 p = rootdata[p].dotdot;
161         return devwalk(c, nc, name, nname, rootdata[p].ptr, rootdata[p].size, rootgen);
162 }
163
164 static int
165 rootstat(struct chan *c, uint8_t *dp, int n)
166 {
167         int p;
168
169         p = rootdata[c->qid.path].dotdot;
170         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
171 }
172
173 static struct chan*
174 rootopen(struct chan *c, int omode)
175 {
176         int p;
177
178         p = rootdata[c->qid.path].dotdot;
179         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
180 }
181
182 static void
183 rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
184 {
185         struct dirtab *r = &roottab[c->qid.path], *newr;
186         struct rootdata *rd = &rootdata[c->qid.path], *newrd;
187         if (0)printk("rootcreate: c %p, name %s, omode %o, perm %x\n", 
188                c, name, omode, perm);
189         /* find an empty slot */
190         //wlock(&root)
191         int path = c->qid.path;
192         int newfile = inumber++; // kref
193         newr = &roottab[newfile];
194         strncpy(newr->name, name, sizeof(newr->name));
195         mkqid(&newr->qid, newfile, newfile, perm&DMDIR);
196         newr->length = 0;
197         newr->perm = perm;
198         newrd = &rootdata[newfile];
199         newrd->dotdot = path;
200         newrd->ptr = newr;
201         newrd->size = 0;
202         newrd->sizep = &newrd->size;
203         rd->size++;
204         if (newfile > rootmaxq)
205                 rootmaxq = newfile;
206         if (1) printk("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
207                   newrd->dotdot, rootmaxq);
208 }
209
210 /*
211  * sysremove() knows this is a nop
212  */
213 static void      
214 rootclose(struct chan *c)
215 {
216 }
217
218 static long      
219 rootread(struct chan *c, void *buf, long n, int64_t offset)
220 {
221         uint32_t p, len;
222         uint8_t *data;
223
224         p = c->qid.path;
225         if(c->qid.type & QTDIR)
226                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size, rootgen);
227         len = rootdata[p].size;
228         if(offset < 0 || offset >= len)
229                 return 0;
230         if(offset+n > len)
231                 n = len - offset;
232         data = rootdata[p].ptr;
233         memmove(buf, data+offset, n);
234         return n;
235 }
236
237
238 static long      
239 rootwrite(struct chan *c, void *a, long n, int64_t off)
240 {
241         error(Eperm);
242         return 0;
243 }
244
245 void dumprootdev(void)
246 {
247         struct dirtab *r = roottab;
248         struct rootdata *rd = rootdata;
249         int i;
250
251         for(i = 0; i < rootmaxq; i++){
252                 if (! r->name[0])
253                         continue;
254                 printk("%s: [%d, %d, %d], %d, %o; ",
255                        r->name, r->qid.path, r->qid.vers, r->qid.type,
256                        r->length, r->perm);
257                 printk("dotdot %d, ptr %p, size %d, sizep %p\n", 
258                        rd->dotdot, rd->ptr, rd->size, rd->sizep);
259         }
260 }
261
262 struct dev rootdevtab __devtab = {
263         'r',
264         "root",
265         devreset,
266         devinit,
267         devshutdown,
268         rootattach,
269         rootwalk,
270         rootstat,
271         rootopen,
272         rootcreate,
273         rootclose,
274         rootread,
275         devbread,
276         rootwrite,
277         devbwrite,
278         devremove,
279         devwstat,
280         devpower,
281         devchaninfo,
282 };