1 /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */ 2 /* plan9.h is first to get the large file support definitions as early as possible */ 3 #include <plan9.h> 4 #include <sys/stat.h> /* for stat, umask */ 5 #include <stdlib.h> /* for malloc */ 6 #include <string.h> /* for strcpy, memmove */ 7 #include <pwd.h> /* for getpwnam, getpwuid */ 8 #include <grp.h> /* for getgrnam, getgrgid */ 9 #include <unistd.h> /* for gethostname, pread, pwrite, read, write */ 10 #include <utime.h> /* for utime */ 11 #include <dirent.h> /* for readdir */ 12 #include <errno.h> /* for errno */ 13 #include <stdio.h> /* for remove [sic] */ 14 #include <fcntl.h> /* for O_RDONLY, etc. */ 15 16 #include <sys/socket.h> /* various networking crud */ 17 #include <netinet/in.h> 18 #include <netdb.h> 19 20 #include <fcall.h> 21 #include <oldfcall.h> 22 #include <u9fs.h> 23 24 /* #ifndef because can be given in makefile */ 25 #ifndef DEFAULTLOG 26 #define DEFAULTLOG "/tmp/u9fs.log" 27 #endif 28 29 char *logfile = DEFAULTLOG; 30 31 #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m)) 32 33 enum { 34 Tdot = 1, 35 Tdotdot 36 }; 37 38 enum { 39 P9P1, 40 P9P2000 41 }; 42 43 typedef struct User User; 44 struct User { 45 int id; 46 gid_t defaultgid; 47 char *name; 48 char **mem; /* group members */ 49 int nmem; 50 User *next; 51 }; 52 53 struct Fid { 54 int fid; 55 char *path; 56 struct stat st; 57 User *u; 58 int omode; 59 DIR *dir; 60 int diroffset; 61 int fd; 62 struct dirent *dirent; 63 int direof; 64 Fid *next; 65 Fid *prev; 66 int auth; 67 void *authmagic; 68 }; 69 70 void* emalloc(size_t); 71 void* erealloc(void*, size_t); 72 char* estrdup(char*); 73 char* estrpath(char*, char*, int); 74 void sysfatal(char*, ...); 75 int okuser(char*); 76 77 void rversion(Fcall*, Fcall*); 78 void rauth(Fcall*, Fcall*); 79 void rattach(Fcall*, Fcall*); 80 void rflush(Fcall*, Fcall*); 81 void rclone(Fcall*, Fcall*); 82 void rwalk(Fcall*, Fcall*); 83 void ropen(Fcall*, Fcall*); 84 void rcreate(Fcall*, Fcall*); 85 void rread(Fcall*, Fcall*); 86 void rwrite(Fcall*, Fcall*); 87 void rclunk(Fcall*, Fcall*); 88 void rstat(Fcall*, Fcall*); 89 void rwstat(Fcall*, Fcall*); 90 void rclwalk(Fcall*, Fcall*); 91 void rremove(Fcall*, Fcall*); 92 93 User* uname2user(char*); 94 User* gname2user(char*); 95 User* uid2user(int); 96 User* gid2user(int); 97 98 Fid* newfid(int, char**); 99 Fid* oldfidex(int, int, char**); 100 Fid* oldfid(int, char**); 101 int fidstat(Fid*, char**); 102 void freefid(Fid*); 103 104 int userchange(User*, char**); 105 int userwalk(User*, char**, char*, Qid*, char**); 106 int useropen(Fid*, int, char**); 107 int usercreate(Fid*, char*, int, long, char**); 108 int userremove(Fid*, char**); 109 int userperm(User*, char*, int, int); 110 int useringroup(User*, User*); 111 112 Qid stat2qid(struct stat*); 113 114 void getfcallold(int, Fcall*, int); 115 void putfcallold(int, Fcall*); 116 117 char Eauth[] = "authentication failed"; 118 char Ebadfid[] = "fid unknown or out of range"; 119 char Ebadoffset[] = "bad offset in directory read"; 120 char Ebadusefid[] = "bad use of fid"; 121 char Edirchange[] = "wstat can't convert between files and directories"; 122 char Eexist[] = "file or directory already exists"; 123 char Efidactive[] = "fid already in use"; 124 char Enotdir[] = "not a directory"; 125 char Enotingroup[] = "not a member of proposed group"; 126 char Enotowner[] = "only owner can change group in wstat"; 127 char Eperm[] = "permission denied"; 128 char Especial0[] = "already attached without access to special files"; 129 char Especial1[] = "already attached with access to special files"; 130 char Especial[] = "no access to special file"; 131 char Etoolarge[] = "i/o count too large"; 132 char Eunknowngroup[] = "unknown group"; 133 char Eunknownuser[] = "unknown user"; 134 char Ewstatbuffer[] = "bogus wstat buffer"; 135 136 ulong msize = IOHDRSZ+8192; 137 uchar* rxbuf; 138 uchar* txbuf; 139 void* databuf; 140 int connected; 141 int devallowed; 142 char* autharg; 143 char* defaultuser; 144 char hostname[256]; 145 char remotehostname[256]; 146 int chatty9p = 0; 147 int network = 1; 148 int old9p = -1; 149 int authed; 150 User* none; 151 152 Auth *authmethods[] = { /* first is default */ 153 &authrhosts, 154 &authp9any, 155 &authnone, 156 }; 157 158 Auth *auth; 159 160 /* 161 * frogs: characters not valid in plan9 162 * filenames, keep this list in sync with 163 * /sys/src/9/port/chan.c:1656 164 */ 165 char isfrog[256]={ 166 /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, 167 /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, 168 /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, 169 /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, 170 ['/'] 1, 171 [0x7f] 1, 172 }; 173 174 void 175 getfcallnew(int fd, Fcall *fc, int have) 176 { 177 int len; 178 179 if(have > BIT32SZ) 180 sysfatal("cannot happen"); 181 182 if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) 183 sysfatal("couldn't read message"); 184 185 len = GBIT32(rxbuf); 186 if(len <= BIT32SZ) 187 sysfatal("bogus message"); 188 189 len -= BIT32SZ; 190 if(readn(fd, rxbuf+BIT32SZ, len) != len) 191 sysfatal("short message"); 192 193 if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) 194 sysfatal("badly sized message type %d", rxbuf[0]); 195 } 196 197 void 198 getfcallold(int fd, Fcall *fc, int have) 199 { 200 int len, n; 201 202 if(have > 3) 203 sysfatal("cannot happen"); 204 205 if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) 206 sysfatal("couldn't read message"); 207 208 len = oldhdrsize(rxbuf[0]); 209 if(len < 3) 210 sysfatal("bad message %d", rxbuf[0]); 211 if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) 212 sysfatal("couldn't read message"); 213 214 n = iosize(rxbuf); 215 if(readn(fd, rxbuf+len, n) != n) 216 sysfatal("couldn't read message"); 217 len += n; 218 219 if(convM2Sold(rxbuf, len, fc) != len) 220 sysfatal("badly sized message type %d", rxbuf[0]); 221 } 222 223 void 224 putfcallnew(int wfd, Fcall *tx) 225 { 226 uint n; 227 228 if((n = convS2M(tx, txbuf, msize)) == 0) 229 sysfatal("couldn't format message type %d", tx->type); 230 if(write(wfd, txbuf, n) != n) 231 sysfatal("couldn't send message"); 232 } 233 234 void 235 putfcallold(int wfd, Fcall *tx) 236 { 237 uint n; 238 239 if((n = convS2Mold(tx, txbuf, msize)) == 0) 240 sysfatal("couldn't format message type %d", tx->type); 241 if(write(wfd, txbuf, n) != n) 242 sysfatal("couldn't send message"); 243 } 244 245 void 246 getfcall(int fd, Fcall *fc) 247 { 248 if(old9p == 1){ 249 getfcallold(fd, fc, 0); 250 return; 251 } 252 if(old9p == 0){ 253 getfcallnew(fd, fc, 0); 254 return; 255 } 256 257 /* auto-detect */ 258 if(readn(fd, rxbuf, 3) != 3) 259 sysfatal("couldn't read message"); 260 261 /* is it an old (9P1) message? */ 262 if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ 263 old9p = 1; 264 getfcallold(fd, fc, 3); 265 return; 266 } 267 268 getfcallnew(fd, fc, 3); 269 old9p = 0; 270 } 271 272 void 273 seterror(Fcall *f, char *error) 274 { 275 f->type = Rerror; 276 f->ename = error ? error : "programmer error"; 277 } 278 279 int 280 isowner(User *u, Fid *f) 281 { 282 return u->id == f->st.st_uid; 283 } 284 285 286 287 void 288 serve(int rfd, int wfd) 289 { 290 Fcall rx, tx; 291 292 for(;;){ 293 getfcall(rfd, &rx); 294 295 if(chatty9p) 296 fprint(2, "<- %F\n", &rx); 297 298 memset(&tx, 0, sizeof tx); 299 tx.type = rx.type+1; 300 tx.tag = rx.tag; 301 switch(rx.type){ 302 case Tflush: 303 break; 304 case Tversion: 305 rversion(&rx, &tx); 306 break; 307 case Tauth: 308 rauth(&rx, &tx); 309 break; 310 case Tattach: 311 rattach(&rx, &tx); 312 break; 313 case Twalk: 314 rwalk(&rx, &tx); 315 break; 316 case Tstat: 317 tx.stat = databuf; 318 rstat(&rx, &tx); 319 break; 320 case Twstat: 321 rwstat(&rx, &tx); 322 break; 323 case Topen: 324 ropen(&rx, &tx); 325 break; 326 case Tcreate: 327 rcreate(&rx, &tx); 328 break; 329 case Tread: 330 tx.data = databuf; 331 rread(&rx, &tx); 332 break; 333 case Twrite: 334 rwrite(&rx, &tx); 335 break; 336 case Tclunk: 337 rclunk(&rx, &tx); 338 break; 339 case Tremove: 340 rremove(&rx, &tx); 341 break; 342 default: 343 fprint(2, "unknown message %F\n", &rx); 344 seterror(&tx, "bad message"); 345 break; 346 } 347 348 if(chatty9p) 349 fprint(2, "-> %F\n", &tx); 350 351 (old9p ? putfcallold : putfcallnew)(wfd, &tx); 352 } 353 } 354 355 void 356 rversion(Fcall *rx, Fcall *tx) 357 { 358 if(msize > rx->msize) 359 msize = rx->msize; 360 tx->msize = msize; 361 if(strncmp(rx->version, "9P", 2) != 0) 362 tx->version = "unknown"; 363 else 364 tx->version = "9P2000"; 365 } 366 367 void 368 rauth(Fcall *rx, Fcall *tx) 369 { 370 char *e; 371 372 if((e = auth->auth(rx, tx)) != nil) 373 seterror(tx, e); 374 } 375 376 void 377 rattach(Fcall *rx, Fcall *tx) 378 { 379 char *e; 380 Fid *fid; 381 User *u; 382 383 if(rx->aname == nil) 384 rx->aname = ""; 385 386 if(strcmp(rx->aname, "device") == 0){ 387 if(connected && !devallowed){ 388 seterror(tx, Especial0); 389 return; 390 } 391 devallowed = 1; 392 }else{ 393 if(connected && devallowed){ 394 seterror(tx, Especial1); 395 return; 396 } 397 } 398 399 if(strcmp(rx->uname, "none") == 0){ 400 if(authed == 0){ 401 seterror(tx, Eauth); 402 return; 403 } 404 } else { 405 if((e = auth->attach(rx, tx)) != nil){ 406 seterror(tx, e); 407 return; 408 } 409 authed++; 410 } 411 412 if((fid = newfid(rx->fid, &e)) == nil){ 413 seterror(tx, e); 414 return; 415 } 416 fid->path = estrdup("/"); 417 if(fidstat(fid, &e) < 0){ 418 seterror(tx, e); 419 freefid(fid); 420 return; 421 } 422 423 if(defaultuser) 424 rx->uname = defaultuser; 425 426 if((u = uname2user(rx->uname)) == nil 427 || (!defaultuser && u->id == 0)){ 428 /* we don't know anyone named root... */ 429 seterror(tx, Eunknownuser); 430 freefid(fid); 431 return; 432 } 433 434 fid->u = u; 435 tx->qid = stat2qid(&fid->st); 436 return; 437 } 438 439 void 440 rwalk(Fcall *rx, Fcall *tx) 441 { 442 int i; 443 char *path, *e; 444 Fid *fid, *nfid; 445 446 e = nil; 447 if((fid = oldfid(rx->fid, &e)) == nil){ 448 seterror(tx, e); 449 return; 450 } 451 452 if(fid->omode != -1){ 453 seterror(tx, Ebadusefid); 454 return; 455 } 456 457 if(fidstat(fid, &e) < 0){ 458 seterror(tx, e); 459 return; 460 } 461 462 if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ 463 seterror(tx, Enotdir); 464 return; 465 } 466 467 nfid = nil; 468 if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ 469 seterror(tx, e); 470 return; 471 } 472 473 path = estrdup(fid->path); 474 e = nil; 475 for(i=0; i<rx->nwname; i++) 476 if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) 477 break; 478 479 if(i == rx->nwname){ /* successful clone or walk */ 480 tx->nwqid = i; 481 if(nfid){ 482 nfid->path = path; 483 nfid->u = fid->u; 484 }else{ 485 free(fid->path); 486 fid->path = path; 487 } 488 }else{ 489 if(i > 0) /* partial walk? */ 490 tx->nwqid = i; 491 else 492 seterror(tx, e); 493 494 if(nfid) /* clone implicit new fid */ 495 freefid(nfid); 496 free(path); 497 } 498 return; 499 } 500 501 void 502 ropen(Fcall *rx, Fcall *tx) 503 { 504 char *e; 505 Fid *fid; 506 507 if((fid = oldfid(rx->fid, &e)) == nil){ 508 seterror(tx, e); 509 return; 510 } 511 512 if(fid->omode != -1){ 513 seterror(tx, Ebadusefid); 514 return; 515 } 516 517 if(fidstat(fid, &e) < 0){ 518 seterror(tx, e); 519 return; 520 } 521 522 if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ 523 seterror(tx, Especial); 524 return; 525 } 526 527 if(useropen(fid, rx->mode, &e) < 0){ 528 seterror(tx, e); 529 return; 530 } 531 532 tx->iounit = 0; 533 tx->qid = stat2qid(&fid->st); 534 } 535 536 void 537 rcreate(Fcall *rx, Fcall *tx) 538 { 539 char *e; 540 Fid *fid; 541 542 if((fid = oldfid(rx->fid, &e)) == nil){ 543 seterror(tx, e); 544 return; 545 } 546 547 if(fid->omode != -1){ 548 seterror(tx, Ebadusefid); 549 return; 550 } 551 552 if(fidstat(fid, &e) < 0){ 553 seterror(tx, e); 554 return; 555 } 556 557 if(!S_ISDIR(fid->st.st_mode)){ 558 seterror(tx, Enotdir); 559 return; 560 } 561 562 if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ 563 seterror(tx, e); 564 return; 565 } 566 567 if(fidstat(fid, &e) < 0){ 568 seterror(tx, e); 569 return; 570 } 571 572 tx->iounit = 0; 573 tx->qid = stat2qid(&fid->st); 574 } 575 576 uchar 577 modebyte(struct stat *st) 578 { 579 uchar b; 580 581 b = 0; 582 583 if(S_ISDIR(st->st_mode)) 584 b |= QTDIR; 585 586 /* no way to test append-only */ 587 /* no real way to test exclusive use, but mark devices as such */ 588 if(S_ISSPECIAL(st->st_mode)) 589 b |= QTEXCL; 590 591 return b; 592 } 593 594 ulong 595 plan9mode(struct stat *st) 596 { 597 return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777); 598 } 599 600 /* 601 * this is for chmod, so don't worry about S_IFDIR 602 */ 603 mode_t 604 unixmode(Dir *d) 605 { 606 return (mode_t)(d->mode&0777); 607 } 608 609 Qid 610 stat2qid(struct stat *st) 611 { 612 uchar *p, *ep, *q; 613 Qid qid; 614 615 /* 616 * For now, ignore the device number. 617 */ 618 qid.path = 0; 619 p = (uchar*)&qid.path; 620 ep = p+sizeof(qid.path); 621 q = p+sizeof(ino_t); 622 if(q > ep){ 623 fprint(2, "warning: inode number too big\n"); 624 q = ep; 625 } 626 memmove(p, &st->st_ino, q-p); 627 q = q+sizeof(dev_t); 628 if(q > ep){ 629 /* 630 * fprint(2, "warning: inode number + device number too big %d+%d\n", 631 * sizeof(ino_t), sizeof(dev_t)); 632 */ 633 q = ep - sizeof(dev_t); 634 if(q < p) 635 fprint(2, "warning: device number too big by itself\n"); 636 else 637 *(dev_t*)q ^= st->st_dev; 638 } 639 640 qid.vers = st->st_mtime ^ (st->st_size << 8); 641 qid.type = modebyte(st); 642 return qid; 643 } 644 645 char * 646 enfrog(char *src) 647 { 648 char *d, *dst; 649 uchar *s; 650 651 d = dst = emalloc(strlen(src)*3 + 1); 652 for (s = (uchar *)src; *s; s++) 653 if(isfrog[*s] || *s == '\\') 654 d += sprintf(d, "\\%02x", *s); 655 else 656 *d++ = *s; 657 *d = 0; 658 return dst; 659 } 660 661 char * 662 defrog(char *s) 663 { 664 char *d, *dst, buf[3]; 665 666 d = dst = emalloc(strlen(s) + 1); 667 for(; *s; s++) 668 if(*s == '\\' && strlen(s) >= 3){ 669 buf[0] = *++s; /* skip \ */ 670 buf[1] = *++s; 671 buf[2] = 0; 672 *d++ = strtoul(buf, NULL, 16); 673 } else 674 *d++ = *s; 675 *d = 0; 676 return dst; 677 } 678 679 void 680 stat2dir(char *path, struct stat *st, Dir *d) 681 { 682 User *u; 683 char *q, *p, *npath; 684 685 memset(d, 0, sizeof(*d)); 686 d->qid = stat2qid(st); 687 d->mode = plan9mode(st); 688 d->atime = st->st_atime; 689 d->mtime = st->st_mtime; 690 d->length = st->st_size; 691 692 d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; 693 d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; 694 d->muid = ""; 695 696 if((q = strrchr(path, '/')) != nil) 697 d->name = enfrog(q+1); 698 else 699 d->name = enfrog(path); 700 } 701 702 void 703 rread(Fcall *rx, Fcall *tx) 704 { 705 char *e, *path; 706 uchar *p, *ep; 707 int n; 708 Fid *fid; 709 Dir d; 710 struct stat st; 711 712 if(rx->count > msize-IOHDRSZ){ 713 seterror(tx, Etoolarge); 714 return; 715 } 716 717 if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 718 seterror(tx, e); 719 return; 720 } 721 722 if (fid->auth) { 723 char *e; 724 e = auth->read(rx, tx); 725 if (e) 726 seterror(tx, e); 727 return; 728 } 729 730 if(fid->omode == -1 || (fid->omode&3) == OWRITE){ 731 seterror(tx, Ebadusefid); 732 return; 733 } 734 735 if(fid->dir){ 736 if(rx->offset != fid->diroffset){ 737 if(rx->offset != 0){ 738 seterror(tx, Ebadoffset); 739 return; 740 } 741 rewinddir(fid->dir); 742 fid->diroffset = 0; 743 fid->direof = 0; 744 } 745 if(fid->direof){ 746 tx->count = 0; 747 return; 748 } 749 750 p = (uchar*)tx->data; 751 ep = (uchar*)tx->data+rx->count; 752 for(;;){ 753 if(p+BIT16SZ >= ep) 754 break; 755 if(fid->dirent == nil) /* one entry cache for when convD2M fails */ 756 if((fid->dirent = readdir(fid->dir)) == nil){ 757 fid->direof = 1; 758 break; 759 } 760 if(strcmp(fid->dirent->d_name, ".") == 0 761 || strcmp(fid->dirent->d_name, "..") == 0){ 762 fid->dirent = nil; 763 continue; 764 } 765 path = estrpath(fid->path, fid->dirent->d_name, 0); 766 memset(&st, 0, sizeof st); 767 if(stat(path, &st) < 0){ 768 fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); 769 fid->dirent = nil; 770 free(path); 771 continue; 772 } 773 free(path); 774 stat2dir(fid->dirent->d_name, &st, &d); 775 if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) 776 break; 777 p += n; 778 fid->dirent = nil; 779 } 780 tx->count = p - (uchar*)tx->data; 781 fid->diroffset += tx->count; 782 }else{ 783 if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ 784 seterror(tx, strerror(errno)); 785 return; 786 } 787 tx->count = n; 788 } 789 } 790 791 void 792 rwrite(Fcall *rx, Fcall *tx) 793 { 794 char *e; 795 Fid *fid; 796 int n; 797 798 if(rx->count > msize-IOHDRSZ){ 799 seterror(tx, Etoolarge); 800 return; 801 } 802 803 if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 804 seterror(tx, e); 805 return; 806 } 807 808 if (fid->auth) { 809 char *e; 810 e = auth->write(rx, tx); 811 if (e) 812 seterror(tx, e); 813 return; 814 } 815 816 if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ 817 seterror(tx, Ebadusefid); 818 return; 819 } 820 821 if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ 822 seterror(tx, strerror(errno)); 823 return; 824 } 825 tx->count = n; 826 } 827 828 void 829 rclunk(Fcall *rx, Fcall *tx) 830 { 831 char *e; 832 Fid *fid; 833 834 if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 835 seterror(tx, e); 836 return; 837 } 838 if (fid->auth) { 839 if (auth->clunk) { 840 e = (*auth->clunk)(rx, tx); 841 if (e) { 842 seterror(tx, e); 843 return; 844 } 845 } 846 } 847 else if(fid->omode != -1 && fid->omode&ORCLOSE) 848 remove(fid->path); 849 freefid(fid); 850 } 851 852 void 853 rremove(Fcall *rx, Fcall *tx) 854 { 855 char *e; 856 Fid *fid; 857 858 if((fid = oldfid(rx->fid, &e)) == nil){ 859 seterror(tx, e); 860 return; 861 } 862 if(userremove(fid, &e) < 0) 863 seterror(tx, e); 864 freefid(fid); 865 } 866 867 void 868 rstat(Fcall *rx, Fcall *tx) 869 { 870 char *e; 871 Fid *fid; 872 Dir d; 873 874 if((fid = oldfid(rx->fid, &e)) == nil){ 875 seterror(tx, e); 876 return; 877 } 878 879 if(fidstat(fid, &e) < 0){ 880 seterror(tx, e); 881 return; 882 } 883 884 stat2dir(fid->path, &fid->st, &d); 885 if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) 886 seterror(tx, "convD2M fails"); 887 } 888 889 void 890 rwstat(Fcall *rx, Fcall *tx) 891 { 892 char *e; 893 char *p, *old, *new, *dir; 894 gid_t gid; 895 Dir d; 896 Fid *fid; 897 898 if((fid = oldfid(rx->fid, &e)) == nil){ 899 seterror(tx, e); 900 return; 901 } 902 903 /* 904 * wstat is supposed to be atomic. 905 * we check all the things we can before trying anything. 906 * still, if we are told to truncate a file and rename it and only 907 * one works, we're screwed. in such cases we leave things 908 * half broken and return an error. it's hardly perfect. 909 */ 910 if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ 911 seterror(tx, Ewstatbuffer); 912 return; 913 } 914 915 if(fidstat(fid, &e) < 0){ 916 seterror(tx, e); 917 return; 918 } 919 920 /* 921 * The casting is necessary because d.mode is ulong and might, 922 * on some systems, be 64 bits. We only want to compare the 923 * bottom 32 bits, since that's all that gets sent in the protocol. 924 * 925 * Same situation for d.mtime and d.length (although that last check 926 * is admittedly superfluous, given the current lack of 128-bit machines). 927 */ 928 gid = (gid_t)-1; 929 if(d.gid[0] != '\0'){ 930 User *g; 931 932 g = gname2user(d.gid); 933 if(g == nil){ 934 seterror(tx, Eunknowngroup); 935 return; 936 } 937 gid = (gid_t)g->id; 938 939 if(groupchange(fid->u, gid2user(gid), &e) < 0){ 940 seterror(tx, e); 941 return; 942 } 943 } 944 945 if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ 946 seterror(tx, Edirchange); 947 return; 948 } 949 950 if(strcmp(fid->path, "/") == 0){ 951 seterror(tx, "no wstat of root"); 952 return; 953 } 954 955 /* 956 * try things in increasing order of harm to the file. 957 * mtime should come after truncate so that if you 958 * do both the mtime actually takes effect, but i'd rather 959 * leave truncate until last. 960 * (see above comment about atomicity). 961 */ 962 if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ 963 if(chatty9p) 964 fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); 965 seterror(tx, strerror(errno)); 966 return; 967 } 968 969 if((u32int)d.mtime != (u32int)~0){ 970 struct utimbuf t; 971 972 t.actime = 0; 973 t.modtime = d.mtime; 974 if(utime(fid->path, &t) < 0){ 975 if(chatty9p) 976 fprint(2, "utime(%s) failed\n", fid->path); 977 seterror(tx, strerror(errno)); 978 return; 979 } 980 } 981 982 if(gid != (gid_t)-1 && gid != fid->st.st_gid){ 983 if(chown(fid->path, (uid_t)-1, gid) < 0){ 984 if(chatty9p) 985 fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); 986 seterror(tx, strerror(errno)); 987 return; 988 } 989 } 990 991 if(d.name[0]){ 992 old = fid->path; 993 dir = estrdup(fid->path); 994 if((p = strrchr(dir, '/')) > dir) 995 *p = '\0'; 996 else{ 997 seterror(tx, "whoops: can't happen in u9fs"); 998 return; 999 } 1000 new = estrpath(dir, d.name, 1); 1001 if(strcmp(old, new) != 0 && rename(old, new) < 0){ 1002 if(chatty9p) 1003 fprint(2, "rename(%s, %s) failed\n", old, new); 1004 seterror(tx, strerror(errno)); 1005 free(new); 1006 free(dir); 1007 return; 1008 } 1009 fid->path = new; 1010 free(old); 1011 free(dir); 1012 } 1013 1014 if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ 1015 fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); 1016 seterror(tx, strerror(errno)); 1017 return; 1018 } 1019 } 1020 1021 /* 1022 * we keep a table by numeric id. by name lookups happen infrequently 1023 * while by-number lookups happen once for every directory entry read 1024 * and every stat request. 1025 */ 1026 User *utab[64]; 1027 User *gtab[64]; 1028 1029 User* 1030 adduser(struct passwd *p) 1031 { 1032 User *u; 1033 1034 u = emalloc(sizeof(*u)); 1035 u->id = p->pw_uid; 1036 u->name = estrdup(p->pw_name); 1037 u->next = utab[p->pw_uid%nelem(utab)]; 1038 u->defaultgid = p->pw_gid; 1039 utab[p->pw_uid%nelem(utab)] = u; 1040 return u; 1041 } 1042 1043 int 1044 useringroup(User *u, User *g) 1045 { 1046 int i; 1047 1048 for(i=0; i<g->nmem; i++) 1049 if(strcmp(g->mem[i], u->name) == 0) 1050 return 1; 1051 1052 /* 1053 * Hack around common Unix problem that everyone has 1054 * default group "user" but /etc/group lists no members. 1055 */ 1056 if(u->defaultgid == g->id) 1057 return 1; 1058 return 0; 1059 } 1060 1061 User* 1062 addgroup(struct group *g) 1063 { 1064 User *u; 1065 char **p; 1066 int n; 1067 1068 u = emalloc(sizeof(*u)); 1069 n = 0; 1070 for(p=g->gr_mem; *p; p++) 1071 n++; 1072 u->mem = emalloc(sizeof(u->mem[0])*n); 1073 n = 0; 1074 for(p=g->gr_mem; *p; p++) 1075 u->mem[n++] = estrdup(*p); 1076 u->nmem = n; 1077 u->id = g->gr_gid; 1078 u->name = estrdup(g->gr_name); 1079 u->next = gtab[g->gr_gid%nelem(gtab)]; 1080 gtab[g->gr_gid%nelem(gtab)] = u; 1081 return u; 1082 } 1083 1084 User* 1085 uname2user(char *name) 1086 { 1087 int i; 1088 User *u; 1089 struct passwd *p; 1090 1091 for(i=0; i<nelem(utab); i++) 1092 for(u=utab[i]; u; u=u->next) 1093 if(strcmp(u->name, name) == 0) 1094 return u; 1095 1096 if((p = getpwnam(name)) == nil) 1097 return nil; 1098 return adduser(p); 1099 } 1100 1101 User* 1102 uid2user(int id) 1103 { 1104 User *u; 1105 struct passwd *p; 1106 1107 for(u=utab[id%nelem(utab)]; u; u=u->next) 1108 if(u->id == id) 1109 return u; 1110 1111 if((p = getpwuid(id)) == nil) 1112 return nil; 1113 return adduser(p); 1114 } 1115 1116 User* 1117 gname2user(char *name) 1118 { 1119 int i; 1120 User *u; 1121 struct group *g; 1122 1123 for(i=0; i<nelem(gtab); i++) 1124 for(u=gtab[i]; u; u=u->next) 1125 if(strcmp(u->name, name) == 0) 1126 return u; 1127 1128 if((g = getgrnam(name)) == nil) 1129 return nil; 1130 return addgroup(g); 1131 } 1132 1133 User* 1134 gid2user(int id) 1135 { 1136 User *u; 1137 struct group *g; 1138 1139 for(u=gtab[id%nelem(gtab)]; u; u=u->next) 1140 if(u->id == id) 1141 return u; 1142 1143 if((g = getgrgid(id)) == nil) 1144 return nil; 1145 return addgroup(g); 1146 } 1147 1148 void 1149 sysfatal(char *fmt, ...) 1150 { 1151 char buf[1024]; 1152 va_list va, temp; 1153 1154 va_start(va, fmt); 1155 va_copy(temp, va); 1156 doprint(buf, buf+sizeof buf, fmt, &temp); 1157 va_end(temp); 1158 va_end(va); 1159 fprint(2, "u9fs: %s\n", buf); 1160 fprint(2, "last unix error: %s\n", strerror(errno)); 1161 exit(1); 1162 } 1163 1164 void* 1165 emalloc(size_t n) 1166 { 1167 void *p; 1168 1169 if(n == 0) 1170 n = 1; 1171 p = malloc(n); 1172 if(p == 0) 1173 sysfatal("malloc(%ld) fails", (long)n); 1174 memset(p, 0, n); 1175 return p; 1176 } 1177 1178 void* 1179 erealloc(void *p, size_t n) 1180 { 1181 if(p == 0) 1182 p = malloc(n); 1183 else 1184 p = realloc(p, n); 1185 if(p == 0) 1186 sysfatal("realloc(..., %ld) fails", (long)n); 1187 return p; 1188 } 1189 1190 char* 1191 estrdup(char *p) 1192 { 1193 p = strdup(p); 1194 if(p == 0) 1195 sysfatal("strdup(%.20s) fails", p); 1196 return p; 1197 } 1198 1199 char* 1200 estrpath(char *p, char *q, int frog) 1201 { 1202 char *r, *s; 1203 1204 if(strcmp(q, "..") == 0){ 1205 r = estrdup(p); 1206 if((s = strrchr(r, '/')) && s > r) 1207 *s = '\0'; 1208 else if(s == r) 1209 s[1] = '\0'; 1210 return r; 1211 } 1212 1213 if(frog) 1214 q = defrog(q); 1215 else 1216 q = strdup(q); 1217 r = emalloc(strlen(p)+1+strlen(q)+1); 1218 strcpy(r, p); 1219 if(r[0]=='\0' || r[strlen(r)-1] != '/') 1220 strcat(r, "/"); 1221 strcat(r, q); 1222 free(q); 1223 return r; 1224 } 1225 1226 Fid *fidtab[1]; 1227 1228 Fid* 1229 lookupfid(int fid) 1230 { 1231 Fid *f; 1232 1233 for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 1234 if(f->fid == fid) 1235 return f; 1236 return nil; 1237 } 1238 1239 Fid* 1240 newfid(int fid, char **ep) 1241 { 1242 Fid *f; 1243 1244 if(lookupfid(fid) != nil){ 1245 *ep = Efidactive; 1246 return nil; 1247 } 1248 1249 f = emalloc(sizeof(*f)); 1250 f->next = fidtab[fid%nelem(fidtab)]; 1251 if(f->next) 1252 f->next->prev = f; 1253 fidtab[fid%nelem(fidtab)] = f; 1254 f->fid = fid; 1255 f->fd = -1; 1256 f->omode = -1; 1257 return f; 1258 } 1259 1260 Fid* 1261 newauthfid(int fid, void *magic, char **ep) 1262 { 1263 Fid *af; 1264 af = newfid(fid, ep); 1265 if (af == nil) 1266 return nil; 1267 af->auth = 1; 1268 af->authmagic = magic; 1269 return af; 1270 } 1271 1272 Fid* 1273 oldfidex(int fid, int auth, char **ep) 1274 { 1275 Fid *f; 1276 1277 if((f = lookupfid(fid)) == nil){ 1278 *ep = Ebadfid; 1279 return nil; 1280 } 1281 1282 if (auth != -1 && f->auth != auth) { 1283 *ep = Ebadfid; 1284 return nil; 1285 } 1286 1287 if (!f->auth) { 1288 if(userchange(f->u, ep) < 0) 1289 return nil; 1290 } 1291 1292 return f; 1293 } 1294 1295 Fid* 1296 oldfid(int fid, char **ep) 1297 { 1298 return oldfidex(fid, 0, ep); 1299 } 1300 1301 Fid* 1302 oldauthfid(int fid, void **magic, char **ep) 1303 { 1304 Fid *af; 1305 af = oldfidex(fid, 1, ep); 1306 if (af == nil) 1307 return nil; 1308 *magic = af->authmagic; 1309 return af; 1310 } 1311 1312 void 1313 freefid(Fid *f) 1314 { 1315 if(f->prev) 1316 f->prev->next = f->next; 1317 else 1318 fidtab[f->fid%nelem(fidtab)] = f->next; 1319 if(f->next) 1320 f->next->prev = f->prev; 1321 if(f->dir) 1322 closedir(f->dir); 1323 if(f->fd) 1324 close(f->fd); 1325 free(f->path); 1326 free(f); 1327 } 1328 1329 int 1330 fidstat(Fid *fid, char **ep) 1331 { 1332 if(stat(fid->path, &fid->st) < 0){ 1333 fprint(2, "fidstat(%s) failed\n", fid->path); 1334 if(ep) 1335 *ep = strerror(errno); 1336 return -1; 1337 } 1338 if(S_ISDIR(fid->st.st_mode)) 1339 fid->st.st_size = 0; 1340 return 0; 1341 } 1342 1343 int 1344 userchange(User *u, char **ep) 1345 { 1346 if(defaultuser) 1347 return 0; 1348 1349 if(setreuid(0, 0) < 0){ 1350 fprint(2, "setreuid(0, 0) failed\n"); 1351 *ep = "cannot setuid back to root"; 1352 return -1; 1353 } 1354 1355 /* 1356 * Initgroups does not appear to be SUSV standard. 1357 * But it exists on SGI and on Linux, which makes me 1358 * think it's standard enough. We have to do something 1359 * like this, and the closest other function I can find is 1360 * setgroups (which initgroups eventually calls). 1361 * Setgroups is the same as far as standardization though, 1362 * so we're stuck using a non-SUSV call. Sigh. 1363 */ 1364 if(initgroups(u->name, u->defaultgid) < 0) 1365 fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 1366 1367 if(setreuid(-1, u->id) < 0){ 1368 fprint(2, "setreuid(-1, %s) failed\n", u->name); 1369 *ep = strerror(errno); 1370 return -1; 1371 } 1372 1373 return 0; 1374 } 1375 1376 /* 1377 * We do our own checking here, then switch to root temporarily 1378 * to set our gid. In a perfect world, you'd be allowed to set your 1379 * egid to any of the supplemental groups of your euid, but this 1380 * is not the case on Linux 2.2.14 (and perhaps others). 1381 * 1382 * This is a race, of course, but it's a race against processes 1383 * that can edit the group lists. If you can do that, you can 1384 * change your own group without our help. 1385 */ 1386 int 1387 groupchange(User *u, User *g, char **ep) 1388 { 1389 if(g == nil) 1390 return -1; 1391 if(!useringroup(u, g)){ 1392 if(chatty9p) 1393 fprint(2, "%s not in group %s\n", u->name, g->name); 1394 *ep = Enotingroup; 1395 return -1; 1396 } 1397 1398 setreuid(0,0); 1399 if(setregid(-1, g->id) < 0){ 1400 fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 1401 *ep = strerror(errno); 1402 return -1; 1403 } 1404 if(userchange(u, ep) < 0) 1405 return -1; 1406 1407 return 0; 1408 } 1409 1410 1411 /* 1412 * An attempt to enforce permissions by looking at the 1413 * file system. Separation of checking permission and 1414 * actually performing the action is a terrible idea, of 1415 * course, so we use setreuid for most of the permission 1416 * enforcement. This is here only so we can give errors 1417 * on open(ORCLOSE) in some cases. 1418 */ 1419 int 1420 userperm(User *u, char *path, int type, int need) 1421 { 1422 char *p, *q; 1423 int i, have; 1424 struct stat st; 1425 User *g; 1426 1427 switch(type){ 1428 default: 1429 fprint(2, "bad type %d in userperm\n", type); 1430 return -1; 1431 case Tdot: 1432 if(stat(path, &st) < 0){ 1433 fprint(2, "userperm: stat(%s) failed\n", path); 1434 return -1; 1435 } 1436 break; 1437 case Tdotdot: 1438 p = estrdup(path); 1439 if((q = strrchr(p, '/'))==nil){ 1440 fprint(2, "userperm(%s, ..): bad path\n", p); 1441 free(p); 1442 return -1; 1443 } 1444 if(q > p) 1445 *q = '\0'; 1446 else 1447 *(q+1) = '\0'; 1448 if(stat(p, &st) < 0){ 1449 fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 1450 p, path); 1451 free(p); 1452 return -1; 1453 } 1454 free(p); 1455 break; 1456 } 1457 1458 if(u == none){ 1459 fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 1460 have = st.st_mode&7; 1461 if((have&need)==need) 1462 return 0; 1463 return -1; 1464 } 1465 have = st.st_mode&7; 1466 if((uid_t)u->id == st.st_uid) 1467 have |= (st.st_mode>>6)&7; 1468 if((have&need)==need) 1469 return 0; 1470 if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 1471 return -1; 1472 g = gid2user(st.st_gid); 1473 for(i=0; i<g->nmem; i++){ 1474 if(strcmp(g->mem[i], u->name) == 0){ 1475 have |= (st.st_mode>>3)&7; 1476 break; 1477 } 1478 } 1479 if((have&need)==need) 1480 return 0; 1481 return -1; 1482 } 1483 1484 int 1485 userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 1486 { 1487 char *npath; 1488 struct stat st; 1489 1490 npath = estrpath(*path, elem, 1); 1491 if(stat(npath, &st) < 0){ 1492 free(npath); 1493 *ep = strerror(errno); 1494 return -1; 1495 } 1496 *qid = stat2qid(&st); 1497 free(*path); 1498 *path = npath; 1499 return 0; 1500 } 1501 1502 int 1503 useropen(Fid *fid, int omode, char **ep) 1504 { 1505 int a, o; 1506 1507 /* 1508 * Check this anyway, to try to head off problems later. 1509 */ 1510 if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 1511 *ep = Eperm; 1512 return -1; 1513 } 1514 1515 switch(omode&3){ 1516 default: 1517 *ep = "programmer error"; 1518 return -1; 1519 case OREAD: 1520 a = R_OK; 1521 o = O_RDONLY; 1522 break; 1523 case ORDWR: 1524 a = R_OK|W_OK; 1525 o = O_RDWR; 1526 break; 1527 case OWRITE: 1528 a = W_OK; 1529 o = O_WRONLY; 1530 break; 1531 case OEXEC: 1532 a = X_OK; 1533 o = O_RDONLY; 1534 break; 1535 } 1536 if(omode & OTRUNC){ 1537 a |= W_OK; 1538 o |= O_TRUNC; 1539 } 1540 1541 if(S_ISDIR(fid->st.st_mode)){ 1542 if(a != R_OK){ 1543 fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 1544 *ep = Eperm; 1545 return -1; 1546 } 1547 if((fid->dir = opendir(fid->path)) == nil){ 1548 *ep = strerror(errno); 1549 return -1; 1550 } 1551 }else{ 1552 /* 1553 * This is wrong because access used the real uid 1554 * and not the effective uid. Let the open sort it out. 1555 * 1556 if(access(fid->path, a) < 0){ 1557 *ep = strerror(errno); 1558 return -1; 1559 } 1560 * 1561 */ 1562 if((fid->fd = open(fid->path, o)) < 0){ 1563 *ep = strerror(errno); 1564 return -1; 1565 } 1566 } 1567 fid->omode = omode; 1568 return 0; 1569 } 1570 1571 int 1572 usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 1573 { 1574 int o, m; 1575 char *opath, *npath; 1576 struct stat st, parent; 1577 1578 if(stat(fid->path, &parent) < 0){ 1579 *ep = strerror(errno); 1580 return -1; 1581 } 1582 1583 /* 1584 * Change group so that created file has expected group 1585 * by Plan 9 semantics. If that fails, might as well go 1586 * with the user's default group. 1587 */ 1588 if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 1589 && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 1590 return -1; 1591 1592 m = (perm & DMDIR) ? 0777 : 0666; 1593 perm = perm & (~m | (fid->st.st_mode & m)); 1594 1595 npath = estrpath(fid->path, elem, 1); 1596 if(perm & DMDIR){ 1597 if((omode&~ORCLOSE) != OREAD){ 1598 *ep = Eperm; 1599 free(npath); 1600 return -1; 1601 } 1602 if(stat(npath, &st) >= 0 || errno != ENOENT){ 1603 *ep = Eexist; 1604 free(npath); 1605 return -1; 1606 } 1607 /* race */ 1608 if(mkdir(npath, perm&0777) < 0){ 1609 *ep = strerror(errno); 1610 free(npath); 1611 return -1; 1612 } 1613 if((fid->dir = opendir(npath)) == nil){ 1614 *ep = strerror(errno); 1615 remove(npath); /* race */ 1616 free(npath); 1617 return -1; 1618 } 1619 }else{ 1620 o = O_CREAT|O_EXCL; 1621 switch(omode&3){ 1622 default: 1623 *ep = "programmer error"; 1624 return -1; 1625 case OREAD: 1626 case OEXEC: 1627 o |= O_RDONLY; 1628 break; 1629 case ORDWR: 1630 o |= O_RDWR; 1631 break; 1632 case OWRITE: 1633 o |= O_WRONLY; 1634 break; 1635 } 1636 if(omode & OTRUNC) 1637 o |= O_TRUNC; 1638 if((fid->fd = open(npath, o, perm&0777)) < 0){ 1639 if(chatty9p) 1640 fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 1641 *ep = strerror(errno); 1642 free(npath); 1643 return -1; 1644 } 1645 } 1646 1647 opath = fid->path; 1648 fid->path = npath; 1649 if(fidstat(fid, ep) < 0){ 1650 fprint(2, "stat after create on %s failed\n", npath); 1651 remove(npath); /* race */ 1652 free(npath); 1653 fid->path = opath; 1654 if(fid->fd >= 0){ 1655 close(fid->fd); 1656 fid->fd = -1; 1657 }else{ 1658 closedir(fid->dir); 1659 fid->dir = nil; 1660 } 1661 return -1; 1662 } 1663 fid->omode = omode; 1664 free(opath); 1665 return 0; 1666 } 1667 1668 int 1669 userremove(Fid *fid, char **ep) 1670 { 1671 if(remove(fid->path) < 0){ 1672 *ep = strerror(errno); 1673 return -1; 1674 } 1675 return 0; 1676 } 1677 1678 void 1679 usage(void) 1680 { 1681 fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 1682 exit(1); 1683 } 1684 1685 int 1686 main(int argc, char **argv) 1687 { 1688 char *authtype; 1689 int i; 1690 int fd; 1691 int logflag; 1692 1693 auth = authmethods[0]; 1694 logflag = O_WRONLY|O_APPEND|O_CREAT; 1695 ARGBEGIN{ 1696 case 'D': 1697 chatty9p = 1; 1698 break; 1699 case 'a': 1700 authtype = EARGF(usage()); 1701 auth = nil; 1702 for(i=0; i<nelem(authmethods); i++) 1703 if(strcmp(authmethods[i]->name, authtype)==0) 1704 auth = authmethods[i]; 1705 if(auth == nil) 1706 sysfatal("unknown auth type '%s'", authtype); 1707 break; 1708 case 'A': 1709 autharg = EARGF(usage()); 1710 break; 1711 case 'l': 1712 logfile = EARGF(usage()); 1713 break; 1714 case 'm': 1715 msize = strtol(EARGF(usage()), 0, 0); 1716 break; 1717 case 'n': 1718 network = 0; 1719 break; 1720 case 'u': 1721 defaultuser = EARGF(usage()); 1722 break; 1723 case 'z': 1724 logflag |= O_TRUNC; 1725 }ARGEND 1726 1727 if(argc > 1) 1728 usage(); 1729 1730 fd = open(logfile, logflag, 0666); 1731 if(fd < 0) 1732 sysfatal("cannot open log '%s'", logfile); 1733 1734 if(dup2(fd, 2) < 0) 1735 sysfatal("cannot dup fd onto stderr"); 1736 fprint(2, "u9fs\nkill %d\n", (int)getpid()); 1737 1738 fmtinstall('F', fcallconv); 1739 fmtinstall('D', dirconv); 1740 fmtinstall('M', dirmodeconv); 1741 1742 rxbuf = emalloc(msize); 1743 txbuf = emalloc(msize); 1744 databuf = emalloc(msize); 1745 1746 if(auth->init) 1747 auth->init(); 1748 1749 if(network) 1750 getremotehostname(remotehostname, sizeof remotehostname); 1751 1752 if(gethostname(hostname, sizeof hostname) < 0) 1753 strcpy(hostname, "gnot"); 1754 1755 umask(0); 1756 1757 if(argc == 1) 1758 if(chroot(argv[0]) < 0) 1759 sysfatal("chroot '%s' failed", argv[0]); 1760 1761 none = uname2user("none"); 1762 1763 serve(0, 1); 1764 return 0; 1765 } 1766