1 #include "u.h" 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include "libc.h" 5 #include "9p.h" 6 #include "stdio.h" 7 #include "setjmp.h" 8 #include "pwd.h" 9 #include "grp.h" 10 11 #define DBG(f) 12 13 struct group *getgrent(void); 14 struct passwd *getpwent(void); 15 16 #ifdef SYSV 17 # include <dirent.h> 18 # define DTYPE struct dirent 19 # define SOCKETS 20 #endif 21 #ifdef V10 22 # include <ndir.h> 23 # define DTYPE struct direct 24 #endif 25 #ifdef BSD 26 # include <sys/dir.h> 27 # define DTYPE struct direct 28 # define SOCKETS 29 #endif 30 #ifdef SOCKETS 31 # define sendmsg __sendmsg 32 # include <sys/socket.h> 33 # include <netinet/in.h> 34 # include <netdb.h> 35 # undef sendmsg 36 char bsdhost[256]; 37 void remotehostname(void); 38 #endif 39 40 typedef struct File File; 41 typedef struct Rfile Rfile; 42 typedef struct Fd Fd; 43 typedef struct Pass Pass; 44 45 struct Fd{ 46 int ref; 47 Ulong offset; 48 int fd; 49 DIR *dir; 50 }; 51 52 struct Rfile{ 53 int busy; 54 int uid; 55 int gid; 56 int rclose; 57 File *file; 58 Fd *fd; 59 }; 60 61 struct File{ 62 int ref; 63 char *path; 64 char *name; 65 Qid qid; 66 struct stat stbuf; 67 }; 68 69 struct Pass{ 70 int id; 71 int gid; 72 char *name; 73 Pass *next; 74 }; 75 76 char data[2][MAXMSG+MAXFDATA]; 77 char tdata[MAXMSG+MAXFDATA]; 78 char rdata[MAXFDATA]; 79 Fcall rhdr; 80 Fcall thdr; 81 Rfile *rfile; 82 File *file0; 83 int nrfilealloc; 84 jmp_buf loopjmp; 85 Pass* uid[256]; 86 Pass* gid[256]; 87 int devallowed; 88 int connected; 89 90 void io(void); 91 void error(char*); 92 char *mfmt(Fcall*); 93 void sendmsg(char*); 94 int okfid(int); 95 Rfile* rfilefid(void); 96 File* newfile(void); 97 void* erealloc(void*, unsigned); 98 char* estrdup(char*); 99 char* dostat(File*, char*); 100 char* bldpath(char*, char*, char*); 101 Ulong qid(struct stat*); 102 Ulong vers(struct stat*); 103 void errjmp(char*); 104 int omode(int); 105 char* id2name(Pass**, int); 106 Pass* name2pass(Pass**, char*); 107 void getpwdf(void); 108 void getgrpf(void); 109 void perm(Rfile*, int, struct stat*); 110 void parentwrperm(Rfile*); 111 112 void rsession(void); 113 void rattach(void); 114 void rflush(void); 115 void rclone(void); 116 void rwalk(void); 117 void ropen(void); 118 void rcreate(void); 119 void rread(void); 120 void rwrite(void); 121 void rclunk(int); 122 void rstat(void); 123 void rwstat(void); 124 void rclwalk(void); 125 126 char Eauth[] = "authentication failed"; 127 char Eperm[] = "permission denied"; 128 char Ebadfid[] = "fid unknown or out of range"; 129 char Efidactive[] = "fid already in use"; 130 char Eopen[] = "file is open"; 131 char Emode[] = "invalid open mode"; 132 char Especial[] = "no access to special file"; 133 char Especial0[] = "already attached without access to special files"; 134 char Especial1[] = "already attached with access to special files"; 135 char Enotopen[] = "file is not open"; 136 char Etoolarge[] = "i/o count too large"; 137 char Ebaddir[] = "i/o error on directory"; 138 char Eunknown[] = "unknown user or group"; 139 char Euid[] = "can't set uid"; 140 char Egid[] = "can't set gid"; 141 char Eowner[] = "not owner"; 142 143 int 144 main(int argc, char *argv[]) 145 { 146 freopen(LOG, "a", stderr); 147 setbuf(stderr, (void*)0); 148 DBG(fprintf(stderr, "u9fs\nkill %d\n", getpid())); 149 if(argc > 1) 150 if(chroot(argv[1]) == -1) 151 error("chroot failed"); 152 153 # ifdef SOCKETS 154 remotehostname(); 155 # endif 156 157 io(); 158 return 0; 159 } 160 161 void 162 io(void) 163 { 164 int m; 165 static int toggle, ndata; 166 char *datap; 167 168 /* 169 * TCP does not preserve record boundaries; this dance works around 170 * the problem. 171 */ 172 setjmp(loopjmp); 173 174 /* 175 * Invariant: data[toggle] has ndata bytes already 176 */ 177 loop: 178 datap = data[toggle]; 179 toggle ^= 1; 180 for(;;){ 181 if(ndata){ 182 m = convM2S(datap, &rhdr, ndata); 183 /* m is number of bytes more than a full message */ 184 if(m >= 0){ 185 memmove(data[toggle], datap+(ndata-m), m); 186 ndata = m; 187 break; 188 } 189 } 190 m = read(0, datap+ndata, (MAXMSG+MAXFDATA)-ndata); 191 if(m <= 0) 192 error("read"); 193 ndata += m; 194 } 195 196 thdr.type = rhdr.type+1; 197 thdr.tag = rhdr.tag; 198 thdr.fid = rhdr.fid; 199 DBG(fprintf(stderr, ">> %s\n", mfmt(&rhdr))); 200 switch(rhdr.type){ 201 case Tnop: 202 case Tflush: /* this is a synchronous fs; easy */ 203 break; 204 case Tsession: 205 rsession(); 206 break; 207 case Tattach: 208 rattach(); 209 break; 210 case Tclone: 211 rclone(); 212 break; 213 case Twalk: 214 rwalk(); 215 break; 216 case Tstat: 217 rstat(); 218 break; 219 case Twstat: 220 rwstat(); 221 break; 222 case Topen: 223 ropen(); 224 break; 225 case Tcreate: 226 rcreate(); 227 break; 228 case Tread: 229 rread(); 230 break; 231 case Twrite: 232 rwrite(); 233 break; 234 case Tclunk: 235 rclunk(0); 236 break; 237 case Tremove: 238 rclunk(1); 239 break; 240 default: 241 fprintf(stderr, "unknown message %s\n", mfmt(&rhdr)); 242 error("bad message"); 243 } 244 sendmsg(0); 245 goto loop; 246 } 247 248 void 249 rsession(void) 250 { 251 memset(thdr.authid, 0, sizeof(thdr.authid)); 252 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 253 memset(thdr.chal, 0, sizeof(thdr.chal)); 254 } 255 256 void 257 rattach(void) 258 { 259 Rfile *rf; 260 char *err; 261 Pass *p; 262 263 err = 0; 264 if(file0 == 0){ 265 file0 = newfile(); 266 file0->ref++; /* one extra to hold it up */ 267 file0->path = estrdup("/"); 268 file0->name = estrdup("/"); 269 errjmp(dostat(file0, 0)); 270 } 271 if(!okfid(rhdr.fid)) 272 errjmp(Ebadfid); 273 if(strncmp(rhdr.aname, "device", 6) == 0){ 274 if(connected && !devallowed) 275 errjmp(Especial0); 276 devallowed = 1; 277 }else{ 278 if(connected && devallowed) 279 errjmp(Especial1); 280 } 281 getpwdf(); 282 getgrpf(); 283 rf = &rfile[rhdr.fid]; 284 if(rf->busy) 285 errjmp(Efidactive); 286 p = name2pass(uid, rhdr.uname); 287 if(p == 0) 288 errjmp(Eunknown); 289 if(p->id == 0) 290 errjmp(Eperm); 291 # ifdef SOCKETS 292 if(ruserok(bsdhost, 0, rhdr.uname, rhdr.uname) < 0) 293 errjmp(Eperm); 294 # endif 295 /* mark busy & inc ref cnt only after committed to succeed */ 296 rf->busy = 1; 297 rf->file = file0; 298 file0->ref++; 299 rf->rclose = 0; 300 rf->uid = p->id; 301 rf->gid = p->gid; 302 thdr.qid = file0->qid; 303 connected = 1; 304 } 305 306 void 307 rclone(void) 308 { 309 Rfile *rf, *nrf; 310 File *f; 311 312 rfilefid(); 313 if(!okfid(rhdr.newfid)) 314 errjmp(Ebadfid); 315 rf = &rfile[rhdr.fid]; 316 nrf = &rfile[rhdr.newfid]; 317 f = rf->file; 318 if(nrf->busy) 319 errjmp(Efidactive); 320 nrf->busy = 1; 321 nrf->file = f; 322 f->ref++; 323 nrf->fd = rf->fd; 324 nrf->uid = rf->uid; 325 nrf->gid = rf->gid; 326 nrf->rclose = rf->rclose; 327 if(nrf->fd){ 328 if(nrf->fd->ref == 0) 329 error("clone fd count"); 330 nrf->fd->ref++; 331 } 332 } 333 334 void 335 rwalk(void) 336 { 337 char *err; 338 Rfile *rf; 339 File *of, *f; 340 341 rf = rfilefid(); 342 if(rf->fd) 343 errjmp(Eopen); 344 of = rf->file; 345 perm(rf, 1, 0); 346 f = newfile(); 347 f->path = estrdup(of->path); 348 err = dostat(f, rhdr.name); 349 if(err){ 350 f->ref = 0; 351 free(f->path); 352 errjmp(err); 353 } 354 if(of->ref <= 0) 355 error("walk ref count"); 356 if(--of->ref == 0){ 357 free(of->path); 358 free(of->name); 359 free(of); 360 } 361 rf->file = f; 362 thdr.qid = f->qid; 363 } 364 365 void 366 ropen(void) 367 { 368 Rfile *rf; 369 File *f; 370 int fd; 371 DIR *dir; 372 int m, trunc; 373 374 rf = rfilefid(); 375 f = rf->file; 376 if(rf->fd) 377 error("open already open"); 378 if(!devallowed && (f->stbuf.st_mode & S_IFCHR)) 379 errjmp(Especial); 380 m = rhdr.mode & (16|3); 381 trunc = m & 16; /* OTRUNC */ 382 switch(m){ 383 case 0: 384 perm(rf, 4, 0); 385 break; 386 case 1: 387 case 1|16: 388 perm(rf, 2, 0); 389 break; 390 case 2: 391 case 0|16: 392 case 2|16: 393 perm(rf, 4, 0); 394 perm(rf, 2, 0); 395 break; 396 case 3: 397 perm(rf, 1, 0); 398 break; 399 default: 400 errjmp(Emode); 401 } 402 403 m = omode(m & 3); 404 errno = 0; 405 if(f->qid.path & CHDIR){ 406 if(rhdr.mode != 0) /* OREAD */ 407 errjmp(Eperm); 408 dir = opendir(f->path); 409 if(dir == 0) 410 errjmp(sys_errlist[errno]); 411 fd = 0; 412 }else{ 413 if(trunc){ 414 fd = creat(f->path, 0666); 415 if(fd >= 0) 416 if(m != 1){ 417 close(fd); 418 fd = open(f->path, m); 419 } 420 }else 421 fd = open(f->path, m); 422 if(fd < 0) 423 errjmp(sys_errlist[errno]); 424 dir = 0; 425 } 426 rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 427 rf->fd = erealloc(0, sizeof(Fd)); 428 rf->fd->ref = 1; 429 rf->fd->fd = fd; 430 rf->fd->dir = dir; 431 rf->fd->offset = 0; 432 thdr.qid = f->qid; 433 } 434 435 void 436 rcreate(void) 437 { 438 Rfile *rf; 439 File *f, *of; 440 char *path, *err; 441 int fd; 442 int m; 443 char name[NAMELEN]; 444 445 rf = rfilefid(); 446 if(rf->fd) 447 errjmp(Eopen); 448 perm(rf, 2, 0); 449 path = bldpath(rf->file->path, rhdr.name, name); 450 m = omode(rhdr.mode&3); 451 errno = 0; 452 if(rhdr.perm & CHDIR){ 453 if(m){ 454 free(path); 455 errjmp(Eperm); 456 } 457 fd = mkdir(path, 0777); 458 if(fd < 0){ 459 free(path); 460 errjmp(sys_errlist[errno]); 461 } 462 fd = open(path, 0); 463 free(path); 464 if(fd >= 0){ 465 fchmod(fd, rhdr.perm&0777); 466 fchown(fd, rf->uid, rf->gid); 467 } 468 }else{ 469 fd = creat(path, 0666); 470 if(fd >= 0){ 471 if(m != 1){ 472 close(fd); 473 fd = open(path, m); 474 } 475 fchmod(fd, rhdr.perm&0777); 476 fchown(fd, rf->uid, rf->gid); 477 } 478 free(path); 479 if(fd < 0) 480 errjmp(sys_errlist[errno]); 481 } 482 f = newfile(); 483 of = rf->file; 484 f->path = estrdup(of->path); 485 err = dostat(f, rhdr.name); 486 if(err){ 487 free(f->path); 488 free(f->name); 489 free(f); 490 errjmp(err); 491 } 492 if(!devallowed && (f->stbuf.st_mode & S_IFCHR)){ 493 free(f->path); 494 free(f->name); 495 free(f); 496 errjmp(Especial); 497 } 498 if(--of->ref == 0){ 499 free(of->path); 500 free(of->name); 501 free(of); 502 } 503 rf->file = f; 504 rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 505 rf->fd = erealloc(0, sizeof(Fd)); 506 rf->fd->ref = 1; 507 rf->fd->fd = fd; 508 rf->fd->dir = 0; 509 rf->fd->offset = 0; 510 thdr.qid = f->qid; 511 } 512 513 void 514 rread(void) 515 { 516 Rfile *rf; 517 File *f; 518 long n; 519 DTYPE *de; 520 Dir d; 521 struct stat stbuf; 522 char *path; 523 524 rf = rfilefid(); 525 if(rf->fd == 0) 526 errjmp(Enotopen); 527 if(rhdr.count > sizeof rdata) 528 errjmp(Etoolarge); 529 f = rf->file; 530 if(rf->fd->dir){ 531 errno = 0; 532 rhdr.count = (rhdr.count/DIRLEN)*DIRLEN; 533 if(rf->fd->offset != rhdr.offset){ 534 rf->fd->offset = rhdr.offset; /* sync offset */ 535 seekdir(rf->fd->dir, 0); 536 for(n=0; n<rhdr.offset; ){ 537 de = readdir(rf->fd->dir); 538 if(de == 0) 539 break; 540 if(de->d_ino==0 || de->d_name[0]==0) 541 continue; 542 if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 543 continue; 544 n += DIRLEN; 545 } 546 } 547 for(n=0; n<rhdr.count; ){ 548 de = readdir(rf->fd->dir); 549 if(de == 0) 550 break; 551 if(de->d_ino==0 || de->d_name[0]==0) 552 continue; 553 if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 554 continue; 555 strncpy(d.name, de->d_name, NAMELEN-1); 556 d.name[NAMELEN-1] = 0; 557 path = erealloc(0, strlen(f->path)+1+strlen(de->d_name)+1); 558 sprintf(path, "%s/%s", f->path, de->d_name); 559 memset(&stbuf, 0, sizeof stbuf); 560 if(stat(path, &stbuf) < 0){ 561 fprintf(stderr, "dir: bad path %s\n", path); 562 /* but continue... probably a bad symlink */ 563 } 564 free(path); 565 strncpy(d.uid, id2name(uid, stbuf.st_uid), NAMELEN); 566 strncpy(d.gid, id2name(gid, stbuf.st_gid), NAMELEN); 567 d.qid.path = qid(&stbuf); 568 d.qid.vers = vers(&stbuf); 569 d.mode = (d.qid.path&CHDIR)|(stbuf.st_mode&0777); 570 d.atime = stbuf.st_atime; 571 d.mtime = stbuf.st_mtime; 572 d.len.l.hlength = 0; 573 d.len.l.length = stbuf.st_size; 574 convD2M(&d, rdata+n); 575 n += DIRLEN; 576 } 577 }else{ 578 errno = 0; 579 if(rf->fd->offset != rhdr.offset){ 580 rf->fd->offset = rhdr.offset; 581 if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 582 errjmp(sys_errlist[errno]); 583 } 584 n = read(rf->fd->fd, rdata, rhdr.count); 585 if(n < 0) 586 errjmp(sys_errlist[errno]); 587 } 588 rf->fd->offset += n; 589 thdr.count = n; 590 thdr.data = rdata; 591 } 592 593 void 594 rwrite(void) 595 { 596 Rfile *rf; 597 int n; 598 599 rf = rfilefid(); 600 if(rf->fd == 0) 601 errjmp(Enotopen); 602 if(rhdr.count > sizeof rdata) 603 errjmp(Etoolarge); 604 errno = 0; 605 if(rf->fd->offset != rhdr.offset){ 606 rf->fd->offset = rhdr.offset; 607 if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 608 errjmp(sys_errlist[errno]); 609 } 610 n = write(rf->fd->fd, rhdr.data, rhdr.count); 611 if(n < 0) 612 errjmp(sys_errlist[errno]); 613 rf->fd->offset += n; 614 thdr.count = n; 615 } 616 617 void 618 rstat(void) 619 { 620 Rfile *rf; 621 File *f; 622 Dir d; 623 624 rf = rfilefid(); 625 f = rf->file; 626 errjmp(dostat(f, 0)); 627 strncpy(d.name, f->name, NAMELEN); 628 strncpy(d.uid, id2name(uid, f->stbuf.st_uid), NAMELEN); 629 strncpy(d.gid, id2name(gid, f->stbuf.st_gid), NAMELEN); 630 d.qid = f->qid; 631 d.mode = (f->qid.path&CHDIR)|(f->stbuf.st_mode&0777); 632 d.atime = f->stbuf.st_atime; 633 d.mtime = f->stbuf.st_mtime; 634 d.len.l.hlength = 0; 635 d.len.l.length = f->stbuf.st_size; 636 convD2M(&d, thdr.stat); 637 } 638 639 void 640 rwstat(void) 641 { 642 Rfile *rf; 643 File *f; 644 Dir d; 645 Pass *p; 646 char *path, *dir, name[NAMELEN]; 647 648 rf = rfilefid(); 649 f = rf->file; 650 errjmp(dostat(f, 0)); 651 convM2D(rhdr.stat, &d); 652 errno = 0; 653 if(rf->uid != f->stbuf.st_uid) 654 errjmp(Eowner); 655 if(strcmp(d.name, f->name) != 0){ 656 parentwrperm(rf); 657 dir = bldpath(f->path, "..", name); 658 path = erealloc(0, strlen(dir)+1+strlen(d.name)+1); 659 sprintf(path, "%s/%s", dir, d.name); 660 if(link(f->path, path) < 0){ 661 free(path); 662 errjmp(sys_errlist[errno]); 663 } 664 if(unlink(f->path) < 0){ 665 free(path); 666 errjmp(sys_errlist[errno]); 667 } 668 free(f->path); 669 free(f->name); 670 f->path = path; 671 f->name = estrdup(d.name); 672 } 673 if((d.mode&0777) != (f->stbuf.st_mode&0777)){ 674 if(chmod(f->path, d.mode&0777) < 0) 675 errjmp(sys_errlist[errno]); 676 f->stbuf.st_mode &= ~0777; 677 f->stbuf.st_mode |= d.mode&0777; 678 } 679 p = name2pass(gid, d.gid); 680 if(p == 0) 681 errjmp(Eunknown); 682 if(p->id != f->stbuf.st_gid){ 683 if(chown(f->path, f->stbuf.st_uid, p->id) < 0) 684 errjmp(sys_errlist[errno]); 685 f->stbuf.st_gid = p->id; 686 } 687 } 688 689 void 690 rclunk(int rm) 691 { 692 int ret; 693 char *err; 694 Rfile *rf; 695 File *f; 696 Fd *fd; 697 698 err = 0; 699 rf = rfilefid(); 700 f = rf->file; 701 if(rm){ 702 parentwrperm(rf); 703 if(f->qid.path & CHDIR) 704 ret = rmdir(f->path); 705 else 706 ret = unlink(f->path); 707 if(ret) 708 err = sys_errlist[errno]; 709 }else if(rf->rclose){ /* ignore errors */ 710 if(f->qid.path & CHDIR) 711 rmdir(f->path); 712 else 713 unlink(f->path); 714 } 715 716 rf->busy = 0; 717 if(--f->ref == 0){ 718 free(f->path); 719 free(f->name); 720 free(f); 721 } 722 fd = rf->fd; 723 if(fd){ 724 if(fd->ref <= 0) 725 error("clunk fd count"); 726 if(--fd->ref == 0){ 727 if(fd->fd) 728 close(fd->fd); 729 if(fd->dir) 730 closedir(fd->dir); 731 free(fd); 732 } 733 rf->fd = 0; 734 } 735 if(err) 736 errjmp(err); 737 } 738 739 char* 740 bldpath(char *a, char *elem, char *name) 741 { 742 char *path, *p; 743 744 if(strcmp(elem, "..") == 0){ 745 if(strcmp(a, "/") == 0){ 746 path = estrdup(a); 747 strcpy(name, a); 748 }else{ 749 p = strrchr(a, '/'); 750 if(p == 0){ 751 fprintf(stderr, "path: '%s'\n", path); 752 error("malformed path 1"); 753 } 754 if(p == a) /* reduced to "/" */ 755 p++; 756 path = erealloc(0, (p-a)+1); 757 memmove(path, a, (p-a)); 758 path[(p-a)] = 0; 759 if(strcmp(path, "/") == 0) 760 p = path; 761 else{ 762 p = strrchr(path, '/'); 763 if(p == 0){ 764 fprintf(stderr, "path: '%s'\n", path); 765 error("malformed path 2"); 766 } 767 p++; 768 } 769 strcpy(name, p); 770 } 771 }else{ 772 if(strcmp(a, "/") == 0) 773 a = ""; 774 path = erealloc(0, strlen(a)+1+strlen(elem)+1); 775 sprintf(path, "%s/%s", a, elem); 776 strcpy(name, elem); 777 } 778 if(strlen(name) >= NAMELEN) 779 error("bldpath: name too long"); 780 return path; 781 } 782 783 char* 784 dostat(File *f, char *elem) 785 { 786 char *path; 787 struct stat stbuf; 788 char name[NAMELEN]; 789 790 if(elem) 791 path = bldpath(f->path, elem, name); 792 else 793 path = f->path; 794 errno = 0; 795 if(stat(path, &stbuf) < 0) 796 return sys_errlist[errno]; 797 if(elem){ 798 free(f->path); 799 f->path = path; 800 f->name = estrdup(name); 801 } 802 f->qid.path = qid(&stbuf); 803 f->qid.vers = vers(&stbuf); 804 f->stbuf = stbuf; 805 return 0; 806 } 807 808 int 809 omode(int m) 810 { 811 switch(m){ 812 case 0: /* OREAD */ 813 case 3: /* OEXEC */ 814 return 0; 815 case 1: /* OWRITE */ 816 return 1; 817 case 2: /* ORDWR */ 818 return 2; 819 } 820 errjmp(Emode); 821 return 0; 822 } 823 824 void 825 sendmsg(char *err) 826 { 827 int n; 828 829 if(err){ 830 thdr.type = Rerror; 831 strncpy(thdr.ename, err, ERRLEN); 832 } 833 DBG(fprintf(stderr, "<< %s\n", mfmt(&thdr))); 834 n = convS2M(&thdr, tdata); 835 if(n == 0) 836 error("bad sendmsg format"); 837 if(write(1, tdata, n) != n) 838 error("write error"); 839 } 840 841 842 int 843 okfid(int fid) 844 { 845 enum{ Delta=10 }; 846 847 if(fid < 0){ 848 fprintf(stderr, "u9fs: negative fid %d\n", fid); 849 return 0; 850 } 851 if(fid >= nrfilealloc){ 852 fid += Delta; 853 rfile = erealloc(rfile, fid*sizeof(Rfile)); 854 memset(rfile+nrfilealloc, 0, (fid-nrfilealloc)*sizeof(Rfile)); 855 nrfilealloc = fid; 856 } 857 return 1; 858 } 859 860 Rfile* 861 rfilefid(void) 862 { 863 Rfile *rf; 864 865 if(!okfid(rhdr.fid)) 866 errjmp(Ebadfid); 867 rf = &rfile[rhdr.fid]; 868 if(rf->busy == 0) 869 errjmp(Ebadfid); 870 if(rf->file->ref <= 0) 871 error("ref count"); 872 return rf; 873 } 874 875 void 876 perm(Rfile *rf, int mask, struct stat *st) 877 { 878 if(st == 0) 879 st = &rf->file->stbuf; 880 /* plan 9 access semantics; simpler and more sensible */ 881 if(rf->uid == st->st_uid) 882 if((st->st_mode>>6) & mask) 883 return; 884 if(rf->gid == st->st_gid) 885 if((st->st_mode>>3) & mask) 886 return; 887 if((st->st_mode>>0) & mask) 888 return; 889 errjmp(Eperm); 890 } 891 892 void 893 parentwrperm(Rfile *rf) 894 { 895 Rfile trf; 896 struct stat st; 897 char *dirp, dir[512]; 898 899 dirp = bldpath(rf->file->path, "..", dir); 900 if(strlen(dirp) < sizeof dir){ /* ugly: avoid leaving dirp allocated */ 901 strcpy(dir, dirp); 902 free(dirp); 903 dirp = dir; 904 } 905 if(stat(dirp, &st) < 0) 906 errjmp(Eperm); 907 trf.uid = rf->uid; 908 trf.gid = rf->gid; 909 perm(&trf, 2, &st); 910 } 911 912 File* 913 newfile(void) 914 { 915 File *f; 916 917 f = erealloc(0, sizeof(File)); 918 memset(f, 0, sizeof(File)); 919 f->ref = 1; 920 return f; 921 } 922 923 /* 924 * qids: directory bit, seven bits of device, 24 bits of inode 925 */ 926 Ulong 927 vers(struct stat *st) 928 { 929 return st->st_mtime; 930 } 931 932 Ulong 933 qid(struct stat *st) 934 { 935 static int nqdev; 936 static Uchar *qdev; 937 Ulong q; 938 int dev; 939 940 if(qdev == 0){ 941 qdev = erealloc(0, 65536U); 942 memset(qdev, 0, 65536U); 943 } 944 q = 0; 945 if((st->st_mode&S_IFMT) == S_IFDIR) 946 q = CHDIR; 947 dev = st->st_dev & 0xFFFFUL; 948 if(qdev[dev] == 0){ 949 if(++nqdev >= 128) 950 error("too many devices"); 951 qdev[dev] = nqdev; 952 } 953 q |= qdev[dev]<<24; 954 q |= st->st_ino & 0x00FFFFFFUL; 955 return q; 956 } 957 958 Pass* 959 name2pass(Pass **pw, char *name) 960 { 961 int i; 962 Pass *p; 963 964 for(i=0; i<256; i++) 965 for(p = pw[i]; p; p = p->next) 966 if(strcmp(name, p->name) == 0) 967 return p; 968 return 0; 969 } 970 971 char* 972 id2name(Pass **pw, int id) 973 { 974 int i; 975 Pass *p; 976 char *s; 977 static char buf[8]; 978 979 s = 0; 980 /* use last on list == first in file */ 981 i = (id&0xFF) ^ ((id>>8)&0xFF); 982 for(p = pw[i]; p; p = p->next) 983 if(p->id == id) 984 s = p->name; 985 if(s) 986 return s; 987 sprintf(buf, "%d", id); 988 return buf; 989 } 990 991 void 992 freepass(Pass **pass) 993 { 994 int i; 995 Pass *p, *np; 996 997 for(i=0; i<256; i++){ 998 for(p = pass[i]; p; p = np){ 999 np = p->next; 1000 free(p); 1001 } 1002 pass[i] = 0; 1003 } 1004 } 1005 1006 void 1007 getpwdf(void) 1008 { 1009 static mtime; 1010 struct stat stbuf; 1011 struct passwd *pw; 1012 int i; 1013 Pass *p; 1014 1015 if(stat("/etc/passwd", &stbuf) < 0) 1016 error("can't read /etc/passwd"); 1017 if(stbuf.st_mtime <= mtime) 1018 return; 1019 freepass(uid); 1020 while(pw = getpwent()){ 1021 i = pw->pw_uid; 1022 i = (i&0xFF) ^ ((i>>8)&0xFF); 1023 p = erealloc(0, sizeof(Pass)); 1024 p->next = uid[i]; 1025 uid[i] = p; 1026 p->id = pw->pw_uid; 1027 p->gid = pw->pw_gid; 1028 p->name = estrdup(pw->pw_name); 1029 } 1030 setpwent(); 1031 endpwent(); 1032 } 1033 1034 void 1035 getgrpf(void) 1036 { 1037 static mtime; 1038 struct stat stbuf; 1039 struct group *pw; 1040 int i; 1041 Pass *p; 1042 1043 if(stat("/etc/group", &stbuf) < 0) 1044 error("can't read /etc/group"); 1045 if(stbuf.st_mtime <= mtime) 1046 return; 1047 freepass(gid); 1048 while(pw = getgrent()){ 1049 i = pw->gr_gid; 1050 i = (i&0xFF) ^ ((i>>8)&0xFF); 1051 p = erealloc(0, sizeof(Pass)); 1052 p->next = gid[i]; 1053 gid[i] = p; 1054 p->id = pw->gr_gid; 1055 p->gid = 0; 1056 p->name = estrdup(pw->gr_name); 1057 } 1058 setgrent(); 1059 endgrent(); 1060 } 1061 1062 void 1063 error(char *s) 1064 { 1065 fprintf(stderr, "u9fs: %s\n", s); 1066 perror("unix error"); 1067 exit(1); 1068 } 1069 1070 void 1071 errjmp(char *s) 1072 { 1073 if(s == 0) 1074 return; 1075 sendmsg(s); 1076 longjmp(loopjmp, 1); 1077 } 1078 1079 void* 1080 erealloc(void *p, unsigned n) 1081 { 1082 if(p == 0) 1083 p = malloc(n); 1084 else 1085 p = realloc(p, n); 1086 if(p == 0) 1087 error("realloc fail"); 1088 return p; 1089 } 1090 1091 char* 1092 estrdup(char *p) 1093 { 1094 p = strdup(p); 1095 if(p == 0) 1096 error("strdup fail"); 1097 return p; 1098 } 1099 1100 #ifdef SOCKETS 1101 void 1102 remotehostname(void) 1103 { 1104 struct sockaddr_in sock; 1105 struct hostent *hp; 1106 int len; 1107 int on = 1; 1108 1109 len = sizeof sock; 1110 if(getpeername(0, &sock, &len) < 0) 1111 error("getpeername"); 1112 hp = gethostbyaddr((char *)&sock.sin_addr, sizeof (struct in_addr), 1113 sock.sin_family); 1114 if(hp == 0) 1115 error("gethostbyaddr"); 1116 strcpy(bsdhost, hp->h_name); 1117 fprintf(stderr, "bsdhost %s on %d\n", bsdhost, getpid()); 1118 1119 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); 1120 } 1121 #endif 1122