Fixes devmnt warnings
[akaros.git] / kern / drivers / dev / dev.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 extern uint32_t kerndate;
17
18 void
19 mkqid(struct qid *q, int64_t path, uint32_t vers, int type)
20 {
21         q->type = type;
22         q->vers = vers;
23         q->path = path;
24 }
25
26 int
27 devno(int c, int user)
28 {
29         int i;
30
31         for(i = 0; devtab[i] != NULL; i++) {
32                 if(devtab[i]->dc == c)
33                         return i;
34         }
35         if(user == 0)
36                 panic("devno %C 0x%ux", c, c);
37
38         return -1;
39 }
40
41 void
42 devdir(struct chan *c, struct qid qid, char *n,
43        int64_t length, char *user, long perm, struct dir *db)
44 {
45         db->name = n;
46         if(c->flag&CMSG)
47                 qid.type |= QTMOUNT;
48         db->qid = qid;
49         db->type = devtab[c->type]->dc;
50         db->dev = c->dev;
51         db->mode = perm;
52         db->mode |= qid.type << 24;
53         db->atime = seconds();
54         db->mtime = kerndate;
55         db->length = length;
56         db->uid = user;
57         db->gid = eve;
58         db->muid = user;
59 }
60
61 /*
62  * the zeroth element of the table MUST be the directory itself for ..
63 */
64 int
65 devgen(struct chan *c, char *unused_char_p_t, struct dirtab *tab, int ntab, int i,
66        struct dir *dp)
67 {
68         if(tab == 0)
69                 return -1;
70         if(i != DEVDOTDOT){
71                 /* skip over the first element, that for . itself */
72                 i++;
73                 if(i >= ntab)
74                         return -1;
75                 tab += i;
76         }
77         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
78         return 1;
79 }
80
81 void
82 devreset(void)
83 {
84 }
85
86 void
87 devinit(void)
88 {
89 }
90
91 void
92 devshutdown(void)
93 {
94 }
95
96 struct chan*
97 devattach(int tc, char *spec)
98 {
99         struct chan *c;
100         char *buf;
101
102         c = newchan();
103         mkqid(&c->qid, 0, 0, QTDIR);
104         c->type = devno(tc, 0);
105         if(spec == NULL)
106                 spec = "";
107         buf = kzmalloc(4 + strlen(spec) + 1, 0);
108         snprintf(buf, sizeof(buf), "#%C%s", tc, spec);
109         c->name = newcname(buf);
110         kfree(buf);
111         return c;
112 }
113
114
115 struct chan*
116 devclone(struct chan *c)
117 {
118         struct chan *nc;
119
120         if(c->flag & COPEN)
121                 panic("clone of open file type %C\n", devtab[c->type]->dc);
122
123         nc = newchan();
124
125         nc->type = c->type;
126         nc->dev = c->dev;
127         nc->mode = c->mode;
128         nc->qid = c->qid;
129         nc->offset = c->offset;
130         nc->umh = NULL;
131         nc->mountid = c->mountid;
132         nc->aux = c->aux;
133         nc->mqid = c->mqid;
134         nc->mcp = c->mcp;
135         return nc;
136 }
137
138 struct walkqid*
139 devwalk(struct chan *c,
140         struct chan *nc, char **name, int nname,
141         struct dirtab *tab, int ntab, Devgen *gen)
142 {
143         ERRSTACK(2);
144         int i, j, alloc;
145         struct walkqid *wq;
146         char *n;
147         struct dir dir;
148
149         if(nname > 0)
150                 isdir(c);
151
152         alloc = 0;
153         wq = kzmalloc(sizeof(struct walkqid) + (nname - 1) * sizeof(struct qid), 0);
154         if(waserror()){
155                 if(alloc && wq->clone!=NULL)
156                         cclose(wq->clone);
157                 kfree(wq);
158                 return NULL;
159         }
160         if(nc == NULL){
161                 nc = devclone(c);
162                 nc->type = 0;   /* device doesn't know about this channel yet */
163                 alloc = 1;
164         }
165         wq->clone = nc;
166
167         for(j=0; j<nname; j++){
168                 if(!(nc->qid.type&QTDIR)){
169                         if(j==0)
170                                 error(Enotdir);
171                         goto Done;
172                 }
173                 n = name[j];
174                 if(strcmp(n, ".") == 0){
175     Accept:
176                         wq->qid[wq->nqid++] = nc->qid;
177                         continue;
178                 }
179                 if(strcmp(n, "..") == 0){
180                         (*gen)(nc, NULL, tab, ntab, DEVDOTDOT, &dir);
181                         nc->qid = dir.qid;
182                         goto Accept;
183                 }
184                 /*
185                  * Ugly problem: If we're using devgen, make sure we're
186                  * walking the directory itself, represented by the first
187                  * entry in the table, and not trying to step into a sub-
188                  * directory of the table, e.g. /net/net. Devgen itself
189                  * should take care of the problem, but it doesn't have
190                  * the necessary information (that we're doing a walk).
191                  */
192                 if(gen==devgen && nc->qid.path!=tab[0].qid.path)
193                         goto Notfound;
194                 for(i=0;; i++) {
195                         switch((*gen)(nc, n, tab, ntab, i, &dir)){
196                         case -1:
197                         Notfound:
198                                 if(j == 0)
199                                         error(Enonexist);
200                                 set_errstr(Enonexist);
201                                 goto Done;
202                         case 0:
203                                 continue;
204                         case 1:
205                                 if(strcmp(n, dir.name) == 0){
206                                         nc->qid = dir.qid;
207                                         goto Accept;
208                                 }
209                                 continue;
210                         }
211                 }
212         }
213         /*
214          * We processed at least one name, so will return some data.
215          * If we didn't process all nname entries succesfully, we drop
216          * the cloned channel and return just the Qids of the walks.
217          */
218 Done:
219         poperror();
220         if(wq->nqid < nname){
221                 if(alloc)
222                         cclose(wq->clone);
223                 wq->clone = NULL;
224         }else if(wq->clone){
225                 /* attach cloned channel to same device */
226                 wq->clone->type = c->type;
227         }
228         return wq;
229 }
230
231 int
232 devstat(struct chan *c, uint8_t *db, int n,
233         struct dirtab *tab, int ntab, Devgen *gen)
234 {
235         int i;
236         struct dir dir;
237         char *p, *elem;
238
239         for(i=0;; i++)
240                 switch((*gen)(c, NULL, tab, ntab, i, &dir)){
241                 case -1:
242                         if(c->qid.type & QTDIR){
243                                 if(c->name == NULL)
244                                         elem = "???";
245                                 else if(strcmp(c->name->s, "/") == 0)
246                                         elem = "/";
247                                 else
248                                         for(elem=p=c->name->s; *p; p++)
249                                                 if(*p == '/')
250                                                         elem = p+1;
251                                 devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
252                                 n = convD2M(&dir, db, n);
253                                 if(n == 0)
254                                         error(Ebadarg);
255                                 return n;
256                         }
257                         printd("%s %s: devstat %C %llux\n",
258                                 up->text, up->env->user,
259                                 devtab[c->type]->dc, c->qid.path);
260
261                         error(Enonexist);
262                 case 0:
263                         break;
264                 case 1:
265                         if(c->qid.path == dir.qid.path) {
266                                 if(c->flag&CMSG)
267                                         dir.mode |= DMMOUNT;
268                                 n = convD2M(&dir, db, n);
269                                 if(n == 0)
270                                         error(Ebadarg);
271                                 return n;
272                         }
273                         break;
274                 }
275 }
276
277 long
278 devdirread(struct chan *c, char *d, long n,
279            struct dirtab *tab, int ntab, Devgen *gen)
280 {
281         long m, dsz;
282         /* this is gross. Make it 2 so we have room at the end for
283          * bad things.
284          */
285         struct dir dir[4];
286
287         for(m=0; m<n; c->dri++) {
288                 switch((*gen)(c, NULL, tab, ntab, c->dri, &dir[0])){
289                 case -1:
290                         return m;
291
292                 case 0:
293                         break;
294
295                 case 1:
296                         dsz = convD2M(&dir[0], ( uint8_t *)d, n-m);
297                         if(dsz <= BIT16SZ){     /* <= not < because this isn't stat; read is stuck */
298                                 if(m == 0)
299                                         error(Eshort);
300                                 return m;
301                         }
302                         m += dsz;
303                         d += dsz;
304                         break;
305                 }
306         }
307
308         return m;
309 }
310
311 /*
312  * error(Eperm) if open permission not granted for up->env->user.
313  */
314 void
315 devpermcheck(char *fileuid, uint32_t perm, int omode)
316 {
317         uint32_t t;
318         static int access[] = { 0400, 0200, 0600, 0100 };
319
320         if(strcmp(current->user, fileuid) == 0)
321                 perm <<= 0;
322         else
323         if(strcmp(current->user, eve) == 0)
324                 perm <<= 3;
325         else
326                 perm <<= 6;
327
328         t = access[omode&3];
329         if((t&perm) != t)
330                 error(Eperm);
331 }
332
333 struct chan*
334 devopen(struct chan *c, int omode, struct dirtab *tab, int ntab, Devgen *gen)
335 {
336         int i;
337         struct dir dir;
338
339         for(i=0;; i++) {
340                 switch((*gen)(c, NULL, tab, ntab, i, &dir)){
341                 case -1:
342                         goto Return;
343                 case 0:
344                         break;
345                 case 1:
346                         if(c->qid.path == dir.qid.path) {
347                                 devpermcheck(dir.uid, dir.mode, omode);
348                                 goto Return;
349                         }
350                         break;
351                 }
352         }
353 Return:
354         c->offset = 0;
355         if((c->qid.type&QTDIR) && omode!=OREAD)
356                 error(Eperm);
357         c->mode = openmode(omode);
358         c->flag |= COPEN;
359         return c;
360 }
361
362 void
363 devcreate(struct chan*c, char *unused_char_p_t, int unused_int, uint32_t u)
364 {
365         error(Eperm);
366 }
367
368 struct block*
369 devbread(struct chan *c, long n, uint32_t offset)
370 {
371         ERRSTACK(2);
372         struct block *bp;
373
374         bp = allocb(n);
375         if(bp == 0)
376                 error(Enomem);
377         if(waserror()) {
378                 freeb(bp);
379                 nexterror();
380         }
381         bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
382         poperror();
383         return bp;
384 }
385
386 long
387 devbwrite(struct chan *c, struct block *bp, uint32_t offset)
388 {
389         ERRSTACK(2);
390         long n;
391
392         if(waserror()) {
393                 freeb(bp);
394                 nexterror();
395         }
396         n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
397         poperror();
398         freeb(bp);
399
400         return n;
401 }
402
403 void
404 devremove(struct chan*c)
405 {
406         error(Eperm);
407 }
408
409 int
410 devwstat(struct chan*c, uint8_t *unused_uint8_p_t, int i)
411 {
412         error(Eperm);
413         return 0;
414 }
415
416 void
417 devpower(int i)
418 {
419         error(Eperm);
420 }
421
422 #if 0
423 int
424 devconfig( int unused_int, char *c, DevConf *)
425 {
426         error(Eperm);
427         return 0;
428 }
429 #endif
430 /*
431  * check that the name in a wstat is plausible
432  */
433 void
434 validwstatname(char *name)
435 {
436         validname(name, 0);
437         if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
438                 error(Efilename);
439 }
440
441 struct dev*
442 devbyname(char *name)
443 {
444         int i;
445
446         for(i = 0; devtab[i] != NULL; i++)
447                 if(strcmp(devtab[i]->name, name) == 0)
448                         return devtab[i];
449         return NULL;
450 }
451
452