1 #include "u.h" 2 #include "lib.h" 3 #include "dat.h" 4 #include "fns.h" 5 #include "error.h" 6 7 extern ulong kerndate; 8 9 void 10 mkqid(Qid *q, vlong path, ulong vers, int type) 11 { 12 q->type = type; 13 q->vers = vers; 14 q->path = path; 15 } 16 17 int 18 devno(int c, int user) 19 { 20 int i; 21 22 for(i = 0; devtab[i] != nil; i++) { 23 if(devtab[i]->dc == c) 24 return i; 25 } 26 if(user == 0) 27 panic("devno %C 0x%ux", c, c); 28 29 return -1; 30 } 31 32 void 33 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db) 34 { 35 db->name = n; 36 if(c->flag&CMSG) 37 qid.type |= QTMOUNT; 38 db->qid = qid; 39 db->type = devtab[c->type]->dc; 40 db->dev = c->dev; 41 db->mode = perm; 42 db->mode |= qid.type << 24; 43 db->atime = seconds(); 44 db->mtime = kerndate; 45 db->length = length; 46 db->uid = user; 47 db->gid = eve; 48 db->muid = user; 49 } 50 51 /* 52 * (here, Devgen is the prototype; devgen is the function in dev.c.) 53 * 54 * a Devgen is expected to return the directory entry for ".." 55 * if you pass it s==DEVDOTDOT (-1). otherwise... 56 * 57 * there are two contradictory rules. 58 * 59 * (i) if c is a directory, a Devgen is expected to list its children 60 * as you iterate s. 61 * 62 * (ii) whether or not c is a directory, a Devgen is expected to list 63 * its siblings as you iterate s. 64 * 65 * devgen always returns the list of children in the root 66 * directory. thus it follows (i) when c is the root and (ii) otherwise. 67 * many other Devgens follow (i) when c is a directory and (ii) otherwise. 68 * 69 * devwalk assumes (i). it knows that devgen breaks (i) 70 * for children that are themselves directories, and explicitly catches them. 71 * 72 * devstat assumes (ii). if the Devgen in question follows (i) 73 * for this particular c, devstat will not find the necessary info. 74 * with our particular Devgen functions, this happens only for 75 * directories, so devstat makes something up, assuming 76 * c->name, c->qid, eve, DMDIR|0555. 77 * 78 * devdirread assumes (i). the callers have to make sure 79 * that the Devgen satisfies (i) for the chan being read. 80 */ 81 /* 82 * the zeroth element of the table MUST be the directory itself for .. 83 */ 84 int 85 devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) 86 { 87 if(tab == 0) 88 return -1; 89 if(i == DEVDOTDOT){ 90 /* nothing */ 91 }else if(name){ 92 for(i=1; i<ntab; i++) 93 if(strcmp(tab[i].name, name) == 0) 94 break; 95 if(i==ntab) 96 return -1; 97 tab += i; 98 }else{ 99 /* skip over the first element, that for . itself */ 100 i++; 101 if(i >= ntab) 102 return -1; 103 tab += i; 104 } 105 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); 106 return 1; 107 } 108 109 void 110 devreset(void) 111 { 112 } 113 114 void 115 devinit(void) 116 { 117 } 118 119 void 120 devshutdown(void) 121 { 122 } 123 124 Chan* 125 devattach(int tc, char *spec) 126 { 127 Chan *c; 128 char *buf; 129 130 c = newchan(); 131 mkqid(&c->qid, 0, 0, QTDIR); 132 c->type = devno(tc, 0); 133 if(spec == nil) 134 spec = ""; 135 buf = smalloc(4+strlen(spec)+1); 136 sprint(buf, "#%C%s", tc, spec); 137 c->name = newcname(buf); 138 free(buf); 139 return c; 140 } 141 142 143 Chan* 144 devclone(Chan *c) 145 { 146 Chan *nc; 147 148 if(c->flag & COPEN) 149 panic("clone of open file type %C\n", devtab[c->type]->dc); 150 151 nc = newchan(); 152 153 nc->type = c->type; 154 nc->dev = c->dev; 155 nc->mode = c->mode; 156 nc->qid = c->qid; 157 nc->offset = c->offset; 158 nc->umh = nil; 159 nc->mountid = c->mountid; 160 nc->aux = c->aux; 161 nc->pgrpid = c->pgrpid; 162 nc->mid = c->mid; 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->name == nil) 274 elem = "???"; 275 else if(strcmp(c->name->s, "/") == 0) 276 elem = "/"; 277 else 278 for(elem=p=c->name->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 print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path); 288 289 error(Enonexist); 290 case 0: 291 break; 292 case 1: 293 if(c->qid.path == dir.qid.path) { 294 if(c->flag&CMSG) 295 dir.mode |= DMMOUNT; 296 n = convD2M(&dir, db, n); 297 if(n == 0) 298 error(Ebadarg); 299 return n; 300 } 301 break; 302 } 303 error(Egreg); /* not reached? */ 304 return -1; 305 } 306 307 long 308 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) 309 { 310 long m, dsz; 311 struct{ 312 Dir d; 313 char slop[100]; 314 }dir; 315 316 for(m=0; m<n; c->dri++) { 317 switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){ 318 case -1: 319 return m; 320 321 case 0: 322 break; 323 324 case 1: 325 dsz = convD2M(&dir.d, (uchar*)d, n-m); 326 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ 327 if(m == 0) 328 error(Eshort); 329 return m; 330 } 331 m += dsz; 332 d += dsz; 333 break; 334 } 335 } 336 337 return m; 338 } 339 340 /* 341 * error(Eperm) if open permission not granted for up->user. 342 */ 343 void 344 devpermcheck(char *fileuid, ulong perm, int omode) 345 { 346 ulong t; 347 static int access[] = { 0400, 0200, 0600, 0100 }; 348 349 if(strcmp(up->user, fileuid) == 0) 350 perm <<= 0; 351 else 352 if(strcmp(up->user, eve) == 0) 353 perm <<= 3; 354 else 355 perm <<= 6; 356 357 t = access[omode&3]; 358 if((t&perm) != t) 359 error(Eperm); 360 } 361 362 Chan* 363 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) 364 { 365 int i; 366 Dir dir; 367 368 for(i=0;; i++) { 369 switch((*gen)(c, nil, tab, ntab, i, &dir)){ 370 case -1: 371 goto Return; 372 case 0: 373 break; 374 case 1: 375 if(c->qid.path == dir.qid.path) { 376 devpermcheck(dir.uid, dir.mode, omode); 377 goto Return; 378 } 379 break; 380 } 381 } 382 Return: 383 c->offset = 0; 384 if((c->qid.type&QTDIR) && omode!=OREAD) 385 error(Eperm); 386 c->mode = openmode(omode); 387 c->flag |= COPEN; 388 return c; 389 } 390 391 void 392 devcreate(Chan *c, char *name, int mode, ulong perm) 393 { 394 USED(c); 395 USED(name); 396 USED(mode); 397 USED(perm); 398 399 error(Eperm); 400 } 401 402 Block* 403 devbread(Chan *c, long n, ulong offset) 404 { 405 Block *bp; 406 407 bp = allocb(n); 408 if(bp == 0) 409 error(Enomem); 410 if(waserror()) { 411 freeb(bp); 412 nexterror(); 413 } 414 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); 415 poperror(); 416 return bp; 417 } 418 419 long 420 devbwrite(Chan *c, Block *bp, ulong offset) 421 { 422 long n; 423 424 if(waserror()) { 425 freeb(bp); 426 nexterror(); 427 } 428 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); 429 poperror(); 430 freeb(bp); 431 432 return n; 433 } 434 435 void 436 devremove(Chan *c) 437 { 438 USED(c); 439 error(Eperm); 440 } 441 442 int 443 devwstat(Chan *c, uchar *a, int n) 444 { 445 USED(c); 446 USED(a); 447 USED(n); 448 449 error(Eperm); 450 return 0; 451 } 452 453 void 454 devpower(int a) 455 { 456 USED(a); 457 error(Eperm); 458 } 459 460 int 461 devconfig(int a, char *b, DevConf *c) 462 { 463 USED(a); 464 USED(b); 465 USED(c); 466 error(Eperm); 467 return 0; 468 } 469