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