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