1 #include <u.h> 2 #include <libc.h> 3 #include <authsrv.h> 4 #include <fcall.h> 5 #include <tapefs.h> 6 7 Fid *fids; 8 Ram *ram; 9 int mfd[2]; 10 char *user; 11 uchar mdata[Maxbuf+IOHDRSZ]; 12 int messagesize = Maxbuf+IOHDRSZ; 13 Fcall rhdr; 14 Fcall thdr; 15 ulong path; 16 Idmap *uidmap; 17 Idmap *gidmap; 18 int replete; 19 int verbose; 20 int newtap; /* tap with time in sec */ 21 22 Fid * newfid(int); 23 int ramstat(Ram*, uchar*, int); 24 void io(void); 25 void usage(void); 26 int perm(int); 27 28 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), 29 *rattach(Fid*), *rwalk(Fid*), 30 *ropen(Fid*), *rcreate(Fid*), 31 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), 32 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); 33 34 char *(*fcalls[])(Fid*) = { 35 [Tflush] rflush, 36 [Tversion] rversion, 37 [Tauth] rauth, 38 [Tattach] rattach, 39 [Twalk] rwalk, 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[] = "tapefs: authentication not required"; 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 char buf[TICKREQLEN]; 77 78 fmtinstall('F', fcallfmt); 79 80 defmnt = "/n/tapefs"; 81 ARGBEGIN{ 82 case 'm': 83 defmnt = ARGF(); 84 break; 85 case 'p': /* password file */ 86 uidmap = getpass(ARGF()); 87 break; 88 case 'g': /* group file */ 89 gidmap = getpass(ARGF()); 90 break; 91 case 'v': 92 verbose++; 93 94 case 'n': 95 newtap++; 96 break; 97 default: 98 usage(); 99 }ARGEND 100 101 if(argc==0) 102 error("no file to mount"); 103 user = getuser(); 104 if(user == nil) 105 user = "dmr"; 106 ram = r = (Ram *)emalloc(sizeof(Ram)); 107 r->busy = 1; 108 r->data = 0; 109 r->ndata = 0; 110 r->perm = DMDIR | 0775; 111 r->qid.path = 0; 112 r->qid.vers = 0; 113 r->qid.type = QTDIR; 114 r->parent = 0; 115 r->child = 0; 116 r->next = 0; 117 r->user = user; 118 r->group = user; 119 r->atime = time(0); 120 r->mtime = r->atime; 121 r->replete = 0; 122 r->name = estrdup("."); 123 populate(argv[0]); 124 r->replete |= replete; 125 if(pipe(p) < 0) 126 error("pipe failed"); 127 mfd[0] = mfd[1] = p[0]; 128 notify(notifyf); 129 130 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ 131 case -1: 132 error("fork"); 133 case 0: 134 close(p[1]); 135 notify(notifyf); 136 io(); 137 break; 138 default: 139 close(p[0]); /* don't deadlock if child fails */ 140 if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) { 141 sprint(buf, "mount on `%s' failed", defmnt); 142 error(buf); 143 } 144 } 145 exits(0); 146 } 147 148 char* 149 rversion(Fid *unused) 150 { 151 Fid *f; 152 153 USED(unused); 154 155 if(rhdr.msize < 256) 156 return "version: message too small"; 157 if(rhdr.msize > messagesize) 158 rhdr.msize = messagesize; 159 else 160 messagesize = rhdr.msize; 161 thdr.msize = messagesize; 162 if(strncmp(rhdr.version, "9P2000", 6) != 0) 163 return "unrecognized 9P version"; 164 thdr.version = "9P2000"; 165 166 for(f = fids; f; f = f->next) 167 if(f->busy) 168 rclunk(f); 169 return 0; 170 } 171 172 char* 173 rauth(Fid *unused) 174 { 175 USED(unused); 176 177 return Enoauth; 178 } 179 180 char* 181 rflush(Fid *f) 182 { 183 USED(f); 184 return 0; 185 } 186 187 char* 188 rattach(Fid *f) 189 { 190 /* no authentication! */ 191 f->busy = 1; 192 f->rclose = 0; 193 f->ram = ram; 194 thdr.qid = f->ram->qid; 195 if(rhdr.uname[0]) 196 f->user = strdup(rhdr.uname); 197 else 198 f->user = "none"; 199 return 0; 200 } 201 202 char* 203 rwalk(Fid *f) 204 { 205 Fid *nf; 206 Ram *r; 207 char *err; 208 char *name; 209 Ram *dir; 210 int i; 211 212 nf = nil; 213 if(f->ram->busy == 0) 214 return Enotexist; 215 if(f->open) 216 return Eisopen; 217 if(rhdr.newfid != rhdr.fid){ 218 nf = newfid(rhdr.newfid); 219 nf->busy = 1; 220 nf->open = 0; 221 nf->rclose = 0; 222 nf->ram = f->ram; 223 nf->user = f->user; /* no ref count; the leakage is minor */ 224 f = nf; 225 } 226 227 thdr.nwqid = 0; 228 err = nil; 229 r = f->ram; 230 231 if(rhdr.nwname > 0){ 232 for(i=0; i<rhdr.nwname; i++){ 233 if((r->qid.type & QTDIR) == 0){ 234 err = Enotdir; 235 break; 236 } 237 if(r->busy == 0){ 238 err = Enotexist; 239 break; 240 } 241 r->atime = time(0); 242 name = rhdr.wname[i]; 243 dir = r; 244 if(!perm(Pexec)){ 245 err = Eperm; 246 break; 247 } 248 if(strcmp(name, "..") == 0){ 249 r = dir->parent; 250 Accept: 251 if(i == MAXWELEM){ 252 err = "name too long"; 253 break; 254 } 255 thdr.wqid[thdr.nwqid++] = r->qid; 256 continue; 257 } 258 if(!dir->replete) 259 popdir(dir); 260 for(r=dir->child; r; r=r->next) 261 if(r->busy && strcmp(name, r->name)==0) 262 goto Accept; 263 break; /* file not found */ 264 } 265 266 if(i==0 && err == nil) 267 err = Enotexist; 268 } 269 270 if(err!=nil || thdr.nwqid<rhdr.nwname){ 271 if(nf){ 272 nf->busy = 0; 273 nf->open = 0; 274 nf->ram = 0; 275 } 276 }else if(thdr.nwqid == rhdr.nwname) 277 f->ram = r; 278 279 return err; 280 281 } 282 283 char * 284 ropen(Fid *f) 285 { 286 Ram *r; 287 int mode, trunc; 288 289 if(f->open) 290 return Eisopen; 291 r = f->ram; 292 if(r->busy == 0) 293 return Enotexist; 294 if(r->perm & DMEXCL) 295 if(r->open) 296 return Excl; 297 mode = rhdr.mode; 298 if(r->qid.type & QTDIR){ 299 if(mode != OREAD) 300 return Eperm; 301 thdr.qid = r->qid; 302 return 0; 303 } 304 if(mode & ORCLOSE) 305 return Eperm; 306 trunc = mode & OTRUNC; 307 mode &= OPERM; 308 if(mode==OWRITE || mode==ORDWR || trunc) 309 if(!perm(Pwrite)) 310 return Eperm; 311 if(mode==OREAD || mode==ORDWR) 312 if(!perm(Pread)) 313 return Eperm; 314 if(mode==OEXEC) 315 if(!perm(Pexec)) 316 return Eperm; 317 if(trunc && (r->perm&DMAPPEND)==0){ 318 r->ndata = 0; 319 dotrunc(r); 320 r->qid.vers++; 321 } 322 thdr.qid = r->qid; 323 thdr.iounit = messagesize-IOHDRSZ; 324 f->open = 1; 325 r->open++; 326 return 0; 327 } 328 329 char * 330 rcreate(Fid *f) 331 { 332 USED(f); 333 334 return Eperm; 335 } 336 337 char* 338 rread(Fid *f) 339 { 340 int i, len; 341 Ram *r; 342 char *buf; 343 uvlong off, end; 344 int n, cnt; 345 346 if(f->ram->busy == 0) 347 return Enotexist; 348 n = 0; 349 thdr.count = 0; 350 off = rhdr.offset; 351 end = rhdr.offset + rhdr.count; 352 cnt = rhdr.count; 353 if(cnt > messagesize-IOHDRSZ) 354 cnt = messagesize-IOHDRSZ; 355 buf = thdr.data; 356 if(f->ram->qid.type & QTDIR){ 357 if(!f->ram->replete) 358 popdir(f->ram); 359 for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){ 360 if(!r->busy) 361 continue; 362 len = ramstat(r, (uchar*)buf+n, cnt-n); 363 if(len <= BIT16SZ) 364 break; 365 if(i >= off) 366 n += len; 367 i += len; 368 } 369 thdr.count = n; 370 return 0; 371 } 372 r = f->ram; 373 if(off >= r->ndata) 374 return 0; 375 r->atime = time(0); 376 n = cnt; 377 if(off+n > r->ndata) 378 n = r->ndata - off; 379 thdr.data = doread(r, off, n); 380 thdr.count = n; 381 return 0; 382 } 383 384 char* 385 rwrite(Fid *f) 386 { 387 Ram *r; 388 ulong off; 389 int cnt; 390 391 r = f->ram; 392 if(dopermw(f->ram)==0) 393 return Eperm; 394 if(r->busy == 0) 395 return Enotexist; 396 off = rhdr.offset; 397 if(r->perm & DMAPPEND) 398 off = r->ndata; 399 cnt = rhdr.count; 400 if(r->qid.type & QTDIR) 401 return "file is a directory"; 402 if(off > 100*1024*1024) /* sanity check */ 403 return "write too big"; 404 dowrite(r, rhdr.data, off, cnt); 405 r->qid.vers++; 406 r->mtime = time(0); 407 thdr.count = cnt; 408 return 0; 409 } 410 411 char * 412 rclunk(Fid *f) 413 { 414 if(f->open) 415 f->ram->open--; 416 f->busy = 0; 417 f->open = 0; 418 f->ram = 0; 419 return 0; 420 } 421 422 char * 423 rremove(Fid *f) 424 { 425 USED(f); 426 return Eperm; 427 } 428 429 char * 430 rstat(Fid *f) 431 { 432 if(f->ram->busy == 0) 433 return Enotexist; 434 thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ); 435 return 0; 436 } 437 438 char * 439 rwstat(Fid *f) 440 { 441 if(f->ram->busy == 0) 442 return Enotexist; 443 return Eperm; 444 } 445 446 int 447 ramstat(Ram *r, uchar *buf, int nbuf) 448 { 449 Dir dir; 450 451 dir.name = r->name; 452 dir.qid = r->qid; 453 dir.mode = r->perm; 454 dir.length = r->ndata; 455 dir.uid = r->user; 456 dir.gid = r->group; 457 dir.muid = r->user; 458 dir.atime = r->atime; 459 dir.mtime = r->mtime; 460 return convD2M(&dir, buf, nbuf); 461 } 462 463 Fid * 464 newfid(int fid) 465 { 466 Fid *f, *ff; 467 468 ff = 0; 469 for(f = fids; f; f = f->next) 470 if(f->fid == fid) 471 return f; 472 else if(!ff && !f->busy) 473 ff = f; 474 if(ff){ 475 ff->fid = fid; 476 ff->open = 0; 477 ff->busy = 1; 478 } 479 f = emalloc(sizeof *f); 480 f->ram = 0; 481 f->fid = fid; 482 f->busy = 1; 483 f->open = 0; 484 f->next = fids; 485 fids = f; 486 return f; 487 } 488 489 void 490 io(void) 491 { 492 char *err; 493 int n, nerr; 494 char buf[ERRMAX]; 495 496 errstr(buf, sizeof buf); 497 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ 498 /* 499 * reading from a pipe or a network device 500 * will give an error after a few eof reads 501 * however, we cannot tell the difference 502 * between a zero-length read and an interrupt 503 * on the processes writing to us, 504 * so we wait for the error 505 */ 506 n = read9pmsg(mfd[0], mdata, sizeof mdata); 507 if(n==0) 508 continue; 509 if(n < 0){ 510 if(buf[0]=='\0') 511 errstr(buf, sizeof buf); 512 continue; 513 } 514 nerr = 0; 515 buf[0] = '\0'; 516 if(convM2S(mdata, n, &rhdr) != n) 517 error("convert error in convM2S"); 518 519 if(verbose) 520 fprint(2, "tapefs: <=%F\n", &rhdr);/**/ 521 522 thdr.data = (char*)mdata + IOHDRSZ; 523 thdr.stat = mdata + IOHDRSZ; 524 if(!fcalls[rhdr.type]) 525 err = "bad fcall type"; 526 else 527 err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 528 if(err){ 529 thdr.type = Rerror; 530 thdr.ename = err; 531 }else{ 532 thdr.type = rhdr.type + 1; 533 thdr.fid = rhdr.fid; 534 } 535 thdr.tag = rhdr.tag; 536 n = convS2M(&thdr, mdata, messagesize); 537 if(n <= 0) 538 error("convert error in convS2M"); 539 if(verbose) 540 fprint(2, "tapefs: =>%F\n", &thdr);/**/ 541 if(write(mfd[1], mdata, n) != n) 542 error("mount write"); 543 } 544 if(buf[0]=='\0' || strstr(buf, "hungup")) 545 exits(""); 546 fprint(2, "%s: mount read: %s\n", argv0, buf); 547 exits(buf); 548 } 549 550 int 551 perm(int p) 552 { 553 if(p==Pwrite) 554 return 0; 555 return 1; 556 } 557 558 void 559 error(char *s) 560 { 561 fprint(2, "%s: %s: ", argv0, s); 562 perror(""); 563 exits(s); 564 } 565 566 char* 567 estrdup(char *s) 568 { 569 char *t; 570 571 t = emalloc(strlen(s)+1); 572 strcpy(t, s); 573 return t; 574 } 575 576 void * 577 emalloc(ulong n) 578 { 579 void *p; 580 p = mallocz(n, 1); 581 if(!p) 582 error("out of memory"); 583 return p; 584 } 585 586 void * 587 erealloc(void *p, ulong n) 588 { 589 p = realloc(p, n); 590 if(!p) 591 error("out of memory"); 592 return p; 593 } 594 595 void 596 usage(void) 597 { 598 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); 599 exits("usage"); 600 } 601