1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <tapefs.h> 6 7 Fid *fids; 8 Ram *ram; 9 int mfd[2]; 10 char user[NAMELEN]; 11 char mdata[MAXMSG+MAXFDATA]; 12 Fcall rhdr; 13 Fcall thdr; 14 ulong path; 15 Idmap *uidmap; 16 Idmap *gidmap; 17 int replete; 18 19 Fid * newfid(int); 20 void ramstat(Ram*, char*); 21 void io(void); 22 void usage(void); 23 int perm(Fid*, Ram*, int); 24 25 char *rflush(Fid*), *rnop(Fid*), *rsession(Fid*), 26 *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*), 27 *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), 28 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), 29 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), 30 *rauth(Fid*); 31 32 char *(*fcalls[])(Fid*) = { 33 [Tflush] rflush, 34 [Tsession] rsession, 35 [Tnop] rnop, 36 [Tattach] rattach, 37 [Tclone] rclone, 38 [Twalk] rwalk, 39 [Tclwalk] rclwalk, 40 [Topen] ropen, 41 [Tcreate] rcreate, 42 [Tread] rread, 43 [Twrite] rwrite, 44 [Tclunk] rclunk, 45 [Tremove] rremove, 46 [Tstat] rstat, 47 [Twstat] rwstat, 48 }; 49 50 char Eperm[] = "permission denied"; 51 char Enotdir[] = "not a directory"; 52 char Enoauth[] = "no authentication in ramfs"; 53 char Enotexist[] = "file does not exist"; 54 char Einuse[] = "file in use"; 55 char Eexist[] = "file exists"; 56 char Enotowner[] = "not owner"; 57 char Eisopen[] = "file already open for I/O"; 58 char Excl[] = "exclusive use file already open"; 59 char Ename[] = "illegal name"; 60 61 void 62 notifyf(void *a, char *s) 63 { 64 USED(a); 65 if(strncmp(s, "interrupt", 9) == 0) 66 noted(NCONT); 67 noted(NDFLT); 68 } 69 70 void 71 main(int argc, char *argv[]) 72 { 73 Ram *r; 74 char *defmnt; 75 int p[2]; 76 77 defmnt = "/n/tapefs"; 78 ARGBEGIN{ 79 case 'm': 80 defmnt = ARGF(); 81 break; 82 case 'p': /* password file */ 83 uidmap = getpass(ARGF()); 84 break; 85 case 'g': /* group file */ 86 gidmap = getpass(ARGF()); 87 break; 88 default: 89 usage(); 90 }ARGEND 91 92 if (argc==0) 93 error("no file to mount"); 94 ram = r = (Ram *)emalloc(sizeof(Ram)); 95 r->busy = 1; 96 r->data = 0; 97 r->ndata = 0; 98 r->perm = CHDIR | 0775; 99 r->qid.path = CHDIR; 100 r->qid.vers = 0; 101 r->parent = 0; 102 r->child = 0; 103 r->next = 0; 104 r->user = user; 105 r->group = user; 106 r->atime = time(0); 107 r->mtime = r->atime; 108 r->replete = 0; 109 strcpy(r->name, "."); 110 strcpy(user, getuser()); 111 populate(argv[0]); 112 r->replete |= replete; 113 if(pipe(p) < 0) 114 error("pipe failed"); 115 mfd[0] = mfd[1] = p[0]; 116 notify(notifyf); 117 118 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ 119 case -1: 120 error("fork"); 121 case 0: 122 close(p[1]); 123 notify(notifyf); 124 io(); 125 break; 126 default: 127 close(p[0]); /* don't deadlock if child fails */ 128 if(mount(p[1], defmnt, MREPL|MCREATE, "") < 0) { 129 char buf[256]; 130 sprint(buf, "mount on `%s' failed", defmnt); 131 error(buf); 132 } 133 } 134 exits(0); 135 } 136 137 char* 138 rnop(Fid *f) 139 { 140 USED(f); 141 return 0; 142 } 143 144 char* 145 rsession(Fid *unused) 146 { 147 Fid *f; 148 149 USED(unused); 150 151 memset(thdr.authid, 0, sizeof(thdr.authid)); 152 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 153 memset(thdr.chal, 0, sizeof(thdr.chal)); 154 for(f = fids; f; f = f->next) 155 if(f->busy) 156 rclunk(f); 157 return 0; 158 } 159 160 char* 161 rflush(Fid *f) 162 { 163 USED(f); 164 return 0; 165 } 166 167 char* 168 rattach(Fid *f) 169 { 170 /* no authentication! */ 171 f->busy = 1; 172 f->rclose = 0; 173 f->ram = ram; 174 thdr.qid = f->ram->qid; 175 if(rhdr.uname[0]) 176 f->user = strdup(rhdr.uname); 177 else 178 f->user = "none"; 179 return 0; 180 } 181 182 char* 183 rclone(Fid *f) 184 { 185 Fid *nf; 186 187 if(f->open) 188 return Eisopen; 189 if(f->ram->busy == 0) 190 return Enotexist; 191 nf = newfid(rhdr.newfid); 192 nf->busy = 1; 193 nf->open = 0; 194 nf->rclose = 0; 195 nf->ram = f->ram; 196 nf->user = f->user; /* no ref count; the leakage is minor */ 197 return 0; 198 } 199 200 char* 201 rwalk(Fid *f) 202 { 203 Ram *r; 204 char *name; 205 Ram *dir; 206 207 if((f->ram->qid.path & CHDIR) == 0) 208 return Enotdir; 209 if(f->ram->busy == 0) 210 return Enotexist; 211 f->ram->atime = time(0); 212 name = rhdr.name; 213 if(strcmp(name, ".") == 0){ 214 thdr.qid = f->ram->qid; 215 return 0; 216 } 217 dir = f->ram; 218 if(!dir || !perm(f, dir, Pexec)) 219 return Eperm; 220 if(strcmp(name, "..") == 0){ 221 f->ram = dir->parent; 222 thdr.qid = f->ram->qid; 223 return 0; 224 } 225 if (!dir->replete) 226 popdir(dir); 227 for(r=dir->child; r; r=r->next) 228 if(r->busy && strcmp(name, r->name)==0){ 229 thdr.qid = r->qid; 230 f->ram = r; 231 return 0; 232 } 233 return Enotexist; 234 } 235 236 char * 237 rclwalk(Fid *f) 238 { 239 Fid *nf; 240 char *err; 241 242 nf = newfid(rhdr.newfid); 243 nf->busy = 1; 244 nf->rclose = 0; 245 nf->ram = f->ram; 246 nf->user = f->user; 247 if(err = rwalk(nf)) 248 rclunk(nf); 249 return err; 250 } 251 252 char * 253 ropen(Fid *f) 254 { 255 Ram *r; 256 int mode, trunc; 257 258 if(f->open) 259 return Eisopen; 260 r = f->ram; 261 if(r->busy == 0) 262 return Enotexist; 263 if(r->perm & CHEXCL) 264 if(r->open) 265 return Excl; 266 mode = rhdr.mode; 267 if(r->qid.path & CHDIR){ 268 if(mode != OREAD) 269 return Eperm; 270 thdr.qid = r->qid; 271 return 0; 272 } 273 if(mode & ORCLOSE) 274 return Eperm; 275 trunc = mode & OTRUNC; 276 mode &= OPERM; 277 if(mode==OWRITE || mode==ORDWR || trunc) 278 if(!perm(f, r, Pwrite)) 279 return Eperm; 280 if(mode==OREAD || mode==ORDWR) 281 if(!perm(f, r, Pread)) 282 return Eperm; 283 if(mode==OEXEC) 284 if(!perm(f, r, Pexec)) 285 return Eperm; 286 if(trunc && (r->perm&CHAPPEND)==0){ 287 r->ndata = 0; 288 dotrunc(r); 289 r->qid.vers++; 290 } 291 thdr.qid = r->qid; 292 f->open = 1; 293 r->open++; 294 return 0; 295 } 296 297 char * 298 rcreate(Fid *f) 299 { 300 USED(f); 301 302 return Eperm; 303 } 304 305 char* 306 rread(Fid *f) 307 { 308 Ram *r; 309 char *buf; 310 long off; 311 int n, cnt; 312 313 if(f->ram->busy == 0) 314 return Enotexist; 315 n = 0; 316 thdr.count = 0; 317 off = rhdr.offset; 318 cnt = rhdr.count; 319 buf = thdr.data; 320 if(f->ram->qid.path & CHDIR){ 321 if (!f->ram->replete) 322 popdir(f->ram); 323 if(off%DIRLEN || cnt%DIRLEN) 324 return "i/o error"; 325 for(r=f->ram->child; off; r=r->next){ 326 if (r==0) 327 return 0; 328 if(r->busy) 329 off -= DIRLEN; 330 } 331 for(; r && n < cnt; r=r->next){ 332 if(!r->busy) 333 continue; 334 ramstat(r, buf+n); 335 n += DIRLEN; 336 } 337 thdr.count = n; 338 return 0; 339 } 340 r = f->ram; 341 if(off >= r->ndata) 342 return 0; 343 r->atime = time(0); 344 n = cnt; 345 if(off+n > r->ndata) 346 n = r->ndata - off; 347 thdr.data = doread(r, off, n); 348 thdr.count = n; 349 return 0; 350 } 351 352 char* 353 rwrite(Fid *f) 354 { 355 Ram *r; 356 ulong off; 357 int cnt; 358 359 r = f->ram; 360 if (dopermw(f->ram)==0) 361 return Eperm; 362 if(r->busy == 0) 363 return Enotexist; 364 off = rhdr.offset; 365 if(r->perm & CHAPPEND) 366 off = r->ndata; 367 cnt = rhdr.count; 368 if(r->qid.path & CHDIR) 369 return "file is a directory"; 370 if(off > 100*1024*1024) /* sanity check */ 371 return "write too big"; 372 dowrite(r, rhdr.data, off, cnt); 373 r->qid.vers++; 374 r->mtime = time(0); 375 thdr.count = cnt; 376 return 0; 377 } 378 379 char * 380 rclunk(Fid *f) 381 { 382 if(f->open) 383 f->ram->open--; 384 f->busy = 0; 385 f->open = 0; 386 f->ram = 0; 387 return 0; 388 } 389 390 char * 391 rremove(Fid *f) 392 { 393 USED(f); 394 return Eperm; 395 } 396 397 char * 398 rstat(Fid *f) 399 { 400 if(f->ram->busy == 0) 401 return Enotexist; 402 ramstat(f->ram, thdr.stat); 403 return 0; 404 } 405 406 char * 407 rwstat(Fid *f) 408 { 409 if(f->ram->busy == 0) 410 return Enotexist; 411 return Eperm; 412 } 413 414 void 415 ramstat(Ram *r, char *buf) 416 { 417 Dir dir; 418 419 memmove(dir.name, r->name, NAMELEN); 420 dir.qid = r->qid; 421 dir.mode = r->perm; 422 dir.length = r->ndata; 423 dir.hlength = 0; 424 strcpy(dir.uid, r->user); 425 strcpy(dir.gid, r->group); 426 dir.atime = r->atime; 427 dir.mtime = r->mtime; 428 convD2M(&dir, buf); 429 } 430 431 Fid * 432 newfid(int fid) 433 { 434 Fid *f, *ff; 435 436 ff = 0; 437 for(f = fids; f; f = f->next) 438 if(f->fid == fid) 439 return f; 440 else if(!ff && !f->busy) 441 ff = f; 442 if(ff){ 443 ff->fid = fid; 444 ff->open = 0; 445 ff->busy = 1; 446 } 447 f = emalloc(sizeof *f); 448 f->ram = 0; 449 f->fid = fid; 450 f->busy = 1; 451 f->open = 0; 452 f->next = fids; 453 fids = f; 454 return f; 455 } 456 457 void 458 io(void) 459 { 460 char *err; 461 int n, nerr; 462 char buf[ERRLEN]; 463 464 errstr(buf); 465 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ 466 /* 467 * reading from a pipe or a network device 468 * will give an error after a few eof reads 469 * however, we cannot tell the difference 470 * between a zero-length read and an interrupt 471 * on the processes writing to us, 472 * so we wait for the error 473 */ 474 n = read(mfd[0], mdata, sizeof mdata); 475 if (n==0) 476 continue; 477 if(n < 0){ 478 if (buf[0]=='\0') 479 errstr(buf); 480 continue; 481 } 482 nerr = 0; 483 buf[0] = '\0'; 484 if(convM2S(mdata, &rhdr, n) == 0) 485 continue; 486 487 /* fprint(2, "ramfs:%F\n", &rhdr);/**/ 488 489 thdr.data = mdata + MAXMSG; 490 if(!fcalls[rhdr.type]) 491 err = "bad fcall type"; 492 else 493 err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 494 if(err){ 495 thdr.type = Rerror; 496 strncpy(thdr.ename, err, ERRLEN); 497 }else{ 498 thdr.type = rhdr.type + 1; 499 thdr.fid = rhdr.fid; 500 } 501 thdr.tag = rhdr.tag; 502 n = convS2M(&thdr, mdata); 503 if(write(mfd[1], mdata, n) != n) 504 error("mount write"); 505 } 506 if (buf[0]=='\0' || strncmp(buf, "write to hung", 13)==0) 507 exits(""); 508 fprint(2, "%s: mount read: %s\n", argv0, buf); 509 exits(buf); 510 } 511 512 int 513 perm(Fid *f, Ram *r, int p) 514 { 515 if (p==Pwrite && dopermw(r)==0) 516 return 0; 517 if((p*Pother) & r->perm) 518 return 1; 519 if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm)) 520 return 1; 521 if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm)) 522 return 1; 523 return 0; 524 } 525 526 void 527 error(char *s) 528 { 529 fprint(2, "%s: %s: ", argv0, s); 530 perror(""); 531 exits(s); 532 } 533 534 void * 535 emalloc(ulong n) 536 { 537 void *p; 538 p = malloc(n); 539 if(!p) 540 error("out of memory"); 541 return p; 542 } 543 544 void * 545 erealloc(void *p, ulong n) 546 { 547 p = realloc(p, n); 548 if(!p) 549 error("out of memory"); 550 return p; 551 } 552 553 void 554 usage(void) 555 { 556 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); 557 exits("usage"); 558 } 559