19a747e4fSDavid du Colombier /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */ 29a747e4fSDavid du Colombier #include <sys/stat.h> /* for stat, umask */ 39a747e4fSDavid du Colombier #include <stdlib.h> /* for malloc */ 49a747e4fSDavid du Colombier #include <string.h> /* for strcpy, memmove */ 59a747e4fSDavid du Colombier #include <pwd.h> /* for getpwnam, getpwuid */ 69a747e4fSDavid du Colombier #include <grp.h> /* for getgrnam, getgrgid */ 79a747e4fSDavid du Colombier #include <unistd.h> /* for gethostname, pread, pwrite, read, write */ 89a747e4fSDavid du Colombier #include <utime.h> /* for utime */ 99a747e4fSDavid du Colombier #include <dirent.h> /* for readdir */ 109a747e4fSDavid du Colombier #include <errno.h> /* for errno */ 119a747e4fSDavid du Colombier #include <stdio.h> /* for remove [sic] */ 129a747e4fSDavid du Colombier #include <fcntl.h> /* for O_RDONLY, etc. */ 133e12c5d1SDavid du Colombier 149a747e4fSDavid du Colombier #include <sys/socket.h> /* various networking crud */ 15219b2ee8SDavid du Colombier #include <netinet/in.h> 16219b2ee8SDavid du Colombier #include <netdb.h> 179a747e4fSDavid du Colombier 189a747e4fSDavid du Colombier #include <plan9.h> 199a747e4fSDavid du Colombier #include <fcall.h> 209a747e4fSDavid du Colombier #include <oldfcall.h> 219a747e4fSDavid du Colombier #include <u9fs.h> 229a747e4fSDavid du Colombier 239a747e4fSDavid du Colombier /* #ifndef because can be given in makefile */ 249a747e4fSDavid du Colombier #ifndef DEFAULTLOG 259a747e4fSDavid du Colombier #define DEFAULTLOG "/tmp/u9fs.log" 263e12c5d1SDavid du Colombier #endif 273e12c5d1SDavid du Colombier 289a747e4fSDavid du Colombier char *logfile = DEFAULTLOG; 293e12c5d1SDavid du Colombier 309a747e4fSDavid du Colombier #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m)) 319a747e4fSDavid du Colombier 329a747e4fSDavid du Colombier enum { 339a747e4fSDavid du Colombier Tdot = 1, 349a747e4fSDavid du Colombier Tdotdot 353e12c5d1SDavid du Colombier }; 363e12c5d1SDavid du Colombier 379a747e4fSDavid du Colombier enum { 389a747e4fSDavid du Colombier P9P1, 399a747e4fSDavid du Colombier P9P2000 403e12c5d1SDavid du Colombier }; 413e12c5d1SDavid du Colombier 429a747e4fSDavid du Colombier typedef struct User User; 439a747e4fSDavid du Colombier struct User { 443e12c5d1SDavid du Colombier int id; 459a747e4fSDavid du Colombier gid_t defaultgid; 463e12c5d1SDavid du Colombier char *name; 479a747e4fSDavid du Colombier char **mem; /* group members */ 487dd7cddfSDavid du Colombier int nmem; 499a747e4fSDavid du Colombier User *next; 503e12c5d1SDavid du Colombier }; 513e12c5d1SDavid du Colombier 529a747e4fSDavid du Colombier typedef struct Fid Fid; 539a747e4fSDavid du Colombier struct Fid { 549a747e4fSDavid du Colombier int fid; 559a747e4fSDavid du Colombier char *path; 569a747e4fSDavid du Colombier struct stat st; 579a747e4fSDavid du Colombier User *u; 589a747e4fSDavid du Colombier int omode; 599a747e4fSDavid du Colombier DIR *dir; 609a747e4fSDavid du Colombier int diroffset; 619a747e4fSDavid du Colombier int fd; 629a747e4fSDavid du Colombier struct dirent *dirent; 639a747e4fSDavid du Colombier Fid *next; 649a747e4fSDavid du Colombier Fid *prev; 659a747e4fSDavid du Colombier }; 663e12c5d1SDavid du Colombier 679a747e4fSDavid du Colombier void* emalloc(size_t); 689a747e4fSDavid du Colombier void* erealloc(void*, size_t); 693e12c5d1SDavid du Colombier char* estrdup(char*); 709a747e4fSDavid du Colombier char* estrpath(char*, char*); 719a747e4fSDavid du Colombier void sysfatal(char*, ...); 729a747e4fSDavid du Colombier int okuser(char*); 733e12c5d1SDavid du Colombier 749a747e4fSDavid du Colombier void rversion(Fcall*, Fcall*); 759a747e4fSDavid du Colombier void rauth(Fcall*, Fcall*); 769a747e4fSDavid du Colombier void rattach(Fcall*, Fcall*); 779a747e4fSDavid du Colombier void rflush(Fcall*, Fcall*); 789a747e4fSDavid du Colombier void rclone(Fcall*, Fcall*); 799a747e4fSDavid du Colombier void rwalk(Fcall*, Fcall*); 809a747e4fSDavid du Colombier void ropen(Fcall*, Fcall*); 819a747e4fSDavid du Colombier void rcreate(Fcall*, Fcall*); 829a747e4fSDavid du Colombier void rread(Fcall*, Fcall*); 839a747e4fSDavid du Colombier void rwrite(Fcall*, Fcall*); 849a747e4fSDavid du Colombier void rclunk(Fcall*, Fcall*); 859a747e4fSDavid du Colombier void rstat(Fcall*, Fcall*); 869a747e4fSDavid du Colombier void rwstat(Fcall*, Fcall*); 879a747e4fSDavid du Colombier void rclwalk(Fcall*, Fcall*); 889a747e4fSDavid du Colombier void rremove(Fcall*, Fcall*); 899a747e4fSDavid du Colombier 909a747e4fSDavid du Colombier User* uname2user(char*); 919a747e4fSDavid du Colombier User* gname2user(char*); 929a747e4fSDavid du Colombier User* uid2user(int); 939a747e4fSDavid du Colombier User* gid2user(int); 949a747e4fSDavid du Colombier 959a747e4fSDavid du Colombier Fid* newfid(int, char**); 969a747e4fSDavid du Colombier Fid* oldfid(int, char**); 979a747e4fSDavid du Colombier int fidstat(Fid*, char**); 989a747e4fSDavid du Colombier void freefid(Fid*); 999a747e4fSDavid du Colombier 1009a747e4fSDavid du Colombier int userchange(User*, char**); 1019a747e4fSDavid du Colombier int userwalk(User*, char**, char*, Qid*, char**); 1029a747e4fSDavid du Colombier int useropen(Fid*, int, char**); 1039a747e4fSDavid du Colombier int usercreate(Fid*, char*, int, long, char**); 1049a747e4fSDavid du Colombier int userremove(Fid*, char**); 1059a747e4fSDavid du Colombier int userperm(User*, char*, int, int); 1069a747e4fSDavid du Colombier int useringroup(User*, User*); 1079a747e4fSDavid du Colombier 1089a747e4fSDavid du Colombier Qid stat2qid(struct stat*); 1099a747e4fSDavid du Colombier 1109a747e4fSDavid du Colombier void getfcallold(int, Fcall*, int); 1119a747e4fSDavid du Colombier void putfcallold(int, Fcall*); 1123e12c5d1SDavid du Colombier 1133e12c5d1SDavid du Colombier char Eauth[] = "authentication failed"; 1143e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range"; 1159a747e4fSDavid du Colombier char Ebadoffset[] = "bad offset in directory read"; 1169a747e4fSDavid du Colombier char Ebadusefid[] = "bad use of fid"; 1179a747e4fSDavid du Colombier char Edirchange[] = "wstat can't convert between files and directories"; 1189a747e4fSDavid du Colombier char Eexist[] = "file or directory already exists"; 1193e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use"; 1209a747e4fSDavid du Colombier char Enotdir[] = "not a directory"; 1219a747e4fSDavid du Colombier char Enotingroup[] = "not a member of proposed group"; 1229a747e4fSDavid du Colombier char Enotowner[] = "only owner can change group in wstat"; 1239a747e4fSDavid du Colombier char Eperm[] = "permission denied"; 1243e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files"; 1253e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files"; 1269a747e4fSDavid du Colombier char Especial[] = "no access to special file"; 1273e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large"; 1289a747e4fSDavid du Colombier char Eunknowngroup[] = "unknown group"; 1299a747e4fSDavid du Colombier char Eunknownuser[] = "unknown user"; 1309a747e4fSDavid du Colombier char Ewstatbuffer[] = "bogus wstat buffer"; 1319a747e4fSDavid du Colombier 1329a747e4fSDavid du Colombier ulong msize = IOHDRSZ+8192; 1339a747e4fSDavid du Colombier uchar* rxbuf; 1349a747e4fSDavid du Colombier uchar* txbuf; 1359a747e4fSDavid du Colombier void* databuf; 1369a747e4fSDavid du Colombier int connected; 1379a747e4fSDavid du Colombier int devallowed; 1389a747e4fSDavid du Colombier char* autharg; 1399a747e4fSDavid du Colombier char* defaultuser; 1409a747e4fSDavid du Colombier char hostname[256]; 1419a747e4fSDavid du Colombier char remotehostname[256]; 1429a747e4fSDavid du Colombier int chatty9p = 0; 1439a747e4fSDavid du Colombier int network = 1; 1449a747e4fSDavid du Colombier int old9p = -1; 1459a747e4fSDavid du Colombier int authed; 1469a747e4fSDavid du Colombier User* none; 1479a747e4fSDavid du Colombier 1489a747e4fSDavid du Colombier Auth *authmethods[] = { /* first is default */ 1499a747e4fSDavid du Colombier &authrhosts, 1509a747e4fSDavid du Colombier &authnone, 1519a747e4fSDavid du Colombier }; 1529a747e4fSDavid du Colombier 1539a747e4fSDavid du Colombier Auth *auth; 1543e12c5d1SDavid du Colombier 1557dd7cddfSDavid du Colombier void 1569a747e4fSDavid du Colombier getfcallnew(int fd, Fcall *fc, int have) 1577dd7cddfSDavid du Colombier { 1589a747e4fSDavid du Colombier int len; 1599a747e4fSDavid du Colombier 1609a747e4fSDavid du Colombier if(have > BIT32SZ) 1619a747e4fSDavid du Colombier sysfatal("cannot happen"); 1629a747e4fSDavid du Colombier 1639a747e4fSDavid du Colombier if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) 1649a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1659a747e4fSDavid du Colombier 1669a747e4fSDavid du Colombier len = GBIT32(rxbuf); 1679a747e4fSDavid du Colombier if(len <= BIT32SZ) 1689a747e4fSDavid du Colombier sysfatal("bogus message"); 1699a747e4fSDavid du Colombier 1709a747e4fSDavid du Colombier len -= BIT32SZ; 1719a747e4fSDavid du Colombier if(readn(fd, rxbuf+BIT32SZ, len) != len) 1729a747e4fSDavid du Colombier sysfatal("short message"); 1739a747e4fSDavid du Colombier 1749a747e4fSDavid du Colombier if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) 1759a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 1769a747e4fSDavid du Colombier } 1779a747e4fSDavid du Colombier 1789a747e4fSDavid du Colombier void 1799a747e4fSDavid du Colombier getfcallold(int fd, Fcall *fc, int have) 1809a747e4fSDavid du Colombier { 1819a747e4fSDavid du Colombier int len, n; 1829a747e4fSDavid du Colombier 1839a747e4fSDavid du Colombier if(have > 3) 1849a747e4fSDavid du Colombier sysfatal("cannot happen"); 1859a747e4fSDavid du Colombier 1869a747e4fSDavid du Colombier if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) 1879a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1889a747e4fSDavid du Colombier 1899a747e4fSDavid du Colombier len = oldhdrsize(rxbuf[0]); 1909a747e4fSDavid du Colombier if(len < 3) 1919a747e4fSDavid du Colombier sysfatal("bad message %d", rxbuf[0]); 1929a747e4fSDavid du Colombier if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) 1939a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1949a747e4fSDavid du Colombier 1959a747e4fSDavid du Colombier n = iosize(rxbuf); 1969a747e4fSDavid du Colombier if(readn(fd, rxbuf+len, n) != n) 1979a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1989a747e4fSDavid du Colombier len += n; 1999a747e4fSDavid du Colombier 2009a747e4fSDavid du Colombier if(convM2Sold(rxbuf, len, fc) != len) 2019a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 2029a747e4fSDavid du Colombier } 2039a747e4fSDavid du Colombier 2049a747e4fSDavid du Colombier void 2059a747e4fSDavid du Colombier putfcallnew(int wfd, Fcall *tx) 2069a747e4fSDavid du Colombier { 2079a747e4fSDavid du Colombier uint n; 2089a747e4fSDavid du Colombier 2099a747e4fSDavid du Colombier if((n = convS2M(tx, txbuf, msize)) == 0) 2109a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2119a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2129a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2139a747e4fSDavid du Colombier } 2149a747e4fSDavid du Colombier 2159a747e4fSDavid du Colombier void 2169a747e4fSDavid du Colombier putfcallold(int wfd, Fcall *tx) 2179a747e4fSDavid du Colombier { 2189a747e4fSDavid du Colombier uint n; 2199a747e4fSDavid du Colombier 2209a747e4fSDavid du Colombier if((n = convS2Mold(tx, txbuf, msize)) == 0) 2219a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2229a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2239a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2249a747e4fSDavid du Colombier } 2259a747e4fSDavid du Colombier 2269a747e4fSDavid du Colombier void 2279a747e4fSDavid du Colombier getfcall(int fd, Fcall *fc) 2289a747e4fSDavid du Colombier { 2299a747e4fSDavid du Colombier if(old9p == 1){ 2309a747e4fSDavid du Colombier getfcallold(fd, fc, 0); 2319a747e4fSDavid du Colombier return; 2329a747e4fSDavid du Colombier } 2339a747e4fSDavid du Colombier if(old9p == 0){ 2349a747e4fSDavid du Colombier getfcallnew(fd, fc, 0); 2359a747e4fSDavid du Colombier return; 2369a747e4fSDavid du Colombier } 2379a747e4fSDavid du Colombier 2389a747e4fSDavid du Colombier /* auto-detect */ 2399a747e4fSDavid du Colombier 2409a747e4fSDavid du Colombier if(readn(fd, rxbuf, 3) != 3) 2419a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2429a747e4fSDavid du Colombier 2439a747e4fSDavid du Colombier /* is it an old (9P1) message? */ 2449a747e4fSDavid du Colombier if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ 2459a747e4fSDavid du Colombier old9p = 1; 2469a747e4fSDavid du Colombier getfcallold(fd, fc, 3); 2479a747e4fSDavid du Colombier return; 2489a747e4fSDavid du Colombier } 2499a747e4fSDavid du Colombier 2509a747e4fSDavid du Colombier getfcallnew(fd, fc, 3); 2519a747e4fSDavid du Colombier old9p = 0; 2529a747e4fSDavid du Colombier } 2539a747e4fSDavid du Colombier 2549a747e4fSDavid du Colombier void 2559a747e4fSDavid du Colombier seterror(Fcall *f, char *error) 2569a747e4fSDavid du Colombier { 2579a747e4fSDavid du Colombier f->type = Rerror; 2589a747e4fSDavid du Colombier f->ename = error ? error : "programmer error"; 2597dd7cddfSDavid du Colombier } 2607dd7cddfSDavid du Colombier 2613e12c5d1SDavid du Colombier int 2629a747e4fSDavid du Colombier isowner(User *u, Fid *f) 2633e12c5d1SDavid du Colombier { 2649a747e4fSDavid du Colombier return u->id == f->st.st_uid; 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier 2673e12c5d1SDavid du Colombier void 2689a747e4fSDavid du Colombier serve(int rfd, int wfd) 2693e12c5d1SDavid du Colombier { 2709a747e4fSDavid du Colombier Fcall rx, tx; 2713e12c5d1SDavid du Colombier 2723e12c5d1SDavid du Colombier for(;;){ 2739a747e4fSDavid du Colombier getfcall(rfd, &rx); 2743e12c5d1SDavid du Colombier 2759a747e4fSDavid du Colombier if(chatty9p) 2769a747e4fSDavid du Colombier fprint(2, "<- %F\n", &rx); 2779a747e4fSDavid du Colombier 2789a747e4fSDavid du Colombier memset(&tx, 0, sizeof tx); 2799a747e4fSDavid du Colombier tx.type = rx.type+1; 2809a747e4fSDavid du Colombier tx.tag = rx.tag; 2819a747e4fSDavid du Colombier switch(rx.type){ 2829a747e4fSDavid du Colombier case Tflush: 2833e12c5d1SDavid du Colombier break; 2849a747e4fSDavid du Colombier case Tversion: 2859a747e4fSDavid du Colombier rversion(&rx, &tx); 2869a747e4fSDavid du Colombier break; 2879a747e4fSDavid du Colombier case Tauth: 2889a747e4fSDavid du Colombier rauth(&rx, &tx); 2893e12c5d1SDavid du Colombier break; 2903e12c5d1SDavid du Colombier case Tattach: 2919a747e4fSDavid du Colombier rattach(&rx, &tx); 2923e12c5d1SDavid du Colombier break; 2933e12c5d1SDavid du Colombier case Twalk: 2949a747e4fSDavid du Colombier rwalk(&rx, &tx); 2953e12c5d1SDavid du Colombier break; 2963e12c5d1SDavid du Colombier case Tstat: 2979a747e4fSDavid du Colombier tx.stat = databuf; 2989a747e4fSDavid du Colombier rstat(&rx, &tx); 2993e12c5d1SDavid du Colombier break; 3003e12c5d1SDavid du Colombier case Twstat: 3019a747e4fSDavid du Colombier rwstat(&rx, &tx); 3023e12c5d1SDavid du Colombier break; 3033e12c5d1SDavid du Colombier case Topen: 3049a747e4fSDavid du Colombier ropen(&rx, &tx); 3053e12c5d1SDavid du Colombier break; 3063e12c5d1SDavid du Colombier case Tcreate: 3079a747e4fSDavid du Colombier rcreate(&rx, &tx); 3083e12c5d1SDavid du Colombier break; 3093e12c5d1SDavid du Colombier case Tread: 3109a747e4fSDavid du Colombier tx.data = databuf; 3119a747e4fSDavid du Colombier rread(&rx, &tx); 3123e12c5d1SDavid du Colombier break; 3133e12c5d1SDavid du Colombier case Twrite: 3149a747e4fSDavid du Colombier rwrite(&rx, &tx); 3153e12c5d1SDavid du Colombier break; 3163e12c5d1SDavid du Colombier case Tclunk: 3179a747e4fSDavid du Colombier rclunk(&rx, &tx); 3183e12c5d1SDavid du Colombier break; 3193e12c5d1SDavid du Colombier case Tremove: 3209a747e4fSDavid du Colombier rremove(&rx, &tx); 3213e12c5d1SDavid du Colombier break; 3223e12c5d1SDavid du Colombier default: 3239a747e4fSDavid du Colombier fprint(2, "unknown message %F\n", &rx); 3249a747e4fSDavid du Colombier seterror(&tx, "bad message"); 3259a747e4fSDavid du Colombier break; 3263e12c5d1SDavid du Colombier } 3279a747e4fSDavid du Colombier 3289a747e4fSDavid du Colombier if(chatty9p) 3299a747e4fSDavid du Colombier fprint(2, "-> %F\n", &tx); 3309a747e4fSDavid du Colombier 3319a747e4fSDavid du Colombier (old9p ? putfcallold : putfcallnew)(wfd, &tx); 3329a747e4fSDavid du Colombier } 3333e12c5d1SDavid du Colombier } 3343e12c5d1SDavid du Colombier 3353e12c5d1SDavid du Colombier void 3369a747e4fSDavid du Colombier rversion(Fcall *rx, Fcall *tx) 3373e12c5d1SDavid du Colombier { 3389a747e4fSDavid du Colombier if(msize > rx->msize) 3399a747e4fSDavid du Colombier msize = rx->msize; 3409a747e4fSDavid du Colombier tx->msize = msize; 3419a747e4fSDavid du Colombier if(strncmp(rx->version, "9P", 2) != 0) 3429a747e4fSDavid du Colombier tx->version = "unknown"; 3439a747e4fSDavid du Colombier else 3449a747e4fSDavid du Colombier tx->version = "9P2000"; 3453e12c5d1SDavid du Colombier } 3463e12c5d1SDavid du Colombier 3473e12c5d1SDavid du Colombier void 3489a747e4fSDavid du Colombier rauth(Fcall *rx, Fcall *tx) 3493e12c5d1SDavid du Colombier { 3509a747e4fSDavid du Colombier char *e; 3513e12c5d1SDavid du Colombier 3529a747e4fSDavid du Colombier if((e = auth->auth(rx, tx)) != nil) 3539a747e4fSDavid du Colombier seterror(tx, e); 3543e12c5d1SDavid du Colombier } 3559a747e4fSDavid du Colombier 3569a747e4fSDavid du Colombier void 3579a747e4fSDavid du Colombier rattach(Fcall *rx, Fcall *tx) 3589a747e4fSDavid du Colombier { 3599a747e4fSDavid du Colombier char *e; 3609a747e4fSDavid du Colombier Fid *fid; 3619a747e4fSDavid du Colombier User *u; 3629a747e4fSDavid du Colombier 3639a747e4fSDavid du Colombier if(rx->aname == nil) 3649a747e4fSDavid du Colombier rx->aname = ""; 3659a747e4fSDavid du Colombier 3669a747e4fSDavid du Colombier if(strcmp(rx->aname, "device") == 0){ 3679a747e4fSDavid du Colombier if(connected && !devallowed){ 3689a747e4fSDavid du Colombier seterror(tx, Especial0); 3699a747e4fSDavid du Colombier return; 3709a747e4fSDavid du Colombier } 3713e12c5d1SDavid du Colombier devallowed = 1; 3723e12c5d1SDavid du Colombier }else{ 3739a747e4fSDavid du Colombier if(connected && devallowed){ 3749a747e4fSDavid du Colombier seterror(tx, Especial1); 3759a747e4fSDavid du Colombier return; 3763e12c5d1SDavid du Colombier } 3779a747e4fSDavid du Colombier } 3789a747e4fSDavid du Colombier 3799a747e4fSDavid du Colombier if(strcmp(rx->uname, "none") == 0){ 3809a747e4fSDavid du Colombier if(authed == 0){ 3819a747e4fSDavid du Colombier seterror(tx, Eauth); 3829a747e4fSDavid du Colombier return; 3839a747e4fSDavid du Colombier } 3849a747e4fSDavid du Colombier } else { 3859a747e4fSDavid du Colombier if((e = auth->attach(rx, tx)) != nil){ 3869a747e4fSDavid du Colombier seterror(tx, e); 3879a747e4fSDavid du Colombier return; 3889a747e4fSDavid du Colombier } 3899a747e4fSDavid du Colombier authed++; 3909a747e4fSDavid du Colombier } 3919a747e4fSDavid du Colombier 3929a747e4fSDavid du Colombier if((fid = newfid(rx->fid, &e)) == nil){ 3939a747e4fSDavid du Colombier seterror(tx, e); 3949a747e4fSDavid du Colombier return; 3959a747e4fSDavid du Colombier } 3969a747e4fSDavid du Colombier fid->path = estrdup("/"); 3979a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 3989a747e4fSDavid du Colombier seterror(tx, e); 3999a747e4fSDavid du Colombier freefid(fid); 4009a747e4fSDavid du Colombier return; 4019a747e4fSDavid du Colombier } 4029a747e4fSDavid du Colombier 4039a747e4fSDavid du Colombier if(defaultuser) 4049a747e4fSDavid du Colombier rx->uname = defaultuser; 4059a747e4fSDavid du Colombier 4069a747e4fSDavid du Colombier if((u = uname2user(rx->uname)) == nil || u->id == 0){ 4079a747e4fSDavid du Colombier /* we don't know anyone named root... */ 4089a747e4fSDavid du Colombier seterror(tx, Eunknownuser); 4099a747e4fSDavid du Colombier freefid(fid); 4109a747e4fSDavid du Colombier return; 4119a747e4fSDavid du Colombier } 4129a747e4fSDavid du Colombier 4139a747e4fSDavid du Colombier fid->u = u; 4149a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 4159a747e4fSDavid du Colombier return; 4163e12c5d1SDavid du Colombier } 4173e12c5d1SDavid du Colombier 4183e12c5d1SDavid du Colombier void 4199a747e4fSDavid du Colombier rwalk(Fcall *rx, Fcall *tx) 4203e12c5d1SDavid du Colombier { 4219a747e4fSDavid du Colombier int i; 4229a747e4fSDavid du Colombier char *path, *e; 4239a747e4fSDavid du Colombier Fid *fid, *nfid; 4243e12c5d1SDavid du Colombier 4259a747e4fSDavid du Colombier e = nil; 4269a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 4279a747e4fSDavid du Colombier seterror(tx, e); 4289a747e4fSDavid du Colombier return; 4293e12c5d1SDavid du Colombier } 4303e12c5d1SDavid du Colombier 4319a747e4fSDavid du Colombier if(fid->omode != -1){ 4329a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 4339a747e4fSDavid du Colombier return; 4343e12c5d1SDavid du Colombier } 4353e12c5d1SDavid du Colombier 4369a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4379a747e4fSDavid du Colombier seterror(tx, e); 4389a747e4fSDavid du Colombier return; 4399a747e4fSDavid du Colombier } 4403e12c5d1SDavid du Colombier 4419a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ 4429a747e4fSDavid du Colombier seterror(tx, Enotdir); 4439a747e4fSDavid du Colombier return; 4449a747e4fSDavid du Colombier } 4459a747e4fSDavid du Colombier 4469a747e4fSDavid du Colombier nfid = nil; 4479a747e4fSDavid du Colombier if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ 4489a747e4fSDavid du Colombier seterror(tx, e); 4499a747e4fSDavid du Colombier return; 4509a747e4fSDavid du Colombier } 4519a747e4fSDavid du Colombier 4529a747e4fSDavid du Colombier path = estrdup(fid->path); 4539a747e4fSDavid du Colombier e = nil; 4549a747e4fSDavid du Colombier for(i=0; i<rx->nwname; i++) 4559a747e4fSDavid du Colombier if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) 4563e12c5d1SDavid du Colombier break; 4573e12c5d1SDavid du Colombier 4589a747e4fSDavid du Colombier if(i == rx->nwname){ /* successful clone or walk */ 4599a747e4fSDavid du Colombier tx->nwqid = i; 4609a747e4fSDavid du Colombier if(nfid){ 4619a747e4fSDavid du Colombier nfid->path = path; 4629a747e4fSDavid du Colombier nfid->u = fid->u; 4633e12c5d1SDavid du Colombier }else{ 4649a747e4fSDavid du Colombier free(fid->path); 4659a747e4fSDavid du Colombier fid->path = path; 4663e12c5d1SDavid du Colombier } 4679a747e4fSDavid du Colombier }else{ 4689a747e4fSDavid du Colombier if(i > 0) /* partial walk? */ 4699a747e4fSDavid du Colombier tx->nwqid = i; 4709a747e4fSDavid du Colombier else 4719a747e4fSDavid du Colombier seterror(tx, e); 4729a747e4fSDavid du Colombier 4739a747e4fSDavid du Colombier if(nfid) /* clone implicit new fid */ 4749a747e4fSDavid du Colombier freefid(nfid); 4759a747e4fSDavid du Colombier free(path); 4763e12c5d1SDavid du Colombier } 4779a747e4fSDavid du Colombier return; 4783e12c5d1SDavid du Colombier } 4793e12c5d1SDavid du Colombier 4803e12c5d1SDavid du Colombier void 4819a747e4fSDavid du Colombier ropen(Fcall *rx, Fcall *tx) 4823e12c5d1SDavid du Colombier { 4839a747e4fSDavid du Colombier char *e; 4849a747e4fSDavid du Colombier Fid *fid; 4853e12c5d1SDavid du Colombier 4869a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 4879a747e4fSDavid du Colombier seterror(tx, e); 4889a747e4fSDavid du Colombier return; 4893e12c5d1SDavid du Colombier } 4909a747e4fSDavid du Colombier 4919a747e4fSDavid du Colombier if(fid->omode != -1){ 4929a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 4939a747e4fSDavid du Colombier return; 4943e12c5d1SDavid du Colombier } 4959a747e4fSDavid du Colombier 4969a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4979a747e4fSDavid du Colombier seterror(tx, e); 4989a747e4fSDavid du Colombier return; 4993e12c5d1SDavid du Colombier } 5009a747e4fSDavid du Colombier 5019a747e4fSDavid du Colombier if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ 5029a747e4fSDavid du Colombier seterror(tx, Especial); 5039a747e4fSDavid du Colombier return; 5043e12c5d1SDavid du Colombier } 5059a747e4fSDavid du Colombier 5069a747e4fSDavid du Colombier if(useropen(fid, rx->mode, &e) < 0){ 5079a747e4fSDavid du Colombier seterror(tx, e); 5089a747e4fSDavid du Colombier return; 5093e12c5d1SDavid du Colombier } 5109a747e4fSDavid du Colombier 5119a747e4fSDavid du Colombier tx->iounit = 0; 5129a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5133e12c5d1SDavid du Colombier } 5143e12c5d1SDavid du Colombier 5153e12c5d1SDavid du Colombier void 5169a747e4fSDavid du Colombier rcreate(Fcall *rx, Fcall *tx) 5173e12c5d1SDavid du Colombier { 5189a747e4fSDavid du Colombier char *e; 5199a747e4fSDavid du Colombier Fid *fid; 5209a747e4fSDavid du Colombier 5219a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 5229a747e4fSDavid du Colombier seterror(tx, e); 5239a747e4fSDavid du Colombier return; 5249a747e4fSDavid du Colombier } 5259a747e4fSDavid du Colombier 5269a747e4fSDavid du Colombier if(fid->omode != -1){ 5279a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 5289a747e4fSDavid du Colombier return; 5299a747e4fSDavid du Colombier } 5309a747e4fSDavid du Colombier 5319a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5329a747e4fSDavid du Colombier seterror(tx, e); 5339a747e4fSDavid du Colombier return; 5349a747e4fSDavid du Colombier } 5359a747e4fSDavid du Colombier 5369a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode)){ 5379a747e4fSDavid du Colombier seterror(tx, Enotdir); 5389a747e4fSDavid du Colombier return; 5399a747e4fSDavid du Colombier } 5409a747e4fSDavid du Colombier 5419a747e4fSDavid du Colombier if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ 5429a747e4fSDavid du Colombier seterror(tx, e); 5439a747e4fSDavid du Colombier return; 5449a747e4fSDavid du Colombier } 5459a747e4fSDavid du Colombier 5469a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5479a747e4fSDavid du Colombier seterror(tx, e); 5489a747e4fSDavid du Colombier return; 5499a747e4fSDavid du Colombier } 5509a747e4fSDavid du Colombier 5519a747e4fSDavid du Colombier tx->iounit = 0; 5529a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5539a747e4fSDavid du Colombier } 5549a747e4fSDavid du Colombier 5559a747e4fSDavid du Colombier uchar 5569a747e4fSDavid du Colombier modebyte(struct stat *st) 5579a747e4fSDavid du Colombier { 5589a747e4fSDavid du Colombier uchar b; 5599a747e4fSDavid du Colombier 5609a747e4fSDavid du Colombier b = 0; 5619a747e4fSDavid du Colombier 5629a747e4fSDavid du Colombier if(S_ISDIR(st->st_mode)) 5639a747e4fSDavid du Colombier b |= QTDIR; 5649a747e4fSDavid du Colombier 5659a747e4fSDavid du Colombier /* no way to test append-only */ 5669a747e4fSDavid du Colombier /* no real way to test exclusive use, but mark devices as such */ 5679a747e4fSDavid du Colombier if(S_ISSPECIAL(st->st_mode)) 5689a747e4fSDavid du Colombier b |= QTEXCL; 5699a747e4fSDavid du Colombier 5709a747e4fSDavid du Colombier return b; 5719a747e4fSDavid du Colombier } 5729a747e4fSDavid du Colombier 5739a747e4fSDavid du Colombier ulong 5749a747e4fSDavid du Colombier plan9mode(struct stat *st) 5759a747e4fSDavid du Colombier { 5769a747e4fSDavid du Colombier return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777); 5779a747e4fSDavid du Colombier } 5789a747e4fSDavid du Colombier 5799a747e4fSDavid du Colombier /* 5809a747e4fSDavid du Colombier * this is for chmod, so don't worry about S_IFDIR 5819a747e4fSDavid du Colombier */ 5829a747e4fSDavid du Colombier mode_t 5839a747e4fSDavid du Colombier unixmode(Dir *d) 5849a747e4fSDavid du Colombier { 5859a747e4fSDavid du Colombier return (mode_t)(d->mode&0777); 5869a747e4fSDavid du Colombier } 5879a747e4fSDavid du Colombier 5889a747e4fSDavid du Colombier Qid 5899a747e4fSDavid du Colombier stat2qid(struct stat *st) 5909a747e4fSDavid du Colombier { 5919a747e4fSDavid du Colombier uchar *p, *ep, *q; 5929a747e4fSDavid du Colombier Qid qid; 5939a747e4fSDavid du Colombier 5949a747e4fSDavid du Colombier /* 5959a747e4fSDavid du Colombier * For now, ignore the device number. 5969a747e4fSDavid du Colombier */ 5979a747e4fSDavid du Colombier qid.path = 0; 5989a747e4fSDavid du Colombier p = (uchar*)&qid.path; 5999a747e4fSDavid du Colombier ep = p+sizeof(qid.path); 6009a747e4fSDavid du Colombier q = p+sizeof(ino_t); 6019a747e4fSDavid du Colombier if(q > ep){ 6029a747e4fSDavid du Colombier fprint(2, "warning: inode number too big\n"); 6039a747e4fSDavid du Colombier q = ep; 6049a747e4fSDavid du Colombier } 6059a747e4fSDavid du Colombier memmove(p, &st->st_ino, q-p); 6069a747e4fSDavid du Colombier q = q+sizeof(dev_t); 6079a747e4fSDavid du Colombier if(q > ep){ 6089a747e4fSDavid du Colombier /* fprint(2, "warning: inode number + device number too big %d+%d\n", sizeof(ino_t), sizeof(dev_t)); */ 6099a747e4fSDavid du Colombier q = ep - sizeof(dev_t); 6109a747e4fSDavid du Colombier if(q < p) 6119a747e4fSDavid du Colombier fprint(2, "warning: device number too big by itself\n"); 6129a747e4fSDavid du Colombier else 6139a747e4fSDavid du Colombier *(dev_t*)q ^= st->st_dev; 6149a747e4fSDavid du Colombier } 6159a747e4fSDavid du Colombier 6169a747e4fSDavid du Colombier qid.vers = st->st_mtime ^ (st->st_size << 8); 6179a747e4fSDavid du Colombier qid.type = modebyte(st); 6189a747e4fSDavid du Colombier return qid; 6199a747e4fSDavid du Colombier } 6209a747e4fSDavid du Colombier 6219a747e4fSDavid du Colombier void 6229a747e4fSDavid du Colombier stat2dir(char *path, struct stat *st, Dir *d) 6239a747e4fSDavid du Colombier { 6249a747e4fSDavid du Colombier User *u; 6259a747e4fSDavid du Colombier char *q; 6269a747e4fSDavid du Colombier 6279a747e4fSDavid du Colombier memset(d, 0, sizeof(*d)); 6289a747e4fSDavid du Colombier d->qid = stat2qid(st); 6299a747e4fSDavid du Colombier d->mode = plan9mode(st); 6309a747e4fSDavid du Colombier d->atime = st->st_atime; 6319a747e4fSDavid du Colombier d->mtime = st->st_mtime; 6329a747e4fSDavid du Colombier d->length = st->st_size; 6339a747e4fSDavid du Colombier 6349a747e4fSDavid du Colombier d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; 6359a747e4fSDavid du Colombier d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; 6369a747e4fSDavid du Colombier d->muid = ""; 6379a747e4fSDavid du Colombier 6389a747e4fSDavid du Colombier if((q = strrchr(path, '/')) != nil) 6399a747e4fSDavid du Colombier d->name = q+1; 6409a747e4fSDavid du Colombier else 6419a747e4fSDavid du Colombier d->name = path; 6429a747e4fSDavid du Colombier } 6439a747e4fSDavid du Colombier 6449a747e4fSDavid du Colombier void 6459a747e4fSDavid du Colombier rread(Fcall *rx, Fcall *tx) 6469a747e4fSDavid du Colombier { 6479a747e4fSDavid du Colombier char *e, *path; 6489a747e4fSDavid du Colombier uchar *p, *ep; 6499a747e4fSDavid du Colombier int n; 6509a747e4fSDavid du Colombier Fid *fid; 6513e12c5d1SDavid du Colombier Dir d; 6529a747e4fSDavid du Colombier struct stat st; 6533e12c5d1SDavid du Colombier 6549a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 6559a747e4fSDavid du Colombier seterror(tx, Etoolarge); 6569a747e4fSDavid du Colombier return; 6573e12c5d1SDavid du Colombier } 6589a747e4fSDavid du Colombier 6599a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 6609a747e4fSDavid du Colombier seterror(tx, e); 6619a747e4fSDavid du Colombier return; 6623e12c5d1SDavid du Colombier } 6639a747e4fSDavid du Colombier 6649a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OWRITE){ 6659a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 6669a747e4fSDavid du Colombier return; 6679a747e4fSDavid du Colombier } 6689a747e4fSDavid du Colombier 6699a747e4fSDavid du Colombier if(fid->dir){ 6709a747e4fSDavid du Colombier if(rx->offset != fid->diroffset){ 6719a747e4fSDavid du Colombier if(rx->offset != 0){ 6729a747e4fSDavid du Colombier seterror(tx, Ebadoffset); 6739a747e4fSDavid du Colombier return; 6749a747e4fSDavid du Colombier } 6759a747e4fSDavid du Colombier rewinddir(fid->dir); 6769a747e4fSDavid du Colombier fid->diroffset = 0; 6779a747e4fSDavid du Colombier } 6789a747e4fSDavid du Colombier 6799a747e4fSDavid du Colombier p = (uchar*)tx->data; 6809a747e4fSDavid du Colombier ep = (uchar*)tx->data+rx->count; 6819a747e4fSDavid du Colombier for(;;){ 6829a747e4fSDavid du Colombier if(p+BIT16SZ >= ep) 6833e12c5d1SDavid du Colombier break; 6849a747e4fSDavid du Colombier if(fid->dirent == nil) /* one entry cache for when convD2M fails */ 6859a747e4fSDavid du Colombier if((fid->dirent = readdir(fid->dir)) == nil) 6869a747e4fSDavid du Colombier break; 6879a747e4fSDavid du Colombier if(strcmp(fid->dirent->d_name, ".") == 0 6889a747e4fSDavid du Colombier || strcmp(fid->dirent->d_name, "..") == 0){ 6899a747e4fSDavid du Colombier fid->dirent = nil; 6903e12c5d1SDavid du Colombier continue; 6919a747e4fSDavid du Colombier } 6929a747e4fSDavid du Colombier path = estrpath(fid->path, fid->dirent->d_name); 6939a747e4fSDavid du Colombier memset(&st, 0, sizeof st); 6949a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 6959a747e4fSDavid du Colombier fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); 6969a747e4fSDavid du Colombier fid->dirent = nil; 6979a747e4fSDavid du Colombier free(path); 6983e12c5d1SDavid du Colombier continue; 6993e12c5d1SDavid du Colombier } 7003e12c5d1SDavid du Colombier free(path); 7019a747e4fSDavid du Colombier stat2dir(fid->dirent->d_name, &st, &d); 7029a747e4fSDavid du Colombier if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) 7039a747e4fSDavid du Colombier break; 7049a747e4fSDavid du Colombier p += n; 7059a747e4fSDavid du Colombier fid->dirent = nil; 7063e12c5d1SDavid du Colombier } 7079a747e4fSDavid du Colombier tx->count = p - (uchar*)tx->data; 7089a747e4fSDavid du Colombier fid->diroffset += tx->count; 7093e12c5d1SDavid du Colombier }else{ 7109a747e4fSDavid du Colombier if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ 7119a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 7129a747e4fSDavid du Colombier return; 713219b2ee8SDavid du Colombier } 7149a747e4fSDavid du Colombier tx->count = n; 7153e12c5d1SDavid du Colombier } 7163e12c5d1SDavid du Colombier } 7173e12c5d1SDavid du Colombier 7183e12c5d1SDavid du Colombier void 7199a747e4fSDavid du Colombier rwrite(Fcall *rx, Fcall *tx) 7203e12c5d1SDavid du Colombier { 7219a747e4fSDavid du Colombier char *e; 7229a747e4fSDavid du Colombier Fid *fid; 7233e12c5d1SDavid du Colombier int n; 7243e12c5d1SDavid du Colombier 7259a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 7269a747e4fSDavid du Colombier seterror(tx, Etoolarge); 7277dd7cddfSDavid du Colombier return; 7287dd7cddfSDavid du Colombier } 7299a747e4fSDavid du Colombier 7309a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 7319a747e4fSDavid du Colombier seterror(tx, e); 7329a747e4fSDavid du Colombier return; 7333e12c5d1SDavid du Colombier } 7349a747e4fSDavid du Colombier 7359a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ 7369a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 7379a747e4fSDavid du Colombier return; 7389a747e4fSDavid du Colombier } 7399a747e4fSDavid du Colombier 7409a747e4fSDavid du Colombier if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ 7419a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 7429a747e4fSDavid du Colombier return; 7439a747e4fSDavid du Colombier } 7449a747e4fSDavid du Colombier tx->count = n; 7453e12c5d1SDavid du Colombier } 7463e12c5d1SDavid du Colombier 7473e12c5d1SDavid du Colombier void 7489a747e4fSDavid du Colombier rclunk(Fcall *rx, Fcall *tx) 7493e12c5d1SDavid du Colombier { 7509a747e4fSDavid du Colombier char *e; 7519a747e4fSDavid du Colombier Fid *fid; 7523e12c5d1SDavid du Colombier 7539a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 7549a747e4fSDavid du Colombier seterror(tx, e); 7559a747e4fSDavid du Colombier return; 7569a747e4fSDavid du Colombier } 7579a747e4fSDavid du Colombier if(fid->omode != -1 && fid->omode&ORCLOSE) 7589a747e4fSDavid du Colombier remove(fid->path); 7599a747e4fSDavid du Colombier freefid(fid); 7603e12c5d1SDavid du Colombier } 761219b2ee8SDavid du Colombier 7629a747e4fSDavid du Colombier void 7639a747e4fSDavid du Colombier rremove(Fcall *rx, Fcall *tx) 7643e12c5d1SDavid du Colombier { 7659a747e4fSDavid du Colombier char *e; 7669a747e4fSDavid du Colombier Fid *fid; 7673e12c5d1SDavid du Colombier 7689a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 7699a747e4fSDavid du Colombier seterror(tx, e); 7709a747e4fSDavid du Colombier return; 7713e12c5d1SDavid du Colombier } 7729a747e4fSDavid du Colombier if(userremove(fid, &e) < 0) 7739a747e4fSDavid du Colombier seterror(tx, e); 7749a747e4fSDavid du Colombier freefid(fid); 7759a747e4fSDavid du Colombier } 7769a747e4fSDavid du Colombier 7779a747e4fSDavid du Colombier void 7789a747e4fSDavid du Colombier rstat(Fcall *rx, Fcall *tx) 7799a747e4fSDavid du Colombier { 7809a747e4fSDavid du Colombier char *e; 7819a747e4fSDavid du Colombier Fid *fid; 7829a747e4fSDavid du Colombier Dir d; 7839a747e4fSDavid du Colombier 7849a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 7859a747e4fSDavid du Colombier seterror(tx, e); 7869a747e4fSDavid du Colombier return; 7879a747e4fSDavid du Colombier } 7889a747e4fSDavid du Colombier 7899a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 7909a747e4fSDavid du Colombier seterror(tx, e); 7919a747e4fSDavid du Colombier return; 7929a747e4fSDavid du Colombier } 7939a747e4fSDavid du Colombier 7949a747e4fSDavid du Colombier stat2dir(fid->path, &fid->st, &d); 7959a747e4fSDavid du Colombier if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) 7969a747e4fSDavid du Colombier seterror(tx, "convD2M fails"); 7979a747e4fSDavid du Colombier } 7989a747e4fSDavid du Colombier 7999a747e4fSDavid du Colombier void 8009a747e4fSDavid du Colombier rwstat(Fcall *rx, Fcall *tx) 8019a747e4fSDavid du Colombier { 8029a747e4fSDavid du Colombier char *e; 8039a747e4fSDavid du Colombier char *p, *old, *new, *dir; 8049a747e4fSDavid du Colombier gid_t gid; 8059a747e4fSDavid du Colombier Dir d; 8069a747e4fSDavid du Colombier Fid *fid; 8079a747e4fSDavid du Colombier 8089a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8099a747e4fSDavid du Colombier seterror(tx, e); 8109a747e4fSDavid du Colombier return; 8119a747e4fSDavid du Colombier } 8129a747e4fSDavid du Colombier 8139a747e4fSDavid du Colombier /* 8149a747e4fSDavid du Colombier * wstat is supposed to be atomic. 8159a747e4fSDavid du Colombier * we check all the things we can before trying anything. 8169a747e4fSDavid du Colombier * still, if we are told to truncate a file and rename it and only 8179a747e4fSDavid du Colombier * one works, we're screwed. in such cases we leave things 8189a747e4fSDavid du Colombier * half broken and return an error. it's hardly perfect. 8199a747e4fSDavid du Colombier */ 8209a747e4fSDavid du Colombier if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ 8219a747e4fSDavid du Colombier seterror(tx, Ewstatbuffer); 8229a747e4fSDavid du Colombier return; 8239a747e4fSDavid du Colombier } 8249a747e4fSDavid du Colombier 8259a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 8269a747e4fSDavid du Colombier seterror(tx, e); 8279a747e4fSDavid du Colombier return; 8289a747e4fSDavid du Colombier } 8299a747e4fSDavid du Colombier 8309a747e4fSDavid du Colombier /* 8319a747e4fSDavid du Colombier * The casting is necessary because d.mode is ulong and might, 8329a747e4fSDavid du Colombier * on some systems, be 64 bits. We only want to compare the 8339a747e4fSDavid du Colombier * bottom 32 bits, since that's all that gets sent in the protocol. 8349a747e4fSDavid du Colombier * 8359a747e4fSDavid du Colombier * Same situation for d.mtime and d.length (although that last check 8369a747e4fSDavid du Colombier * is admittedly superfluous, given the current lack of 128-bit machines). 8379a747e4fSDavid du Colombier */ 8389a747e4fSDavid du Colombier gid = (gid_t)-1; 8399a747e4fSDavid du Colombier if(d.gid[0] != '\0'){ 8409a747e4fSDavid du Colombier User *g; 8419a747e4fSDavid du Colombier 8429a747e4fSDavid du Colombier g = gname2user(d.gid); 8439a747e4fSDavid du Colombier if(g == nil){ 8449a747e4fSDavid du Colombier seterror(tx, Eunknowngroup); 8459a747e4fSDavid du Colombier return; 8469a747e4fSDavid du Colombier } 8479a747e4fSDavid du Colombier gid = (gid_t)g->id; 8489a747e4fSDavid du Colombier 8499a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(gid), &e) < 0){ 8509a747e4fSDavid du Colombier seterror(tx, e); 8519a747e4fSDavid du Colombier return; 8529a747e4fSDavid du Colombier } 8539a747e4fSDavid du Colombier } 8549a747e4fSDavid du Colombier 8559a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ 8569a747e4fSDavid du Colombier seterror(tx, Edirchange); 8579a747e4fSDavid du Colombier return; 8589a747e4fSDavid du Colombier } 8599a747e4fSDavid du Colombier 8609a747e4fSDavid du Colombier if(strcmp(fid->path, "/") == 0){ 8619a747e4fSDavid du Colombier seterror(tx, "no wstat of root"); 8629a747e4fSDavid du Colombier return; 8639a747e4fSDavid du Colombier } 8649a747e4fSDavid du Colombier 8659a747e4fSDavid du Colombier /* 8669a747e4fSDavid du Colombier * try things in increasing order of harm to the file. 8679a747e4fSDavid du Colombier * mtime should come after truncate so that if you 8689a747e4fSDavid du Colombier * do both the mtime actually takes effect, but i'd rather 8699a747e4fSDavid du Colombier * leave truncate until last. 8709a747e4fSDavid du Colombier * (see above comment about atomicity). 8719a747e4fSDavid du Colombier */ 8729a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ 8739a747e4fSDavid du Colombier if(chatty9p) 8749a747e4fSDavid du Colombier fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); 8759a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 8769a747e4fSDavid du Colombier return; 8779a747e4fSDavid du Colombier } 8789a747e4fSDavid du Colombier 8799a747e4fSDavid du Colombier if((u32int)d.mtime != (u32int)~0){ 8809a747e4fSDavid du Colombier struct utimbuf t; 8819a747e4fSDavid du Colombier 8829a747e4fSDavid du Colombier t.actime = 0; 8839a747e4fSDavid du Colombier t.modtime = d.mtime; 8849a747e4fSDavid du Colombier if(utime(fid->path, &t) < 0){ 8859a747e4fSDavid du Colombier if(chatty9p) 8869a747e4fSDavid du Colombier fprint(2, "utime(%s) failed\n", fid->path); 8879a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 8889a747e4fSDavid du Colombier return; 8899a747e4fSDavid du Colombier } 8909a747e4fSDavid du Colombier } 8919a747e4fSDavid du Colombier 8929a747e4fSDavid du Colombier if(gid != (gid_t)-1 && gid != fid->st.st_gid){ 8939a747e4fSDavid du Colombier if(chown(fid->path, (uid_t)-1, gid) < 0){ 8949a747e4fSDavid du Colombier if(chatty9p) 8959a747e4fSDavid du Colombier fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); 8969a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 8979a747e4fSDavid du Colombier return; 8989a747e4fSDavid du Colombier } 8999a747e4fSDavid du Colombier } 9009a747e4fSDavid du Colombier 9019a747e4fSDavid du Colombier if(d.name[0]){ 9029a747e4fSDavid du Colombier old = fid->path; 9039a747e4fSDavid du Colombier dir = estrdup(fid->path); 9049a747e4fSDavid du Colombier if((p = strrchr(dir, '/')) > dir) 9059a747e4fSDavid du Colombier *p = '\0'; 9063e12c5d1SDavid du Colombier else{ 9079a747e4fSDavid du Colombier seterror(tx, "whoops: can't happen in u9fs"); 9089a747e4fSDavid du Colombier return; 9093e12c5d1SDavid du Colombier } 9103e12c5d1SDavid du Colombier 9119a747e4fSDavid du Colombier new = estrpath(dir, d.name); 9129a747e4fSDavid du Colombier if(strcmp(old, new) != 0 && rename(old, new) < 0){ 9139a747e4fSDavid du Colombier if(chatty9p) 9149a747e4fSDavid du Colombier fprint(2, "rename(%s, %s) failed\n", old, new); 9159a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9169a747e4fSDavid du Colombier free(new); 9179a747e4fSDavid du Colombier free(dir); 9189a747e4fSDavid du Colombier return; 9199a747e4fSDavid du Colombier } 9209a747e4fSDavid du Colombier fid->path = new; 9219a747e4fSDavid du Colombier free(old); 9229a747e4fSDavid du Colombier free(dir); 9239a747e4fSDavid du Colombier } 9249a747e4fSDavid du Colombier 9259a747e4fSDavid du Colombier if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ 9269a747e4fSDavid du Colombier fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); 9279a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9289a747e4fSDavid du Colombier return; 9299a747e4fSDavid du Colombier } 9309a747e4fSDavid du Colombier } 9319a747e4fSDavid du Colombier 9329a747e4fSDavid du Colombier /* 9339a747e4fSDavid du Colombier * we keep a table by numeric id. by name lookups happen infrequently 9349a747e4fSDavid du Colombier * while by-number lookups happen once for every directory entry read 9359a747e4fSDavid du Colombier * and every stat request. 9369a747e4fSDavid du Colombier */ 9379a747e4fSDavid du Colombier User *utab[64]; 9389a747e4fSDavid du Colombier User *gtab[64]; 9399a747e4fSDavid du Colombier 9409a747e4fSDavid du Colombier User* 9419a747e4fSDavid du Colombier adduser(struct passwd *p) 9423e12c5d1SDavid du Colombier { 9439a747e4fSDavid du Colombier User *u; 9443e12c5d1SDavid du Colombier 9459a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 9469a747e4fSDavid du Colombier u->id = p->pw_uid; 9479a747e4fSDavid du Colombier u->name = estrdup(p->pw_name); 9489a747e4fSDavid du Colombier u->next = utab[p->pw_uid%nelem(utab)]; 9499a747e4fSDavid du Colombier u->defaultgid = p->pw_gid; 9509a747e4fSDavid du Colombier utab[p->pw_uid%nelem(utab)] = u; 9519a747e4fSDavid du Colombier return u; 9523e12c5d1SDavid du Colombier } 9533e12c5d1SDavid du Colombier 9543e12c5d1SDavid du Colombier int 9559a747e4fSDavid du Colombier useringroup(User *u, User *g) 9563e12c5d1SDavid du Colombier { 9579a747e4fSDavid du Colombier int i; 9589a747e4fSDavid du Colombier 9599a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++) 9609a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0) 9613e12c5d1SDavid du Colombier return 1; 9629a747e4fSDavid du Colombier 9639a747e4fSDavid du Colombier /* 9649a747e4fSDavid du Colombier * Hack around common Unix problem that everyone has 9659a747e4fSDavid du Colombier * default group "user" but /etc/group lists no members. 9669a747e4fSDavid du Colombier */ 9679a747e4fSDavid du Colombier if(u->defaultgid == g->id) 9689a747e4fSDavid du Colombier return 1; 9693e12c5d1SDavid du Colombier return 0; 9703e12c5d1SDavid du Colombier } 9713e12c5d1SDavid du Colombier 9729a747e4fSDavid du Colombier User* 9739a747e4fSDavid du Colombier addgroup(struct group *g) 9743e12c5d1SDavid du Colombier { 9759a747e4fSDavid du Colombier User *u; 9769a747e4fSDavid du Colombier char **p; 9773e12c5d1SDavid du Colombier int n; 9783e12c5d1SDavid du Colombier 9799a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 9809a747e4fSDavid du Colombier n = 0; 9819a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 9829a747e4fSDavid du Colombier n++; 9839a747e4fSDavid du Colombier u->mem = emalloc(sizeof(u->mem[0])*n); 9849a747e4fSDavid du Colombier n = 0; 9859a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 9869a747e4fSDavid du Colombier u->mem[n++] = estrdup(*p); 9879a747e4fSDavid du Colombier u->nmem = n; 9889a747e4fSDavid du Colombier u->id = g->gr_gid; 9899a747e4fSDavid du Colombier u->name = estrdup(g->gr_name); 9909a747e4fSDavid du Colombier u->next = gtab[g->gr_gid%nelem(gtab)]; 9919a747e4fSDavid du Colombier gtab[g->gr_gid%nelem(gtab)] = u; 9929a747e4fSDavid du Colombier return u; 9933e12c5d1SDavid du Colombier } 9943e12c5d1SDavid du Colombier 9959a747e4fSDavid du Colombier User* 9969a747e4fSDavid du Colombier uname2user(char *name) 9977dd7cddfSDavid du Colombier { 9987dd7cddfSDavid du Colombier int i; 9999a747e4fSDavid du Colombier User *u; 10009a747e4fSDavid du Colombier struct passwd *p; 10017dd7cddfSDavid du Colombier 10029a747e4fSDavid du Colombier for(i=0; i<nelem(utab); i++) 10039a747e4fSDavid du Colombier for(u=utab[i]; u; u=u->next) 10049a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 10059a747e4fSDavid du Colombier return u; 10069a747e4fSDavid du Colombier 10079a747e4fSDavid du Colombier if((p = getpwnam(name)) == nil) 10089a747e4fSDavid du Colombier return nil; 10099a747e4fSDavid du Colombier return adduser(p); 10107dd7cddfSDavid du Colombier } 10117dd7cddfSDavid du Colombier 10129a747e4fSDavid du Colombier User* 10139a747e4fSDavid du Colombier uid2user(int id) 10149a747e4fSDavid du Colombier { 10159a747e4fSDavid du Colombier User *u; 10169a747e4fSDavid du Colombier struct passwd *p; 10179a747e4fSDavid du Colombier 10189a747e4fSDavid du Colombier for(u=utab[id%nelem(utab)]; u; u=u->next) 10199a747e4fSDavid du Colombier if(u->id == id) 10209a747e4fSDavid du Colombier return u; 10219a747e4fSDavid du Colombier 10229a747e4fSDavid du Colombier if((p = getpwuid(id)) == nil) 10239a747e4fSDavid du Colombier return nil; 10249a747e4fSDavid du Colombier return adduser(p); 10259a747e4fSDavid du Colombier } 10269a747e4fSDavid du Colombier 10279a747e4fSDavid du Colombier User* 10289a747e4fSDavid du Colombier gname2user(char *name) 10293e12c5d1SDavid du Colombier { 10303e12c5d1SDavid du Colombier int i; 10319a747e4fSDavid du Colombier User *u; 10329a747e4fSDavid du Colombier struct group *g; 10333e12c5d1SDavid du Colombier 10349a747e4fSDavid du Colombier for(i=0; i<nelem(gtab); i++) 10359a747e4fSDavid du Colombier for(u=gtab[i]; u; u=u->next) 10369a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 10379a747e4fSDavid du Colombier return u; 10389a747e4fSDavid du Colombier 10399a747e4fSDavid du Colombier if((g = getgrnam(name)) == nil) 10409a747e4fSDavid du Colombier return nil; 10419a747e4fSDavid du Colombier return addgroup(g); 10429a747e4fSDavid du Colombier } 10439a747e4fSDavid du Colombier 10449a747e4fSDavid du Colombier User* 10459a747e4fSDavid du Colombier gid2user(int id) 10469a747e4fSDavid du Colombier { 10479a747e4fSDavid du Colombier User *u; 10489a747e4fSDavid du Colombier struct group *g; 10499a747e4fSDavid du Colombier 10509a747e4fSDavid du Colombier for(u=gtab[id%nelem(gtab)]; u; u=u->next) 10519a747e4fSDavid du Colombier if(u->id == id) 10529a747e4fSDavid du Colombier return u; 10539a747e4fSDavid du Colombier 10549a747e4fSDavid du Colombier if((g = getgrgid(id)) == nil) 10559a747e4fSDavid du Colombier return nil; 10569a747e4fSDavid du Colombier return addgroup(g); 10573e12c5d1SDavid du Colombier } 10583e12c5d1SDavid du Colombier 10593e12c5d1SDavid du Colombier void 10609a747e4fSDavid du Colombier sysfatal(char *fmt, ...) 10613e12c5d1SDavid du Colombier { 10629a747e4fSDavid du Colombier char buf[1024]; 10639a747e4fSDavid du Colombier va_list va; 10643e12c5d1SDavid du Colombier 10659a747e4fSDavid du Colombier va_start(va, fmt); 10669a747e4fSDavid du Colombier doprint(buf, buf+sizeof buf, fmt, va); 10679a747e4fSDavid du Colombier va_end(va); 10689a747e4fSDavid du Colombier fprint(2, "u9fs: %s\n", buf); 10699a747e4fSDavid du Colombier fprint(2, "last unix error: %s\n", strerror(errno)); 10703e12c5d1SDavid du Colombier exit(1); 10713e12c5d1SDavid du Colombier } 10723e12c5d1SDavid du Colombier 10733e12c5d1SDavid du Colombier void* 10749a747e4fSDavid du Colombier emalloc(size_t n) 10759a747e4fSDavid du Colombier { 10769a747e4fSDavid du Colombier void *p; 10779a747e4fSDavid du Colombier 1078*d9306527SDavid du Colombier if(n == 0) 1079*d9306527SDavid du Colombier n = 1; 10809a747e4fSDavid du Colombier p = malloc(n); 10819a747e4fSDavid du Colombier if(p == 0) 10829a747e4fSDavid du Colombier sysfatal("malloc(%ld) fails", (long)n); 10839a747e4fSDavid du Colombier memset(p, 0, n); 10849a747e4fSDavid du Colombier return p; 10859a747e4fSDavid du Colombier } 10869a747e4fSDavid du Colombier 10879a747e4fSDavid du Colombier void* 10889a747e4fSDavid du Colombier erealloc(void *p, size_t n) 10893e12c5d1SDavid du Colombier { 10903e12c5d1SDavid du Colombier if(p == 0) 10913e12c5d1SDavid du Colombier p = malloc(n); 10923e12c5d1SDavid du Colombier else 10933e12c5d1SDavid du Colombier p = realloc(p, n); 10943e12c5d1SDavid du Colombier if(p == 0) 10959a747e4fSDavid du Colombier sysfatal("realloc(..., %ld) fails", (long)n); 10963e12c5d1SDavid du Colombier return p; 10973e12c5d1SDavid du Colombier } 10983e12c5d1SDavid du Colombier 10993e12c5d1SDavid du Colombier char* 11003e12c5d1SDavid du Colombier estrdup(char *p) 11013e12c5d1SDavid du Colombier { 11023e12c5d1SDavid du Colombier p = strdup(p); 11033e12c5d1SDavid du Colombier if(p == 0) 11049a747e4fSDavid du Colombier sysfatal("strdup(%.20s) fails", p); 11053e12c5d1SDavid du Colombier return p; 11063e12c5d1SDavid du Colombier } 1107219b2ee8SDavid du Colombier 11089a747e4fSDavid du Colombier char* 11099a747e4fSDavid du Colombier estrpath(char *p, char *q) 1110219b2ee8SDavid du Colombier { 11119a747e4fSDavid du Colombier char *r, *s; 1112219b2ee8SDavid du Colombier 11139a747e4fSDavid du Colombier if(strcmp(q, "..") == 0){ 11149a747e4fSDavid du Colombier r = estrdup(p); 11159a747e4fSDavid du Colombier if((s = strrchr(r, '/')) && s > r) 11169a747e4fSDavid du Colombier *s = '\0'; 11179a747e4fSDavid du Colombier else if(s == r) 11189a747e4fSDavid du Colombier s[1] = '\0'; 11199a747e4fSDavid du Colombier return r; 1120219b2ee8SDavid du Colombier } 11219a747e4fSDavid du Colombier 11229a747e4fSDavid du Colombier r = emalloc(strlen(p)+1+strlen(q)+1); 11239a747e4fSDavid du Colombier strcpy(r, p); 11249a747e4fSDavid du Colombier if(r[0]=='\0' || r[strlen(r)-1] != '/') 11259a747e4fSDavid du Colombier strcat(r, "/"); 11269a747e4fSDavid du Colombier strcat(r, q); 11279a747e4fSDavid du Colombier return r; 11289a747e4fSDavid du Colombier } 11299a747e4fSDavid du Colombier 11309a747e4fSDavid du Colombier Fid *newfid(int, char**); 11319a747e4fSDavid du Colombier Fid *oldfid(int, char**); 11329a747e4fSDavid du Colombier int fidstat(Fid*, char**); 11339a747e4fSDavid du Colombier void freefid(Fid*); 11349a747e4fSDavid du Colombier 11359a747e4fSDavid du Colombier Fid *fidtab[1]; 11369a747e4fSDavid du Colombier 11379a747e4fSDavid du Colombier Fid* 11389a747e4fSDavid du Colombier lookupfid(int fid) 11399a747e4fSDavid du Colombier { 11409a747e4fSDavid du Colombier Fid *f; 11419a747e4fSDavid du Colombier 11429a747e4fSDavid du Colombier for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 11439a747e4fSDavid du Colombier if(f->fid == fid) 11449a747e4fSDavid du Colombier return f; 11459a747e4fSDavid du Colombier return nil; 11469a747e4fSDavid du Colombier } 11479a747e4fSDavid du Colombier 11489a747e4fSDavid du Colombier Fid* 11499a747e4fSDavid du Colombier newfid(int fid, char **ep) 11509a747e4fSDavid du Colombier { 11519a747e4fSDavid du Colombier Fid *f; 11529a747e4fSDavid du Colombier 11539a747e4fSDavid du Colombier if(lookupfid(fid) != nil){ 11549a747e4fSDavid du Colombier *ep = Efidactive; 11559a747e4fSDavid du Colombier return nil; 11569a747e4fSDavid du Colombier } 11579a747e4fSDavid du Colombier 11589a747e4fSDavid du Colombier f = emalloc(sizeof(*f)); 11599a747e4fSDavid du Colombier f->next = fidtab[fid%nelem(fidtab)]; 11609a747e4fSDavid du Colombier if(f->next) 11619a747e4fSDavid du Colombier f->next->prev = f; 11629a747e4fSDavid du Colombier fidtab[fid%nelem(fidtab)] = f; 11639a747e4fSDavid du Colombier f->fid = fid; 11649a747e4fSDavid du Colombier f->fd = -1; 11659a747e4fSDavid du Colombier f->omode = -1; 11669a747e4fSDavid du Colombier return f; 11679a747e4fSDavid du Colombier } 11689a747e4fSDavid du Colombier 11699a747e4fSDavid du Colombier Fid* 11709a747e4fSDavid du Colombier oldfid(int fid, char **ep) 11719a747e4fSDavid du Colombier { 11729a747e4fSDavid du Colombier Fid *f; 11739a747e4fSDavid du Colombier 11749a747e4fSDavid du Colombier if((f = lookupfid(fid)) == nil){ 11759a747e4fSDavid du Colombier *ep = Ebadfid; 11769a747e4fSDavid du Colombier return nil; 11779a747e4fSDavid du Colombier } 11789a747e4fSDavid du Colombier 11799a747e4fSDavid du Colombier if(userchange(f->u, ep) < 0) 11809a747e4fSDavid du Colombier return nil; 11819a747e4fSDavid du Colombier 11829a747e4fSDavid du Colombier return f; 11839a747e4fSDavid du Colombier } 11849a747e4fSDavid du Colombier 11859a747e4fSDavid du Colombier void 11869a747e4fSDavid du Colombier freefid(Fid *f) 11879a747e4fSDavid du Colombier { 11889a747e4fSDavid du Colombier if(f->prev) 11899a747e4fSDavid du Colombier f->prev->next = f->next; 11909a747e4fSDavid du Colombier else 11919a747e4fSDavid du Colombier fidtab[f->fid%nelem(fidtab)] = f->next; 11929a747e4fSDavid du Colombier if(f->next) 11939a747e4fSDavid du Colombier f->next->prev = f->prev; 11949a747e4fSDavid du Colombier if(f->dir) 11959a747e4fSDavid du Colombier closedir(f->dir); 11969a747e4fSDavid du Colombier if(f->fd) 11979a747e4fSDavid du Colombier close(f->fd); 11989a747e4fSDavid du Colombier free(f->path); 11999a747e4fSDavid du Colombier free(f); 12009a747e4fSDavid du Colombier } 12019a747e4fSDavid du Colombier 12029a747e4fSDavid du Colombier int 12039a747e4fSDavid du Colombier fidstat(Fid *fid, char **ep) 12049a747e4fSDavid du Colombier { 12059a747e4fSDavid du Colombier if(stat(fid->path, &fid->st) < 0){ 12069a747e4fSDavid du Colombier fprint(2, "fidstat(%s) failed\n", fid->path); 12079a747e4fSDavid du Colombier if(ep) 12089a747e4fSDavid du Colombier *ep = strerror(errno); 12099a747e4fSDavid du Colombier return -1; 12109a747e4fSDavid du Colombier } 12119a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)) 12129a747e4fSDavid du Colombier fid->st.st_size = 0; 12139a747e4fSDavid du Colombier return 0; 12149a747e4fSDavid du Colombier } 12159a747e4fSDavid du Colombier 12169a747e4fSDavid du Colombier int 12179a747e4fSDavid du Colombier userchange(User *u, char **ep) 12189a747e4fSDavid du Colombier { 1219*d9306527SDavid du Colombier if(defaultuser) 1220*d9306527SDavid du Colombier return 0; 1221*d9306527SDavid du Colombier 1222*d9306527SDavid du Colombier if(setreuid(0, 0) < 0){ 12239a747e4fSDavid du Colombier fprint(2, "setreuid(0, 0) failed\n"); 12249a747e4fSDavid du Colombier *ep = "cannot setuid back to root"; 12259a747e4fSDavid du Colombier return -1; 12269a747e4fSDavid du Colombier } 12279a747e4fSDavid du Colombier 12289a747e4fSDavid du Colombier /* 12299a747e4fSDavid du Colombier * Initgroups does not appear to be SUSV standard. 12309a747e4fSDavid du Colombier * But it exists on SGI and on Linux, which makes me 12319a747e4fSDavid du Colombier * think it's standard enough. We have to do something 12329a747e4fSDavid du Colombier * like this, and the closest other function I can find is 12339a747e4fSDavid du Colombier * setgroups (which initgroups eventually calls). 12349a747e4fSDavid du Colombier * Setgroups is the same as far as standardization though, 12359a747e4fSDavid du Colombier * so we're stuck using a non-SUSV call. Sigh. 12369a747e4fSDavid du Colombier */ 12379a747e4fSDavid du Colombier if(initgroups(u->name, u->defaultgid) < 0) 12389a747e4fSDavid du Colombier fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 12399a747e4fSDavid du Colombier 12409a747e4fSDavid du Colombier if(setreuid(-1, u->id) < 0){ 12419a747e4fSDavid du Colombier fprint(2, "setreuid(-1, %s) failed\n", u->name); 12429a747e4fSDavid du Colombier *ep = strerror(errno); 12439a747e4fSDavid du Colombier return -1; 12449a747e4fSDavid du Colombier } 12459a747e4fSDavid du Colombier 12469a747e4fSDavid du Colombier return 0; 12479a747e4fSDavid du Colombier } 12489a747e4fSDavid du Colombier 12499a747e4fSDavid du Colombier /* 12509a747e4fSDavid du Colombier * We do our own checking here, then switch to root temporarily 12519a747e4fSDavid du Colombier * to set our gid. In a perfect world, you'd be allowed to set your 12529a747e4fSDavid du Colombier * egid to any of the supplemental groups of your euid, but this 12539a747e4fSDavid du Colombier * is not the case on Linux 2.2.14 (and perhaps others). 12549a747e4fSDavid du Colombier * 12559a747e4fSDavid du Colombier * This is a race, of course, but it's a race against processes 12569a747e4fSDavid du Colombier * that can edit the group lists. If you can do that, you can 12579a747e4fSDavid du Colombier * change your own group without our help. 12589a747e4fSDavid du Colombier */ 12599a747e4fSDavid du Colombier int 12609a747e4fSDavid du Colombier groupchange(User *u, User *g, char **ep) 12619a747e4fSDavid du Colombier { 12629a747e4fSDavid du Colombier if(!useringroup(u, g)){ 12639a747e4fSDavid du Colombier if(chatty9p) 12649a747e4fSDavid du Colombier fprint(2, "%s not in group %s\n", u->name, g->name); 12659a747e4fSDavid du Colombier *ep = Enotingroup; 12669a747e4fSDavid du Colombier return -1; 12679a747e4fSDavid du Colombier } 12689a747e4fSDavid du Colombier 12699a747e4fSDavid du Colombier setreuid(0,0); 12709a747e4fSDavid du Colombier if(setregid(-1, g->id) < 0){ 12719a747e4fSDavid du Colombier fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 12729a747e4fSDavid du Colombier *ep = strerror(errno); 12739a747e4fSDavid du Colombier return -1; 12749a747e4fSDavid du Colombier } 12759a747e4fSDavid du Colombier if(userchange(u, ep) < 0) 12769a747e4fSDavid du Colombier return -1; 12779a747e4fSDavid du Colombier 12789a747e4fSDavid du Colombier return 0; 12799a747e4fSDavid du Colombier } 12809a747e4fSDavid du Colombier 12819a747e4fSDavid du Colombier 12829a747e4fSDavid du Colombier /* 12839a747e4fSDavid du Colombier * An attempt to enforce permissions by looking at the 12849a747e4fSDavid du Colombier * file system. Separation of checking permission and 12859a747e4fSDavid du Colombier * actually performing the action is a terrible idea, of 12869a747e4fSDavid du Colombier * course, so we use setreuid for most of the permission 12879a747e4fSDavid du Colombier * enforcement. This is here only so we can give errors 12889a747e4fSDavid du Colombier * on open(ORCLOSE) in some cases. 12899a747e4fSDavid du Colombier */ 12909a747e4fSDavid du Colombier int 12919a747e4fSDavid du Colombier userperm(User *u, char *path, int type, int need) 12929a747e4fSDavid du Colombier { 12939a747e4fSDavid du Colombier char *p, *q; 12949a747e4fSDavid du Colombier int i, have; 12959a747e4fSDavid du Colombier struct stat st; 12969a747e4fSDavid du Colombier User *g; 12979a747e4fSDavid du Colombier 12989a747e4fSDavid du Colombier switch(type){ 12999a747e4fSDavid du Colombier default: 13009a747e4fSDavid du Colombier fprint(2, "bad type %d in userperm\n", type); 13019a747e4fSDavid du Colombier return -1; 13029a747e4fSDavid du Colombier case Tdot: 13039a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 13049a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) failed\n", path); 13059a747e4fSDavid du Colombier return -1; 13069a747e4fSDavid du Colombier } 13079a747e4fSDavid du Colombier break; 13089a747e4fSDavid du Colombier case Tdotdot: 13099a747e4fSDavid du Colombier p = estrdup(path); 13109a747e4fSDavid du Colombier if((q = strrchr(p, '/'))==nil){ 13119a747e4fSDavid du Colombier fprint(2, "userperm(%s, ..): bad path\n", p); 13129a747e4fSDavid du Colombier free(p); 13139a747e4fSDavid du Colombier return -1; 13149a747e4fSDavid du Colombier } 13159a747e4fSDavid du Colombier if(q > p) 13169a747e4fSDavid du Colombier *q = '\0'; 13179a747e4fSDavid du Colombier else 13189a747e4fSDavid du Colombier *(q+1) = '\0'; 13199a747e4fSDavid du Colombier if(stat(p, &st) < 0){ 13209a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 13219a747e4fSDavid du Colombier p, path); 13229a747e4fSDavid du Colombier free(p); 13239a747e4fSDavid du Colombier return -1; 13249a747e4fSDavid du Colombier } 13259a747e4fSDavid du Colombier free(p); 13269a747e4fSDavid du Colombier break; 13279a747e4fSDavid du Colombier } 13289a747e4fSDavid du Colombier 13299a747e4fSDavid du Colombier if(u == none){ 13309a747e4fSDavid du Colombier fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 13319a747e4fSDavid du Colombier have = st.st_mode&7; 13329a747e4fSDavid du Colombier if((have&need)==need) 13339a747e4fSDavid du Colombier return 0; 13349a747e4fSDavid du Colombier return -1; 13359a747e4fSDavid du Colombier } 13369a747e4fSDavid du Colombier have = st.st_mode&7; 13379a747e4fSDavid du Colombier if((uid_t)u->id == st.st_uid) 13389a747e4fSDavid du Colombier have |= (st.st_mode>>6)&7; 13399a747e4fSDavid du Colombier if((have&need)==need) 13409a747e4fSDavid du Colombier return 0; 13419a747e4fSDavid du Colombier if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 13429a747e4fSDavid du Colombier return -1; 13439a747e4fSDavid du Colombier g = gid2user(st.st_gid); 13449a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++){ 13459a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0){ 13469a747e4fSDavid du Colombier have |= (st.st_mode>>3)&7; 13479a747e4fSDavid du Colombier break; 13489a747e4fSDavid du Colombier } 13499a747e4fSDavid du Colombier } 13509a747e4fSDavid du Colombier if((have&need)==need) 13519a747e4fSDavid du Colombier return 0; 13529a747e4fSDavid du Colombier return -1; 13539a747e4fSDavid du Colombier } 13549a747e4fSDavid du Colombier 13559a747e4fSDavid du Colombier int 13569a747e4fSDavid du Colombier userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 13579a747e4fSDavid du Colombier { 13589a747e4fSDavid du Colombier char *npath; 13599a747e4fSDavid du Colombier struct stat st; 13609a747e4fSDavid du Colombier 13619a747e4fSDavid du Colombier npath = estrpath(*path, elem); 13629a747e4fSDavid du Colombier if(stat(npath, &st) < 0){ 13639a747e4fSDavid du Colombier free(npath); 13649a747e4fSDavid du Colombier *ep = strerror(errno); 13659a747e4fSDavid du Colombier return -1; 13669a747e4fSDavid du Colombier } 13679a747e4fSDavid du Colombier *qid = stat2qid(&st); 13689a747e4fSDavid du Colombier free(*path); 13699a747e4fSDavid du Colombier *path = npath; 13709a747e4fSDavid du Colombier return 0; 13719a747e4fSDavid du Colombier } 13729a747e4fSDavid du Colombier 13739a747e4fSDavid du Colombier int 13749a747e4fSDavid du Colombier useropen(Fid *fid, int omode, char **ep) 13759a747e4fSDavid du Colombier { 13769a747e4fSDavid du Colombier int a, o; 13779a747e4fSDavid du Colombier 13789a747e4fSDavid du Colombier /* 13799a747e4fSDavid du Colombier * Check this anyway, to try to head off problems later. 13809a747e4fSDavid du Colombier */ 13819a747e4fSDavid du Colombier if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 13829a747e4fSDavid du Colombier *ep = Eperm; 13839a747e4fSDavid du Colombier return -1; 13849a747e4fSDavid du Colombier } 13859a747e4fSDavid du Colombier 13869a747e4fSDavid du Colombier switch(omode&3){ 13879a747e4fSDavid du Colombier default: 13889a747e4fSDavid du Colombier *ep = "programmer error"; 13899a747e4fSDavid du Colombier return -1; 13909a747e4fSDavid du Colombier case OREAD: 13919a747e4fSDavid du Colombier a = R_OK; 13929a747e4fSDavid du Colombier o = O_RDONLY; 13939a747e4fSDavid du Colombier break; 13949a747e4fSDavid du Colombier case ORDWR: 13959a747e4fSDavid du Colombier a = R_OK|W_OK; 13969a747e4fSDavid du Colombier o = O_RDWR; 13979a747e4fSDavid du Colombier break; 13989a747e4fSDavid du Colombier case OWRITE: 13999a747e4fSDavid du Colombier a = R_OK; 14009a747e4fSDavid du Colombier o = O_WRONLY; 14019a747e4fSDavid du Colombier break; 14029a747e4fSDavid du Colombier case OEXEC: 14039a747e4fSDavid du Colombier a = X_OK; 14049a747e4fSDavid du Colombier o = O_RDONLY; 14059a747e4fSDavid du Colombier break; 14069a747e4fSDavid du Colombier } 14079a747e4fSDavid du Colombier if(omode & OTRUNC){ 14089a747e4fSDavid du Colombier a |= W_OK; 14099a747e4fSDavid du Colombier o |= O_TRUNC; 14109a747e4fSDavid du Colombier } 14119a747e4fSDavid du Colombier 14129a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)){ 14139a747e4fSDavid du Colombier if(a != R_OK){ 14149a747e4fSDavid du Colombier fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 14159a747e4fSDavid du Colombier *ep = Eperm; 14169a747e4fSDavid du Colombier return -1; 14179a747e4fSDavid du Colombier } 14189a747e4fSDavid du Colombier if((fid->dir = opendir(fid->path)) == nil){ 14199a747e4fSDavid du Colombier *ep = strerror(errno); 14209a747e4fSDavid du Colombier return -1; 14219a747e4fSDavid du Colombier } 14229a747e4fSDavid du Colombier }else{ 14239a747e4fSDavid du Colombier if(access(fid->path, a) < 0){ 14249a747e4fSDavid du Colombier *ep = strerror(errno); 14259a747e4fSDavid du Colombier return -1; 14269a747e4fSDavid du Colombier } 14279a747e4fSDavid du Colombier if((fid->fd = open(fid->path, o)) < 0){ 14289a747e4fSDavid du Colombier *ep = strerror(errno); 14299a747e4fSDavid du Colombier return -1; 14309a747e4fSDavid du Colombier } 14319a747e4fSDavid du Colombier } 14329a747e4fSDavid du Colombier fid->omode = omode; 14339a747e4fSDavid du Colombier return 0; 14349a747e4fSDavid du Colombier } 14359a747e4fSDavid du Colombier 14369a747e4fSDavid du Colombier int 14379a747e4fSDavid du Colombier usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 14389a747e4fSDavid du Colombier { 14399a747e4fSDavid du Colombier int o, m; 14409a747e4fSDavid du Colombier char *opath, *npath; 14419a747e4fSDavid du Colombier struct stat st, parent; 14429a747e4fSDavid du Colombier 14439a747e4fSDavid du Colombier if(stat(fid->path, &parent) < 0){ 14449a747e4fSDavid du Colombier *ep = strerror(errno); 14459a747e4fSDavid du Colombier return -1; 14469a747e4fSDavid du Colombier } 14479a747e4fSDavid du Colombier 14489a747e4fSDavid du Colombier /* 14499a747e4fSDavid du Colombier * Change group so that created file has expected group 14509a747e4fSDavid du Colombier * by Plan 9 semantics. If that fails, might as well go 14519a747e4fSDavid du Colombier * with the user's default group. 14529a747e4fSDavid du Colombier */ 14539a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 14549a747e4fSDavid du Colombier && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 14559a747e4fSDavid du Colombier return -1; 14569a747e4fSDavid du Colombier 14579a747e4fSDavid du Colombier m = (perm & DMDIR) ? 0777 : 0666; 14589a747e4fSDavid du Colombier perm = perm & (~m | (fid->st.st_mode & m)); 14599a747e4fSDavid du Colombier 14609a747e4fSDavid du Colombier npath = estrpath(fid->path, elem); 14619a747e4fSDavid du Colombier if(perm & DMDIR){ 14629a747e4fSDavid du Colombier if((omode&~ORCLOSE) != OREAD){ 14639a747e4fSDavid du Colombier *ep = Eperm; 14649a747e4fSDavid du Colombier free(npath); 14659a747e4fSDavid du Colombier return -1; 14669a747e4fSDavid du Colombier } 14679a747e4fSDavid du Colombier if(stat(npath, &st) >= 0 || errno != ENOENT){ 14689a747e4fSDavid du Colombier *ep = Eexist; 14699a747e4fSDavid du Colombier free(npath); 14709a747e4fSDavid du Colombier return -1; 14719a747e4fSDavid du Colombier } 14729a747e4fSDavid du Colombier /* race */ 14739a747e4fSDavid du Colombier if(mkdir(npath, perm&0777) < 0){ 14749a747e4fSDavid du Colombier *ep = strerror(errno); 14759a747e4fSDavid du Colombier free(npath); 14769a747e4fSDavid du Colombier return -1; 14779a747e4fSDavid du Colombier } 14789a747e4fSDavid du Colombier if((fid->dir = opendir(npath)) == nil){ 14799a747e4fSDavid du Colombier *ep = strerror(errno); 14809a747e4fSDavid du Colombier remove(npath); /* race */ 14819a747e4fSDavid du Colombier free(npath); 14829a747e4fSDavid du Colombier return -1; 14839a747e4fSDavid du Colombier } 14849a747e4fSDavid du Colombier }else{ 14859a747e4fSDavid du Colombier o = O_CREAT|O_EXCL; 14869a747e4fSDavid du Colombier switch(omode&3){ 14879a747e4fSDavid du Colombier default: 14889a747e4fSDavid du Colombier *ep = "programmer error"; 14899a747e4fSDavid du Colombier return -1; 14909a747e4fSDavid du Colombier case OREAD: 14919a747e4fSDavid du Colombier case OEXEC: 14929a747e4fSDavid du Colombier o |= O_RDONLY; 14939a747e4fSDavid du Colombier break; 14949a747e4fSDavid du Colombier case ORDWR: 14959a747e4fSDavid du Colombier o |= O_RDWR; 14969a747e4fSDavid du Colombier break; 14979a747e4fSDavid du Colombier case OWRITE: 14989a747e4fSDavid du Colombier o |= O_WRONLY; 14999a747e4fSDavid du Colombier break; 15009a747e4fSDavid du Colombier } 15019a747e4fSDavid du Colombier if(omode & OTRUNC) 15029a747e4fSDavid du Colombier o |= O_TRUNC; 15039a747e4fSDavid du Colombier if((fid->fd = open(npath, o, perm&0777)) < 0){ 15049a747e4fSDavid du Colombier if(chatty9p) 15059a747e4fSDavid du Colombier fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 15069a747e4fSDavid du Colombier *ep = strerror(errno); 15079a747e4fSDavid du Colombier free(npath); 15089a747e4fSDavid du Colombier return -1; 15099a747e4fSDavid du Colombier } 15109a747e4fSDavid du Colombier } 15119a747e4fSDavid du Colombier 15129a747e4fSDavid du Colombier opath = fid->path; 15139a747e4fSDavid du Colombier fid->path = npath; 15149a747e4fSDavid du Colombier if(fidstat(fid, ep) < 0){ 15159a747e4fSDavid du Colombier fprint(2, "stat after create on %s failed\n", npath); 15169a747e4fSDavid du Colombier remove(npath); /* race */ 15179a747e4fSDavid du Colombier free(npath); 15189a747e4fSDavid du Colombier fid->path = opath; 15199a747e4fSDavid du Colombier if(fid->fd >= 0){ 15209a747e4fSDavid du Colombier close(fid->fd); 15219a747e4fSDavid du Colombier fid->fd = -1; 15229a747e4fSDavid du Colombier }else{ 15239a747e4fSDavid du Colombier closedir(fid->dir); 15249a747e4fSDavid du Colombier fid->dir = nil; 15259a747e4fSDavid du Colombier } 15269a747e4fSDavid du Colombier return -1; 15279a747e4fSDavid du Colombier } 15289a747e4fSDavid du Colombier fid->omode = omode; 15299a747e4fSDavid du Colombier free(opath); 15309a747e4fSDavid du Colombier return 0; 15319a747e4fSDavid du Colombier } 15329a747e4fSDavid du Colombier 15339a747e4fSDavid du Colombier int 15349a747e4fSDavid du Colombier userremove(Fid *fid, char **ep) 15359a747e4fSDavid du Colombier { 15369a747e4fSDavid du Colombier if(remove(fid->path) < 0){ 15379a747e4fSDavid du Colombier *ep = strerror(errno); 15389a747e4fSDavid du Colombier return -1; 15399a747e4fSDavid du Colombier } 15409a747e4fSDavid du Colombier return 0; 15419a747e4fSDavid du Colombier } 15429a747e4fSDavid du Colombier 15439a747e4fSDavid du Colombier void 15449a747e4fSDavid du Colombier usage(void) 15459a747e4fSDavid du Colombier { 15469a747e4fSDavid du Colombier fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 15479a747e4fSDavid du Colombier exit(1); 15489a747e4fSDavid du Colombier } 15499a747e4fSDavid du Colombier 15509a747e4fSDavid du Colombier int 15519a747e4fSDavid du Colombier main(int argc, char **argv) 15529a747e4fSDavid du Colombier { 15539a747e4fSDavid du Colombier char *authtype; 15549a747e4fSDavid du Colombier int i; 15559a747e4fSDavid du Colombier int fd; 15569a747e4fSDavid du Colombier int logflag; 15579a747e4fSDavid du Colombier 15589a747e4fSDavid du Colombier auth = authmethods[0]; 15599a747e4fSDavid du Colombier logflag = O_WRONLY|O_APPEND|O_CREAT; 15609a747e4fSDavid du Colombier ARGBEGIN{ 15619a747e4fSDavid du Colombier case 'D': 15629a747e4fSDavid du Colombier chatty9p = 1; 15639a747e4fSDavid du Colombier break; 15649a747e4fSDavid du Colombier case 'a': 15659a747e4fSDavid du Colombier authtype = EARGF(usage()); 15669a747e4fSDavid du Colombier auth = nil; 15679a747e4fSDavid du Colombier for(i=0; i<nelem(authmethods); i++) 15689a747e4fSDavid du Colombier if(strcmp(authmethods[i]->name, authtype)==0) 15699a747e4fSDavid du Colombier auth = authmethods[i]; 15709a747e4fSDavid du Colombier if(auth == nil) 15719a747e4fSDavid du Colombier sysfatal("unknown auth type '%s'", authtype); 15729a747e4fSDavid du Colombier break; 15739a747e4fSDavid du Colombier case 'A': 15749a747e4fSDavid du Colombier autharg = EARGF(usage()); 15759a747e4fSDavid du Colombier break; 15769a747e4fSDavid du Colombier case 'l': 15779a747e4fSDavid du Colombier logfile = EARGF(usage()); 15789a747e4fSDavid du Colombier break; 15799a747e4fSDavid du Colombier case 'm': 15809a747e4fSDavid du Colombier msize = strtol(EARGF(usage()), 0, 0); 15819a747e4fSDavid du Colombier break; 15829a747e4fSDavid du Colombier case 'n': 15839a747e4fSDavid du Colombier network = 0; 15849a747e4fSDavid du Colombier break; 15859a747e4fSDavid du Colombier case 'u': 15869a747e4fSDavid du Colombier defaultuser = EARGF(usage()); 15879a747e4fSDavid du Colombier break; 15889a747e4fSDavid du Colombier case 'z': 15899a747e4fSDavid du Colombier logflag |= O_TRUNC; 15909a747e4fSDavid du Colombier }ARGEND 15919a747e4fSDavid du Colombier 15929a747e4fSDavid du Colombier if(argc > 1) 15939a747e4fSDavid du Colombier usage(); 15949a747e4fSDavid du Colombier 15959a747e4fSDavid du Colombier fd = open(logfile, logflag, 0666); 15969a747e4fSDavid du Colombier if(fd < 0) 15979a747e4fSDavid du Colombier sysfatal("cannot open log '%s'", logfile); 15989a747e4fSDavid du Colombier 15999a747e4fSDavid du Colombier if(dup2(fd, 2) < 0) 16009a747e4fSDavid du Colombier sysfatal("cannot dup fd onto stderr"); 16019a747e4fSDavid du Colombier fprint(2, "u9fs\nkill %d\n", (int)getpid()); 16029a747e4fSDavid du Colombier 16039a747e4fSDavid du Colombier fmtinstall('F', fcallconv); 16049a747e4fSDavid du Colombier fmtinstall('D', dirconv); 16059a747e4fSDavid du Colombier fmtinstall('M', dirmodeconv); 16069a747e4fSDavid du Colombier 16079a747e4fSDavid du Colombier rxbuf = emalloc(msize); 16089a747e4fSDavid du Colombier txbuf = emalloc(msize); 16099a747e4fSDavid du Colombier databuf = emalloc(msize); 16109a747e4fSDavid du Colombier 16119a747e4fSDavid du Colombier if(auth->init) 16129a747e4fSDavid du Colombier auth->init(); 16139a747e4fSDavid du Colombier 16149a747e4fSDavid du Colombier if(network) 16159a747e4fSDavid du Colombier getremotehostname(remotehostname, sizeof remotehostname); 16169a747e4fSDavid du Colombier 16179a747e4fSDavid du Colombier if(gethostname(hostname, sizeof hostname) < 0) 16189a747e4fSDavid du Colombier strcpy(hostname, "gnot"); 16199a747e4fSDavid du Colombier 16209a747e4fSDavid du Colombier umask(0); 16219a747e4fSDavid du Colombier 16229a747e4fSDavid du Colombier if(argc == 1) 16239a747e4fSDavid du Colombier if(chroot(argv[0]) < 0) 16249a747e4fSDavid du Colombier sysfatal("chroot '%s' failed", argv[0]); 16259a747e4fSDavid du Colombier 16269a747e4fSDavid du Colombier none = uname2user("none"); 16279a747e4fSDavid du Colombier serve(0, 1); 16289a747e4fSDavid du Colombier return 0; 16299a747e4fSDavid du Colombier } 1630