dev.c (8241B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "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\n", 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 void 387 devcreate(Chan *c, char *name, int mode, ulong perm) 388 { 389 error(Eperm); 390 } 391 392 Block* 393 devbread(Chan *c, long n, ulong offset) 394 { 395 Block *bp; 396 397 bp = allocb(n); 398 if(bp == 0) 399 error(Enomem); 400 if(waserror()) { 401 freeb(bp); 402 nexterror(); 403 } 404 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); 405 poperror(); 406 return bp; 407 } 408 409 long 410 devbwrite(Chan *c, Block *bp, ulong offset) 411 { 412 long n; 413 414 if(waserror()) { 415 freeb(bp); 416 nexterror(); 417 } 418 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); 419 poperror(); 420 freeb(bp); 421 422 return n; 423 } 424 425 void 426 devremove(Chan *c) 427 { 428 error(Eperm); 429 } 430 431 int 432 devwstat(Chan *c, uchar *stat, int nstat) 433 { 434 error(Eperm); 435 return 0; 436 } 437 438 void 439 devpower(int toggle) 440 { 441 error(Eperm); 442 } 443 444 int 445 devconfig(int toggle, char *name, DevConf *conf) 446 { 447 error(Eperm); 448 return 0; 449 }