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