19a747e4fSDavid du Colombier /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */ 2f5736e95SDavid du Colombier /* plan9.h is first to get the large file support definitions as early as possible */ 3f5736e95SDavid du Colombier #include <plan9.h> 49a747e4fSDavid du Colombier #include <sys/stat.h> /* for stat, umask */ 59a747e4fSDavid du Colombier #include <stdlib.h> /* for malloc */ 69a747e4fSDavid du Colombier #include <string.h> /* for strcpy, memmove */ 79a747e4fSDavid du Colombier #include <pwd.h> /* for getpwnam, getpwuid */ 89a747e4fSDavid du Colombier #include <grp.h> /* for getgrnam, getgrgid */ 99a747e4fSDavid du Colombier #include <unistd.h> /* for gethostname, pread, pwrite, read, write */ 109a747e4fSDavid du Colombier #include <utime.h> /* for utime */ 119a747e4fSDavid du Colombier #include <dirent.h> /* for readdir */ 129a747e4fSDavid du Colombier #include <errno.h> /* for errno */ 139a747e4fSDavid du Colombier #include <stdio.h> /* for remove [sic] */ 149a747e4fSDavid du Colombier #include <fcntl.h> /* for O_RDONLY, etc. */ 153e12c5d1SDavid du Colombier 169a747e4fSDavid du Colombier #include <sys/socket.h> /* various networking crud */ 17219b2ee8SDavid du Colombier #include <netinet/in.h> 18219b2ee8SDavid du Colombier #include <netdb.h> 199a747e4fSDavid du Colombier 209a747e4fSDavid du Colombier #include <fcall.h> 219a747e4fSDavid du Colombier #include <oldfcall.h> 229a747e4fSDavid du Colombier #include <u9fs.h> 239a747e4fSDavid du Colombier 249a747e4fSDavid du Colombier /* #ifndef because can be given in makefile */ 259a747e4fSDavid du Colombier #ifndef DEFAULTLOG 269a747e4fSDavid du Colombier #define DEFAULTLOG "/tmp/u9fs.log" 273e12c5d1SDavid du Colombier #endif 283e12c5d1SDavid du Colombier 299a747e4fSDavid du Colombier char *logfile = DEFAULTLOG; 303e12c5d1SDavid du Colombier 319a747e4fSDavid du Colombier #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m)) 329a747e4fSDavid du Colombier 339a747e4fSDavid du Colombier enum { 349a747e4fSDavid du Colombier Tdot = 1, 359a747e4fSDavid du Colombier Tdotdot 363e12c5d1SDavid du Colombier }; 373e12c5d1SDavid du Colombier 389a747e4fSDavid du Colombier enum { 399a747e4fSDavid du Colombier P9P1, 409a747e4fSDavid du Colombier P9P2000 413e12c5d1SDavid du Colombier }; 423e12c5d1SDavid du Colombier 439a747e4fSDavid du Colombier typedef struct User User; 449a747e4fSDavid du Colombier struct User { 453e12c5d1SDavid du Colombier int id; 469a747e4fSDavid du Colombier gid_t defaultgid; 473e12c5d1SDavid du Colombier char *name; 489a747e4fSDavid du Colombier char **mem; /* group members */ 497dd7cddfSDavid du Colombier int nmem; 509a747e4fSDavid du Colombier User *next; 513e12c5d1SDavid du Colombier }; 523e12c5d1SDavid du Colombier 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; 6550a9bdd4SDavid du Colombier int auth; 6650a9bdd4SDavid du Colombier void *authmagic; 679a747e4fSDavid du Colombier }; 683e12c5d1SDavid du Colombier 699a747e4fSDavid du Colombier void* emalloc(size_t); 709a747e4fSDavid du Colombier void* erealloc(void*, size_t); 713e12c5d1SDavid du Colombier char* estrdup(char*); 72*dfda52d8SDavid du Colombier char* estrpath(char*, char*, int); 739a747e4fSDavid du Colombier void sysfatal(char*, ...); 749a747e4fSDavid du Colombier int okuser(char*); 753e12c5d1SDavid du Colombier 769a747e4fSDavid du Colombier void rversion(Fcall*, Fcall*); 779a747e4fSDavid du Colombier void rauth(Fcall*, Fcall*); 789a747e4fSDavid du Colombier void rattach(Fcall*, Fcall*); 799a747e4fSDavid du Colombier void rflush(Fcall*, Fcall*); 809a747e4fSDavid du Colombier void rclone(Fcall*, Fcall*); 819a747e4fSDavid du Colombier void rwalk(Fcall*, Fcall*); 829a747e4fSDavid du Colombier void ropen(Fcall*, Fcall*); 839a747e4fSDavid du Colombier void rcreate(Fcall*, Fcall*); 849a747e4fSDavid du Colombier void rread(Fcall*, Fcall*); 859a747e4fSDavid du Colombier void rwrite(Fcall*, Fcall*); 869a747e4fSDavid du Colombier void rclunk(Fcall*, Fcall*); 879a747e4fSDavid du Colombier void rstat(Fcall*, Fcall*); 889a747e4fSDavid du Colombier void rwstat(Fcall*, Fcall*); 899a747e4fSDavid du Colombier void rclwalk(Fcall*, Fcall*); 909a747e4fSDavid du Colombier void rremove(Fcall*, Fcall*); 919a747e4fSDavid du Colombier 929a747e4fSDavid du Colombier User* uname2user(char*); 939a747e4fSDavid du Colombier User* gname2user(char*); 949a747e4fSDavid du Colombier User* uid2user(int); 959a747e4fSDavid du Colombier User* gid2user(int); 969a747e4fSDavid du Colombier 979a747e4fSDavid du Colombier Fid* newfid(int, char**); 9850a9bdd4SDavid du Colombier Fid* oldfidex(int, int, char**); 999a747e4fSDavid du Colombier Fid* oldfid(int, char**); 1009a747e4fSDavid du Colombier int fidstat(Fid*, char**); 1019a747e4fSDavid du Colombier void freefid(Fid*); 1029a747e4fSDavid du Colombier 1039a747e4fSDavid du Colombier int userchange(User*, char**); 1049a747e4fSDavid du Colombier int userwalk(User*, char**, char*, Qid*, char**); 1059a747e4fSDavid du Colombier int useropen(Fid*, int, char**); 1069a747e4fSDavid du Colombier int usercreate(Fid*, char*, int, long, char**); 1079a747e4fSDavid du Colombier int userremove(Fid*, char**); 1089a747e4fSDavid du Colombier int userperm(User*, char*, int, int); 1099a747e4fSDavid du Colombier int useringroup(User*, User*); 1109a747e4fSDavid du Colombier 1119a747e4fSDavid du Colombier Qid stat2qid(struct stat*); 1129a747e4fSDavid du Colombier 1139a747e4fSDavid du Colombier void getfcallold(int, Fcall*, int); 1149a747e4fSDavid du Colombier void putfcallold(int, Fcall*); 1153e12c5d1SDavid du Colombier 1163e12c5d1SDavid du Colombier char Eauth[] = "authentication failed"; 1173e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range"; 1189a747e4fSDavid du Colombier char Ebadoffset[] = "bad offset in directory read"; 1199a747e4fSDavid du Colombier char Ebadusefid[] = "bad use of fid"; 1209a747e4fSDavid du Colombier char Edirchange[] = "wstat can't convert between files and directories"; 1219a747e4fSDavid du Colombier char Eexist[] = "file or directory already exists"; 1223e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use"; 1239a747e4fSDavid du Colombier char Enotdir[] = "not a directory"; 1249a747e4fSDavid du Colombier char Enotingroup[] = "not a member of proposed group"; 1259a747e4fSDavid du Colombier char Enotowner[] = "only owner can change group in wstat"; 1269a747e4fSDavid du Colombier char Eperm[] = "permission denied"; 1273e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files"; 1283e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files"; 1299a747e4fSDavid du Colombier char Especial[] = "no access to special file"; 1303e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large"; 1319a747e4fSDavid du Colombier char Eunknowngroup[] = "unknown group"; 1329a747e4fSDavid du Colombier char Eunknownuser[] = "unknown user"; 1339a747e4fSDavid du Colombier char Ewstatbuffer[] = "bogus wstat buffer"; 1349a747e4fSDavid du Colombier 1359a747e4fSDavid du Colombier ulong msize = IOHDRSZ+8192; 1369a747e4fSDavid du Colombier uchar* rxbuf; 1379a747e4fSDavid du Colombier uchar* txbuf; 1389a747e4fSDavid du Colombier void* databuf; 1399a747e4fSDavid du Colombier int connected; 1409a747e4fSDavid du Colombier int devallowed; 1419a747e4fSDavid du Colombier char* autharg; 1429a747e4fSDavid du Colombier char* defaultuser; 1439a747e4fSDavid du Colombier char hostname[256]; 1449a747e4fSDavid du Colombier char remotehostname[256]; 1459a747e4fSDavid du Colombier int chatty9p = 0; 1469a747e4fSDavid du Colombier int network = 1; 1479a747e4fSDavid du Colombier int old9p = -1; 1489a747e4fSDavid du Colombier int authed; 1499a747e4fSDavid du Colombier User* none; 1509a747e4fSDavid du Colombier 1519a747e4fSDavid du Colombier Auth *authmethods[] = { /* first is default */ 1529a747e4fSDavid du Colombier &authrhosts, 15350a9bdd4SDavid du Colombier &authp9any, 1549a747e4fSDavid du Colombier &authnone, 1559a747e4fSDavid du Colombier }; 1569a747e4fSDavid du Colombier 1579a747e4fSDavid du Colombier Auth *auth; 1583e12c5d1SDavid du Colombier 159*dfda52d8SDavid du Colombier /* 160*dfda52d8SDavid du Colombier * frogs: characters not valid in plan9 161*dfda52d8SDavid du Colombier * filenames, keep this list in sync with 162*dfda52d8SDavid du Colombier * /sys/src/9/port/chan.c:1656 163*dfda52d8SDavid du Colombier */ 164*dfda52d8SDavid du Colombier char isfrog[256]={ 165*dfda52d8SDavid du Colombier /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, 166*dfda52d8SDavid du Colombier /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, 167*dfda52d8SDavid du Colombier /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, 168*dfda52d8SDavid du Colombier /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, 169*dfda52d8SDavid du Colombier ['/'] 1, 170*dfda52d8SDavid du Colombier [0x7f] 1, 171*dfda52d8SDavid du Colombier }; 172*dfda52d8SDavid du Colombier 1737dd7cddfSDavid du Colombier void 1749a747e4fSDavid du Colombier getfcallnew(int fd, Fcall *fc, int have) 1757dd7cddfSDavid du Colombier { 1769a747e4fSDavid du Colombier int len; 1779a747e4fSDavid du Colombier 1789a747e4fSDavid du Colombier if(have > BIT32SZ) 1799a747e4fSDavid du Colombier sysfatal("cannot happen"); 1809a747e4fSDavid du Colombier 1819a747e4fSDavid du Colombier if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) 1829a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1839a747e4fSDavid du Colombier 1849a747e4fSDavid du Colombier len = GBIT32(rxbuf); 1859a747e4fSDavid du Colombier if(len <= BIT32SZ) 1869a747e4fSDavid du Colombier sysfatal("bogus message"); 1879a747e4fSDavid du Colombier 1889a747e4fSDavid du Colombier len -= BIT32SZ; 1899a747e4fSDavid du Colombier if(readn(fd, rxbuf+BIT32SZ, len) != len) 1909a747e4fSDavid du Colombier sysfatal("short message"); 1919a747e4fSDavid du Colombier 1929a747e4fSDavid du Colombier if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) 1939a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 1949a747e4fSDavid du Colombier } 1959a747e4fSDavid du Colombier 1969a747e4fSDavid du Colombier void 1979a747e4fSDavid du Colombier getfcallold(int fd, Fcall *fc, int have) 1989a747e4fSDavid du Colombier { 1999a747e4fSDavid du Colombier int len, n; 2009a747e4fSDavid du Colombier 2019a747e4fSDavid du Colombier if(have > 3) 2029a747e4fSDavid du Colombier sysfatal("cannot happen"); 2039a747e4fSDavid du Colombier 2049a747e4fSDavid du Colombier if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) 2059a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2069a747e4fSDavid du Colombier 2079a747e4fSDavid du Colombier len = oldhdrsize(rxbuf[0]); 2089a747e4fSDavid du Colombier if(len < 3) 2099a747e4fSDavid du Colombier sysfatal("bad message %d", rxbuf[0]); 2109a747e4fSDavid du Colombier if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) 2119a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2129a747e4fSDavid du Colombier 2139a747e4fSDavid du Colombier n = iosize(rxbuf); 2149a747e4fSDavid du Colombier if(readn(fd, rxbuf+len, n) != n) 2159a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2169a747e4fSDavid du Colombier len += n; 2179a747e4fSDavid du Colombier 2189a747e4fSDavid du Colombier if(convM2Sold(rxbuf, len, fc) != len) 2199a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 2209a747e4fSDavid du Colombier } 2219a747e4fSDavid du Colombier 2229a747e4fSDavid du Colombier void 2239a747e4fSDavid du Colombier putfcallnew(int wfd, Fcall *tx) 2249a747e4fSDavid du Colombier { 2259a747e4fSDavid du Colombier uint n; 2269a747e4fSDavid du Colombier 2279a747e4fSDavid du Colombier if((n = convS2M(tx, txbuf, msize)) == 0) 2289a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2299a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2309a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2319a747e4fSDavid du Colombier } 2329a747e4fSDavid du Colombier 2339a747e4fSDavid du Colombier void 2349a747e4fSDavid du Colombier putfcallold(int wfd, Fcall *tx) 2359a747e4fSDavid du Colombier { 2369a747e4fSDavid du Colombier uint n; 2379a747e4fSDavid du Colombier 2389a747e4fSDavid du Colombier if((n = convS2Mold(tx, txbuf, msize)) == 0) 2399a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2409a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2419a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2429a747e4fSDavid du Colombier } 2439a747e4fSDavid du Colombier 2449a747e4fSDavid du Colombier void 2459a747e4fSDavid du Colombier getfcall(int fd, Fcall *fc) 2469a747e4fSDavid du Colombier { 2479a747e4fSDavid du Colombier if(old9p == 1){ 2489a747e4fSDavid du Colombier getfcallold(fd, fc, 0); 2499a747e4fSDavid du Colombier return; 2509a747e4fSDavid du Colombier } 2519a747e4fSDavid du Colombier if(old9p == 0){ 2529a747e4fSDavid du Colombier getfcallnew(fd, fc, 0); 2539a747e4fSDavid du Colombier return; 2549a747e4fSDavid du Colombier } 2559a747e4fSDavid du Colombier 2569a747e4fSDavid du Colombier /* auto-detect */ 2579a747e4fSDavid du Colombier if(readn(fd, rxbuf, 3) != 3) 2589a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2599a747e4fSDavid du Colombier 2609a747e4fSDavid du Colombier /* is it an old (9P1) message? */ 2619a747e4fSDavid du Colombier if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ 2629a747e4fSDavid du Colombier old9p = 1; 2639a747e4fSDavid du Colombier getfcallold(fd, fc, 3); 2649a747e4fSDavid du Colombier return; 2659a747e4fSDavid du Colombier } 2669a747e4fSDavid du Colombier 2679a747e4fSDavid du Colombier getfcallnew(fd, fc, 3); 2689a747e4fSDavid du Colombier old9p = 0; 2699a747e4fSDavid du Colombier } 2709a747e4fSDavid du Colombier 2719a747e4fSDavid du Colombier void 2729a747e4fSDavid du Colombier seterror(Fcall *f, char *error) 2739a747e4fSDavid du Colombier { 2749a747e4fSDavid du Colombier f->type = Rerror; 2759a747e4fSDavid du Colombier f->ename = error ? error : "programmer error"; 2767dd7cddfSDavid du Colombier } 2777dd7cddfSDavid du Colombier 2783e12c5d1SDavid du Colombier int 2799a747e4fSDavid du Colombier isowner(User *u, Fid *f) 2803e12c5d1SDavid du Colombier { 2819a747e4fSDavid du Colombier return u->id == f->st.st_uid; 2823e12c5d1SDavid du Colombier } 2833e12c5d1SDavid du Colombier 2849df35464SDavid du Colombier 2859df35464SDavid du Colombier 2863e12c5d1SDavid du Colombier void 2879a747e4fSDavid du Colombier serve(int rfd, int wfd) 2883e12c5d1SDavid du Colombier { 2899a747e4fSDavid du Colombier Fcall rx, tx; 2903e12c5d1SDavid du Colombier 2913e12c5d1SDavid du Colombier for(;;){ 2929a747e4fSDavid du Colombier getfcall(rfd, &rx); 2933e12c5d1SDavid du Colombier 2949a747e4fSDavid du Colombier if(chatty9p) 2959a747e4fSDavid du Colombier fprint(2, "<- %F\n", &rx); 2969a747e4fSDavid du Colombier 2979a747e4fSDavid du Colombier memset(&tx, 0, sizeof tx); 2989a747e4fSDavid du Colombier tx.type = rx.type+1; 2999a747e4fSDavid du Colombier tx.tag = rx.tag; 3009a747e4fSDavid du Colombier switch(rx.type){ 3019a747e4fSDavid du Colombier case Tflush: 3023e12c5d1SDavid du Colombier break; 3039a747e4fSDavid du Colombier case Tversion: 3049a747e4fSDavid du Colombier rversion(&rx, &tx); 3059a747e4fSDavid du Colombier break; 3069a747e4fSDavid du Colombier case Tauth: 3079a747e4fSDavid du Colombier rauth(&rx, &tx); 3083e12c5d1SDavid du Colombier break; 3093e12c5d1SDavid du Colombier case Tattach: 3109a747e4fSDavid du Colombier rattach(&rx, &tx); 3113e12c5d1SDavid du Colombier break; 3123e12c5d1SDavid du Colombier case Twalk: 3139a747e4fSDavid du Colombier rwalk(&rx, &tx); 3143e12c5d1SDavid du Colombier break; 3153e12c5d1SDavid du Colombier case Tstat: 3169a747e4fSDavid du Colombier tx.stat = databuf; 3179a747e4fSDavid du Colombier rstat(&rx, &tx); 3183e12c5d1SDavid du Colombier break; 3193e12c5d1SDavid du Colombier case Twstat: 3209a747e4fSDavid du Colombier rwstat(&rx, &tx); 3213e12c5d1SDavid du Colombier break; 3223e12c5d1SDavid du Colombier case Topen: 3239a747e4fSDavid du Colombier ropen(&rx, &tx); 3243e12c5d1SDavid du Colombier break; 3253e12c5d1SDavid du Colombier case Tcreate: 3269a747e4fSDavid du Colombier rcreate(&rx, &tx); 3273e12c5d1SDavid du Colombier break; 3283e12c5d1SDavid du Colombier case Tread: 3299a747e4fSDavid du Colombier tx.data = databuf; 3309a747e4fSDavid du Colombier rread(&rx, &tx); 3313e12c5d1SDavid du Colombier break; 3323e12c5d1SDavid du Colombier case Twrite: 3339a747e4fSDavid du Colombier rwrite(&rx, &tx); 3343e12c5d1SDavid du Colombier break; 3353e12c5d1SDavid du Colombier case Tclunk: 3369a747e4fSDavid du Colombier rclunk(&rx, &tx); 3373e12c5d1SDavid du Colombier break; 3383e12c5d1SDavid du Colombier case Tremove: 3399a747e4fSDavid du Colombier rremove(&rx, &tx); 3403e12c5d1SDavid du Colombier break; 3413e12c5d1SDavid du Colombier default: 3429a747e4fSDavid du Colombier fprint(2, "unknown message %F\n", &rx); 3439a747e4fSDavid du Colombier seterror(&tx, "bad message"); 3449a747e4fSDavid du Colombier break; 3453e12c5d1SDavid du Colombier } 3469a747e4fSDavid du Colombier 3479a747e4fSDavid du Colombier if(chatty9p) 3489a747e4fSDavid du Colombier fprint(2, "-> %F\n", &tx); 3499a747e4fSDavid du Colombier 3509a747e4fSDavid du Colombier (old9p ? putfcallold : putfcallnew)(wfd, &tx); 3519a747e4fSDavid du Colombier } 3523e12c5d1SDavid du Colombier } 3533e12c5d1SDavid du Colombier 3543e12c5d1SDavid du Colombier void 3559a747e4fSDavid du Colombier rversion(Fcall *rx, Fcall *tx) 3563e12c5d1SDavid du Colombier { 3579a747e4fSDavid du Colombier if(msize > rx->msize) 3589a747e4fSDavid du Colombier msize = rx->msize; 3599a747e4fSDavid du Colombier tx->msize = msize; 3609a747e4fSDavid du Colombier if(strncmp(rx->version, "9P", 2) != 0) 3619a747e4fSDavid du Colombier tx->version = "unknown"; 3629a747e4fSDavid du Colombier else 3639a747e4fSDavid du Colombier tx->version = "9P2000"; 3643e12c5d1SDavid du Colombier } 3653e12c5d1SDavid du Colombier 3663e12c5d1SDavid du Colombier void 3679a747e4fSDavid du Colombier rauth(Fcall *rx, Fcall *tx) 3683e12c5d1SDavid du Colombier { 3699a747e4fSDavid du Colombier char *e; 3703e12c5d1SDavid du Colombier 3719a747e4fSDavid du Colombier if((e = auth->auth(rx, tx)) != nil) 3729a747e4fSDavid du Colombier seterror(tx, e); 3733e12c5d1SDavid du Colombier } 3749a747e4fSDavid du Colombier 3759a747e4fSDavid du Colombier void 3769a747e4fSDavid du Colombier rattach(Fcall *rx, Fcall *tx) 3779a747e4fSDavid du Colombier { 3789a747e4fSDavid du Colombier char *e; 3799a747e4fSDavid du Colombier Fid *fid; 3809a747e4fSDavid du Colombier User *u; 3819a747e4fSDavid du Colombier 3829a747e4fSDavid du Colombier if(rx->aname == nil) 3839a747e4fSDavid du Colombier rx->aname = ""; 3849a747e4fSDavid du Colombier 3859a747e4fSDavid du Colombier if(strcmp(rx->aname, "device") == 0){ 3869a747e4fSDavid du Colombier if(connected && !devallowed){ 3879a747e4fSDavid du Colombier seterror(tx, Especial0); 3889a747e4fSDavid du Colombier return; 3899a747e4fSDavid du Colombier } 3903e12c5d1SDavid du Colombier devallowed = 1; 3913e12c5d1SDavid du Colombier }else{ 3929a747e4fSDavid du Colombier if(connected && devallowed){ 3939a747e4fSDavid du Colombier seterror(tx, Especial1); 3949a747e4fSDavid du Colombier return; 3953e12c5d1SDavid du Colombier } 3969a747e4fSDavid du Colombier } 3979a747e4fSDavid du Colombier 3989a747e4fSDavid du Colombier if(strcmp(rx->uname, "none") == 0){ 3999a747e4fSDavid du Colombier if(authed == 0){ 4009a747e4fSDavid du Colombier seterror(tx, Eauth); 4019a747e4fSDavid du Colombier return; 4029a747e4fSDavid du Colombier } 4039a747e4fSDavid du Colombier } else { 4049a747e4fSDavid du Colombier if((e = auth->attach(rx, tx)) != nil){ 4059a747e4fSDavid du Colombier seterror(tx, e); 4069a747e4fSDavid du Colombier return; 4079a747e4fSDavid du Colombier } 4089a747e4fSDavid du Colombier authed++; 4099a747e4fSDavid du Colombier } 4109a747e4fSDavid du Colombier 4119a747e4fSDavid du Colombier if((fid = newfid(rx->fid, &e)) == nil){ 4129a747e4fSDavid du Colombier seterror(tx, e); 4139a747e4fSDavid du Colombier return; 4149a747e4fSDavid du Colombier } 4159a747e4fSDavid du Colombier fid->path = estrdup("/"); 4169a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4179a747e4fSDavid du Colombier seterror(tx, e); 4189a747e4fSDavid du Colombier freefid(fid); 4199a747e4fSDavid du Colombier return; 4209a747e4fSDavid du Colombier } 4219a747e4fSDavid du Colombier 4229a747e4fSDavid du Colombier if(defaultuser) 4239a747e4fSDavid du Colombier rx->uname = defaultuser; 4249a747e4fSDavid du Colombier 425fa1160edSDavid du Colombier if((u = uname2user(rx->uname)) == nil 426fa1160edSDavid du Colombier || (!defaultuser && u->id == 0)){ 4279a747e4fSDavid du Colombier /* we don't know anyone named root... */ 4289a747e4fSDavid du Colombier seterror(tx, Eunknownuser); 4299a747e4fSDavid du Colombier freefid(fid); 4309a747e4fSDavid du Colombier return; 4319a747e4fSDavid du Colombier } 4329a747e4fSDavid du Colombier 4339a747e4fSDavid du Colombier fid->u = u; 4349a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 4359a747e4fSDavid du Colombier return; 4363e12c5d1SDavid du Colombier } 4373e12c5d1SDavid du Colombier 4383e12c5d1SDavid du Colombier void 4399a747e4fSDavid du Colombier rwalk(Fcall *rx, Fcall *tx) 4403e12c5d1SDavid du Colombier { 4419a747e4fSDavid du Colombier int i; 4429a747e4fSDavid du Colombier char *path, *e; 4439a747e4fSDavid du Colombier Fid *fid, *nfid; 4443e12c5d1SDavid du Colombier 4459a747e4fSDavid du Colombier e = nil; 4469a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 4479a747e4fSDavid du Colombier seterror(tx, e); 4489a747e4fSDavid du Colombier return; 4493e12c5d1SDavid du Colombier } 4503e12c5d1SDavid du Colombier 4519a747e4fSDavid du Colombier if(fid->omode != -1){ 4529a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 4539a747e4fSDavid du Colombier return; 4543e12c5d1SDavid du Colombier } 4553e12c5d1SDavid du Colombier 4569a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4579a747e4fSDavid du Colombier seterror(tx, e); 4589a747e4fSDavid du Colombier return; 4599a747e4fSDavid du Colombier } 4603e12c5d1SDavid du Colombier 4619a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ 4629a747e4fSDavid du Colombier seterror(tx, Enotdir); 4639a747e4fSDavid du Colombier return; 4649a747e4fSDavid du Colombier } 4659a747e4fSDavid du Colombier 4669a747e4fSDavid du Colombier nfid = nil; 4679a747e4fSDavid du Colombier if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ 4689a747e4fSDavid du Colombier seterror(tx, e); 4699a747e4fSDavid du Colombier return; 4709a747e4fSDavid du Colombier } 4719a747e4fSDavid du Colombier 4729a747e4fSDavid du Colombier path = estrdup(fid->path); 4739a747e4fSDavid du Colombier e = nil; 4749a747e4fSDavid du Colombier for(i=0; i<rx->nwname; i++) 4759a747e4fSDavid du Colombier if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) 4763e12c5d1SDavid du Colombier break; 4773e12c5d1SDavid du Colombier 4789a747e4fSDavid du Colombier if(i == rx->nwname){ /* successful clone or walk */ 4799a747e4fSDavid du Colombier tx->nwqid = i; 4809a747e4fSDavid du Colombier if(nfid){ 4819a747e4fSDavid du Colombier nfid->path = path; 4829a747e4fSDavid du Colombier nfid->u = fid->u; 4833e12c5d1SDavid du Colombier }else{ 4849a747e4fSDavid du Colombier free(fid->path); 4859a747e4fSDavid du Colombier fid->path = path; 4863e12c5d1SDavid du Colombier } 4879a747e4fSDavid du Colombier }else{ 4889a747e4fSDavid du Colombier if(i > 0) /* partial walk? */ 4899a747e4fSDavid du Colombier tx->nwqid = i; 4909a747e4fSDavid du Colombier else 4919a747e4fSDavid du Colombier seterror(tx, e); 4929a747e4fSDavid du Colombier 4939a747e4fSDavid du Colombier if(nfid) /* clone implicit new fid */ 4949a747e4fSDavid du Colombier freefid(nfid); 4959a747e4fSDavid du Colombier free(path); 4963e12c5d1SDavid du Colombier } 4979a747e4fSDavid du Colombier return; 4983e12c5d1SDavid du Colombier } 4993e12c5d1SDavid du Colombier 5003e12c5d1SDavid du Colombier void 5019a747e4fSDavid du Colombier ropen(Fcall *rx, Fcall *tx) 5023e12c5d1SDavid du Colombier { 5039a747e4fSDavid du Colombier char *e; 5049a747e4fSDavid du Colombier Fid *fid; 5053e12c5d1SDavid du Colombier 5069a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 5079a747e4fSDavid du Colombier seterror(tx, e); 5089a747e4fSDavid du Colombier return; 5093e12c5d1SDavid du Colombier } 5109a747e4fSDavid du Colombier 5119a747e4fSDavid du Colombier if(fid->omode != -1){ 5129a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 5139a747e4fSDavid du Colombier return; 5143e12c5d1SDavid du Colombier } 5159a747e4fSDavid du Colombier 5169a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5179a747e4fSDavid du Colombier seterror(tx, e); 5189a747e4fSDavid du Colombier return; 5193e12c5d1SDavid du Colombier } 5209a747e4fSDavid du Colombier 5219a747e4fSDavid du Colombier if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ 5229a747e4fSDavid du Colombier seterror(tx, Especial); 5239a747e4fSDavid du Colombier return; 5243e12c5d1SDavid du Colombier } 5259a747e4fSDavid du Colombier 5269a747e4fSDavid du Colombier if(useropen(fid, rx->mode, &e) < 0){ 5279a747e4fSDavid du Colombier seterror(tx, e); 5289a747e4fSDavid du Colombier return; 5293e12c5d1SDavid du Colombier } 5309a747e4fSDavid du Colombier 5319a747e4fSDavid du Colombier tx->iounit = 0; 5329a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5333e12c5d1SDavid du Colombier } 5343e12c5d1SDavid du Colombier 5353e12c5d1SDavid du Colombier void 5369a747e4fSDavid du Colombier rcreate(Fcall *rx, Fcall *tx) 5373e12c5d1SDavid du Colombier { 5389a747e4fSDavid du Colombier char *e; 5399a747e4fSDavid du Colombier Fid *fid; 5409a747e4fSDavid du Colombier 5419a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 5429a747e4fSDavid du Colombier seterror(tx, e); 5439a747e4fSDavid du Colombier return; 5449a747e4fSDavid du Colombier } 5459a747e4fSDavid du Colombier 5469a747e4fSDavid du Colombier if(fid->omode != -1){ 5479a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 5489a747e4fSDavid du Colombier return; 5499a747e4fSDavid du Colombier } 5509a747e4fSDavid du Colombier 5519a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5529a747e4fSDavid du Colombier seterror(tx, e); 5539a747e4fSDavid du Colombier return; 5549a747e4fSDavid du Colombier } 5559a747e4fSDavid du Colombier 5569a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode)){ 5579a747e4fSDavid du Colombier seterror(tx, Enotdir); 5589a747e4fSDavid du Colombier return; 5599a747e4fSDavid du Colombier } 5609a747e4fSDavid du Colombier 5619a747e4fSDavid du Colombier if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ 5629a747e4fSDavid du Colombier seterror(tx, e); 5639a747e4fSDavid du Colombier return; 5649a747e4fSDavid du Colombier } 5659a747e4fSDavid du Colombier 5669a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5679a747e4fSDavid du Colombier seterror(tx, e); 5689a747e4fSDavid du Colombier return; 5699a747e4fSDavid du Colombier } 5709a747e4fSDavid du Colombier 5719a747e4fSDavid du Colombier tx->iounit = 0; 5729a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5739a747e4fSDavid du Colombier } 5749a747e4fSDavid du Colombier 5759a747e4fSDavid du Colombier uchar 5769a747e4fSDavid du Colombier modebyte(struct stat *st) 5779a747e4fSDavid du Colombier { 5789a747e4fSDavid du Colombier uchar b; 5799a747e4fSDavid du Colombier 5809a747e4fSDavid du Colombier b = 0; 5819a747e4fSDavid du Colombier 5829a747e4fSDavid du Colombier if(S_ISDIR(st->st_mode)) 5839a747e4fSDavid du Colombier b |= QTDIR; 5849a747e4fSDavid du Colombier 5859a747e4fSDavid du Colombier /* no way to test append-only */ 5869a747e4fSDavid du Colombier /* no real way to test exclusive use, but mark devices as such */ 5879a747e4fSDavid du Colombier if(S_ISSPECIAL(st->st_mode)) 5889a747e4fSDavid du Colombier b |= QTEXCL; 5899a747e4fSDavid du Colombier 5909a747e4fSDavid du Colombier return b; 5919a747e4fSDavid du Colombier } 5929a747e4fSDavid du Colombier 5939a747e4fSDavid du Colombier ulong 5949a747e4fSDavid du Colombier plan9mode(struct stat *st) 5959a747e4fSDavid du Colombier { 5969a747e4fSDavid du Colombier return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777); 5979a747e4fSDavid du Colombier } 5989a747e4fSDavid du Colombier 5999a747e4fSDavid du Colombier /* 6009a747e4fSDavid du Colombier * this is for chmod, so don't worry about S_IFDIR 6019a747e4fSDavid du Colombier */ 6029a747e4fSDavid du Colombier mode_t 6039a747e4fSDavid du Colombier unixmode(Dir *d) 6049a747e4fSDavid du Colombier { 6059a747e4fSDavid du Colombier return (mode_t)(d->mode&0777); 6069a747e4fSDavid du Colombier } 6079a747e4fSDavid du Colombier 6089a747e4fSDavid du Colombier Qid 6099a747e4fSDavid du Colombier stat2qid(struct stat *st) 6109a747e4fSDavid du Colombier { 6119a747e4fSDavid du Colombier uchar *p, *ep, *q; 6129a747e4fSDavid du Colombier Qid qid; 6139a747e4fSDavid du Colombier 6149a747e4fSDavid du Colombier /* 6159a747e4fSDavid du Colombier * For now, ignore the device number. 6169a747e4fSDavid du Colombier */ 6179a747e4fSDavid du Colombier qid.path = 0; 6189a747e4fSDavid du Colombier p = (uchar*)&qid.path; 6199a747e4fSDavid du Colombier ep = p+sizeof(qid.path); 6209a747e4fSDavid du Colombier q = p+sizeof(ino_t); 6219a747e4fSDavid du Colombier if(q > ep){ 6229a747e4fSDavid du Colombier fprint(2, "warning: inode number too big\n"); 6239a747e4fSDavid du Colombier q = ep; 6249a747e4fSDavid du Colombier } 6259a747e4fSDavid du Colombier memmove(p, &st->st_ino, q-p); 6269a747e4fSDavid du Colombier q = q+sizeof(dev_t); 6279a747e4fSDavid du Colombier if(q > ep){ 628*dfda52d8SDavid du Colombier /* 629*dfda52d8SDavid du Colombier * fprint(2, "warning: inode number + device number too big %d+%d\n", 630*dfda52d8SDavid du Colombier * sizeof(ino_t), sizeof(dev_t)); 631*dfda52d8SDavid du Colombier */ 6329a747e4fSDavid du Colombier q = ep - sizeof(dev_t); 6339a747e4fSDavid du Colombier if(q < p) 6349a747e4fSDavid du Colombier fprint(2, "warning: device number too big by itself\n"); 6359a747e4fSDavid du Colombier else 6369a747e4fSDavid du Colombier *(dev_t*)q ^= st->st_dev; 6379a747e4fSDavid du Colombier } 6389a747e4fSDavid du Colombier 6399a747e4fSDavid du Colombier qid.vers = st->st_mtime ^ (st->st_size << 8); 6409a747e4fSDavid du Colombier qid.type = modebyte(st); 6419a747e4fSDavid du Colombier return qid; 6429a747e4fSDavid du Colombier } 6439a747e4fSDavid du Colombier 644*dfda52d8SDavid du Colombier char * 645*dfda52d8SDavid du Colombier enfrog(char *src) 646*dfda52d8SDavid du Colombier { 647*dfda52d8SDavid du Colombier char *d, *dst; 648*dfda52d8SDavid du Colombier uchar *s; 649*dfda52d8SDavid du Colombier 650*dfda52d8SDavid du Colombier d = dst = emalloc(strlen(src)*3 + 1); 651*dfda52d8SDavid du Colombier for (s = (uchar *)src; *s; s++) 652*dfda52d8SDavid du Colombier if(isfrog[*s] || *s == '\\') 653*dfda52d8SDavid du Colombier d += sprintf(d, "\\%02x", *s); 654*dfda52d8SDavid du Colombier else 655*dfda52d8SDavid du Colombier *d++ = *s; 656*dfda52d8SDavid du Colombier *d = 0; 657*dfda52d8SDavid du Colombier return dst; 658*dfda52d8SDavid du Colombier } 659*dfda52d8SDavid du Colombier 660*dfda52d8SDavid du Colombier char * 661*dfda52d8SDavid du Colombier defrog(char *s) 662*dfda52d8SDavid du Colombier { 663*dfda52d8SDavid du Colombier char *d, *dst, buf[3]; 664*dfda52d8SDavid du Colombier 665*dfda52d8SDavid du Colombier d = dst = emalloc(strlen(s) + 1); 666*dfda52d8SDavid du Colombier for(; *s; s++) 667*dfda52d8SDavid du Colombier if(*s == '\\' && strlen(s) >= 3){ 668*dfda52d8SDavid du Colombier buf[0] = *++s; /* skip \ */ 669*dfda52d8SDavid du Colombier buf[1] = *++s; 670*dfda52d8SDavid du Colombier buf[2] = 0; 671*dfda52d8SDavid du Colombier *d++ = strtoul(buf, NULL, 16); 672*dfda52d8SDavid du Colombier } else 673*dfda52d8SDavid du Colombier *d++ = *s; 674*dfda52d8SDavid du Colombier *d = 0; 675*dfda52d8SDavid du Colombier return dst; 676*dfda52d8SDavid du Colombier } 677*dfda52d8SDavid du Colombier 6789a747e4fSDavid du Colombier void 6799a747e4fSDavid du Colombier stat2dir(char *path, struct stat *st, Dir *d) 6809a747e4fSDavid du Colombier { 6819a747e4fSDavid du Colombier User *u; 682*dfda52d8SDavid du Colombier char *q, *p, *npath; 6839a747e4fSDavid du Colombier 6849a747e4fSDavid du Colombier memset(d, 0, sizeof(*d)); 6859a747e4fSDavid du Colombier d->qid = stat2qid(st); 6869a747e4fSDavid du Colombier d->mode = plan9mode(st); 6879a747e4fSDavid du Colombier d->atime = st->st_atime; 6889a747e4fSDavid du Colombier d->mtime = st->st_mtime; 6899a747e4fSDavid du Colombier d->length = st->st_size; 6909a747e4fSDavid du Colombier 6919a747e4fSDavid du Colombier d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; 6929a747e4fSDavid du Colombier d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; 6939a747e4fSDavid du Colombier d->muid = ""; 6949a747e4fSDavid du Colombier 6959a747e4fSDavid du Colombier if((q = strrchr(path, '/')) != nil) 696*dfda52d8SDavid du Colombier d->name = enfrog(q+1); 6979a747e4fSDavid du Colombier else 698*dfda52d8SDavid du Colombier d->name = enfrog(path); 6999a747e4fSDavid du Colombier } 7009a747e4fSDavid du Colombier 7019a747e4fSDavid du Colombier void 7029a747e4fSDavid du Colombier rread(Fcall *rx, Fcall *tx) 7039a747e4fSDavid du Colombier { 7049a747e4fSDavid du Colombier char *e, *path; 7059a747e4fSDavid du Colombier uchar *p, *ep; 7069a747e4fSDavid du Colombier int n; 7079a747e4fSDavid du Colombier Fid *fid; 7083e12c5d1SDavid du Colombier Dir d; 7099a747e4fSDavid du Colombier struct stat st; 7103e12c5d1SDavid du Colombier 7119a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 7129a747e4fSDavid du Colombier seterror(tx, Etoolarge); 7139a747e4fSDavid du Colombier return; 7143e12c5d1SDavid du Colombier } 7159a747e4fSDavid du Colombier 71650a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 71750a9bdd4SDavid du Colombier seterror(tx, e); 71850a9bdd4SDavid du Colombier return; 71950a9bdd4SDavid du Colombier } 72050a9bdd4SDavid du Colombier 72150a9bdd4SDavid du Colombier if (fid->auth) { 72250a9bdd4SDavid du Colombier char *e; 72350a9bdd4SDavid du Colombier e = auth->read(rx, tx); 72450a9bdd4SDavid du Colombier if (e) 7259a747e4fSDavid du Colombier seterror(tx, e); 7269a747e4fSDavid du Colombier return; 7273e12c5d1SDavid du Colombier } 7289a747e4fSDavid du Colombier 7299a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OWRITE){ 7309a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 7319a747e4fSDavid du Colombier return; 7329a747e4fSDavid du Colombier } 7339a747e4fSDavid du Colombier 7349a747e4fSDavid du Colombier if(fid->dir){ 7359a747e4fSDavid du Colombier if(rx->offset != fid->diroffset){ 7369a747e4fSDavid du Colombier if(rx->offset != 0){ 7379a747e4fSDavid du Colombier seterror(tx, Ebadoffset); 7389a747e4fSDavid du Colombier return; 7399a747e4fSDavid du Colombier } 7409a747e4fSDavid du Colombier rewinddir(fid->dir); 7419a747e4fSDavid du Colombier fid->diroffset = 0; 7429a747e4fSDavid du Colombier } 7439a747e4fSDavid du Colombier 7449a747e4fSDavid du Colombier p = (uchar*)tx->data; 7459a747e4fSDavid du Colombier ep = (uchar*)tx->data+rx->count; 7469a747e4fSDavid du Colombier for(;;){ 7479a747e4fSDavid du Colombier if(p+BIT16SZ >= ep) 7483e12c5d1SDavid du Colombier break; 7499a747e4fSDavid du Colombier if(fid->dirent == nil) /* one entry cache for when convD2M fails */ 7509a747e4fSDavid du Colombier if((fid->dirent = readdir(fid->dir)) == nil) 7519a747e4fSDavid du Colombier break; 7529a747e4fSDavid du Colombier if(strcmp(fid->dirent->d_name, ".") == 0 7539a747e4fSDavid du Colombier || strcmp(fid->dirent->d_name, "..") == 0){ 7549a747e4fSDavid du Colombier fid->dirent = nil; 7553e12c5d1SDavid du Colombier continue; 7569a747e4fSDavid du Colombier } 757*dfda52d8SDavid du Colombier path = estrpath(fid->path, fid->dirent->d_name, 0); 7589a747e4fSDavid du Colombier memset(&st, 0, sizeof st); 7599a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 7609a747e4fSDavid du Colombier fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); 7619a747e4fSDavid du Colombier fid->dirent = nil; 7629a747e4fSDavid du Colombier free(path); 7633e12c5d1SDavid du Colombier continue; 7643e12c5d1SDavid du Colombier } 7653e12c5d1SDavid du Colombier free(path); 7669a747e4fSDavid du Colombier stat2dir(fid->dirent->d_name, &st, &d); 7679a747e4fSDavid du Colombier if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) 7689a747e4fSDavid du Colombier break; 7699a747e4fSDavid du Colombier p += n; 7709a747e4fSDavid du Colombier fid->dirent = nil; 7713e12c5d1SDavid du Colombier } 7729a747e4fSDavid du Colombier tx->count = p - (uchar*)tx->data; 7739a747e4fSDavid du Colombier fid->diroffset += tx->count; 7743e12c5d1SDavid du Colombier }else{ 7759a747e4fSDavid du Colombier if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ 7769a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 7779a747e4fSDavid du Colombier return; 778219b2ee8SDavid du Colombier } 7799a747e4fSDavid du Colombier tx->count = n; 7803e12c5d1SDavid du Colombier } 7813e12c5d1SDavid du Colombier } 7823e12c5d1SDavid du Colombier 7833e12c5d1SDavid du Colombier void 7849a747e4fSDavid du Colombier rwrite(Fcall *rx, Fcall *tx) 7853e12c5d1SDavid du Colombier { 7869a747e4fSDavid du Colombier char *e; 7879a747e4fSDavid du Colombier Fid *fid; 7883e12c5d1SDavid du Colombier int n; 7893e12c5d1SDavid du Colombier 7909a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 7919a747e4fSDavid du Colombier seterror(tx, Etoolarge); 7927dd7cddfSDavid du Colombier return; 7937dd7cddfSDavid du Colombier } 7949a747e4fSDavid du Colombier 79550a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 79650a9bdd4SDavid du Colombier seterror(tx, e); 79750a9bdd4SDavid du Colombier return; 79850a9bdd4SDavid du Colombier } 79950a9bdd4SDavid du Colombier 80050a9bdd4SDavid du Colombier if (fid->auth) { 80150a9bdd4SDavid du Colombier char *e; 80250a9bdd4SDavid du Colombier e = auth->write(rx, tx); 80350a9bdd4SDavid du Colombier if (e) 8049a747e4fSDavid du Colombier seterror(tx, e); 8059a747e4fSDavid du Colombier return; 8063e12c5d1SDavid du Colombier } 8079a747e4fSDavid du Colombier 8089a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ 8099a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 8109a747e4fSDavid du Colombier return; 8119a747e4fSDavid du Colombier } 8129a747e4fSDavid du Colombier 8139a747e4fSDavid du Colombier if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ 8149a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 8159a747e4fSDavid du Colombier return; 8169a747e4fSDavid du Colombier } 8179a747e4fSDavid du Colombier tx->count = n; 8183e12c5d1SDavid du Colombier } 8193e12c5d1SDavid du Colombier 8203e12c5d1SDavid du Colombier void 8219a747e4fSDavid du Colombier rclunk(Fcall *rx, Fcall *tx) 8223e12c5d1SDavid du Colombier { 8239a747e4fSDavid du Colombier char *e; 8249a747e4fSDavid du Colombier Fid *fid; 8253e12c5d1SDavid du Colombier 82650a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 8279a747e4fSDavid du Colombier seterror(tx, e); 8289a747e4fSDavid du Colombier return; 8299a747e4fSDavid du Colombier } 83050a9bdd4SDavid du Colombier if (fid->auth) { 83150a9bdd4SDavid du Colombier if (auth->clunk) { 83250a9bdd4SDavid du Colombier e = (*auth->clunk)(rx, tx); 83350a9bdd4SDavid du Colombier if (e) { 83450a9bdd4SDavid du Colombier seterror(tx, e); 83550a9bdd4SDavid du Colombier return; 83650a9bdd4SDavid du Colombier } 83750a9bdd4SDavid du Colombier } 83850a9bdd4SDavid du Colombier } 83950a9bdd4SDavid du Colombier else if(fid->omode != -1 && fid->omode&ORCLOSE) 8409a747e4fSDavid du Colombier remove(fid->path); 8419a747e4fSDavid du Colombier freefid(fid); 8423e12c5d1SDavid du Colombier } 843219b2ee8SDavid du Colombier 8449a747e4fSDavid du Colombier void 8459a747e4fSDavid du Colombier rremove(Fcall *rx, Fcall *tx) 8463e12c5d1SDavid du Colombier { 8479a747e4fSDavid du Colombier char *e; 8489a747e4fSDavid du Colombier Fid *fid; 8493e12c5d1SDavid du Colombier 8509a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8519a747e4fSDavid du Colombier seterror(tx, e); 8529a747e4fSDavid du Colombier return; 8533e12c5d1SDavid du Colombier } 8549a747e4fSDavid du Colombier if(userremove(fid, &e) < 0) 8559a747e4fSDavid du Colombier seterror(tx, e); 8569a747e4fSDavid du Colombier freefid(fid); 8579a747e4fSDavid du Colombier } 8589a747e4fSDavid du Colombier 8599a747e4fSDavid du Colombier void 8609a747e4fSDavid du Colombier rstat(Fcall *rx, Fcall *tx) 8619a747e4fSDavid du Colombier { 8629a747e4fSDavid du Colombier char *e; 8639a747e4fSDavid du Colombier Fid *fid; 8649a747e4fSDavid du Colombier Dir d; 8659a747e4fSDavid du Colombier 8669a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8679a747e4fSDavid du Colombier seterror(tx, e); 8689a747e4fSDavid du Colombier return; 8699a747e4fSDavid du Colombier } 8709a747e4fSDavid du Colombier 8719a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 8729a747e4fSDavid du Colombier seterror(tx, e); 8739a747e4fSDavid du Colombier return; 8749a747e4fSDavid du Colombier } 8759a747e4fSDavid du Colombier 8769a747e4fSDavid du Colombier stat2dir(fid->path, &fid->st, &d); 8779a747e4fSDavid du Colombier if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) 8789a747e4fSDavid du Colombier seterror(tx, "convD2M fails"); 8799a747e4fSDavid du Colombier } 8809a747e4fSDavid du Colombier 8819a747e4fSDavid du Colombier void 8829a747e4fSDavid du Colombier rwstat(Fcall *rx, Fcall *tx) 8839a747e4fSDavid du Colombier { 8849a747e4fSDavid du Colombier char *e; 8859a747e4fSDavid du Colombier char *p, *old, *new, *dir; 8869a747e4fSDavid du Colombier gid_t gid; 8879a747e4fSDavid du Colombier Dir d; 8889a747e4fSDavid du Colombier Fid *fid; 8899a747e4fSDavid du Colombier 8909a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8919a747e4fSDavid du Colombier seterror(tx, e); 8929a747e4fSDavid du Colombier return; 8939a747e4fSDavid du Colombier } 8949a747e4fSDavid du Colombier 8959a747e4fSDavid du Colombier /* 8969a747e4fSDavid du Colombier * wstat is supposed to be atomic. 8979a747e4fSDavid du Colombier * we check all the things we can before trying anything. 8989a747e4fSDavid du Colombier * still, if we are told to truncate a file and rename it and only 8999a747e4fSDavid du Colombier * one works, we're screwed. in such cases we leave things 9009a747e4fSDavid du Colombier * half broken and return an error. it's hardly perfect. 9019a747e4fSDavid du Colombier */ 9029a747e4fSDavid du Colombier if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ 9039a747e4fSDavid du Colombier seterror(tx, Ewstatbuffer); 9049a747e4fSDavid du Colombier return; 9059a747e4fSDavid du Colombier } 9069a747e4fSDavid du Colombier 9079a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 9089a747e4fSDavid du Colombier seterror(tx, e); 9099a747e4fSDavid du Colombier return; 9109a747e4fSDavid du Colombier } 9119a747e4fSDavid du Colombier 9129a747e4fSDavid du Colombier /* 9139a747e4fSDavid du Colombier * The casting is necessary because d.mode is ulong and might, 9149a747e4fSDavid du Colombier * on some systems, be 64 bits. We only want to compare the 9159a747e4fSDavid du Colombier * bottom 32 bits, since that's all that gets sent in the protocol. 9169a747e4fSDavid du Colombier * 9179a747e4fSDavid du Colombier * Same situation for d.mtime and d.length (although that last check 9189a747e4fSDavid du Colombier * is admittedly superfluous, given the current lack of 128-bit machines). 9199a747e4fSDavid du Colombier */ 9209a747e4fSDavid du Colombier gid = (gid_t)-1; 9219a747e4fSDavid du Colombier if(d.gid[0] != '\0'){ 9229a747e4fSDavid du Colombier User *g; 9239a747e4fSDavid du Colombier 9249a747e4fSDavid du Colombier g = gname2user(d.gid); 9259a747e4fSDavid du Colombier if(g == nil){ 9269a747e4fSDavid du Colombier seterror(tx, Eunknowngroup); 9279a747e4fSDavid du Colombier return; 9289a747e4fSDavid du Colombier } 9299a747e4fSDavid du Colombier gid = (gid_t)g->id; 9309a747e4fSDavid du Colombier 9319a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(gid), &e) < 0){ 9329a747e4fSDavid du Colombier seterror(tx, e); 9339a747e4fSDavid du Colombier return; 9349a747e4fSDavid du Colombier } 9359a747e4fSDavid du Colombier } 9369a747e4fSDavid du Colombier 9379a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ 9389a747e4fSDavid du Colombier seterror(tx, Edirchange); 9399a747e4fSDavid du Colombier return; 9409a747e4fSDavid du Colombier } 9419a747e4fSDavid du Colombier 9429a747e4fSDavid du Colombier if(strcmp(fid->path, "/") == 0){ 9439a747e4fSDavid du Colombier seterror(tx, "no wstat of root"); 9449a747e4fSDavid du Colombier return; 9459a747e4fSDavid du Colombier } 9469a747e4fSDavid du Colombier 9479a747e4fSDavid du Colombier /* 9489a747e4fSDavid du Colombier * try things in increasing order of harm to the file. 9499a747e4fSDavid du Colombier * mtime should come after truncate so that if you 9509a747e4fSDavid du Colombier * do both the mtime actually takes effect, but i'd rather 9519a747e4fSDavid du Colombier * leave truncate until last. 9529a747e4fSDavid du Colombier * (see above comment about atomicity). 9539a747e4fSDavid du Colombier */ 9549a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ 9559a747e4fSDavid du Colombier if(chatty9p) 9569a747e4fSDavid du Colombier fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); 9579a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9589a747e4fSDavid du Colombier return; 9599a747e4fSDavid du Colombier } 9609a747e4fSDavid du Colombier 9619a747e4fSDavid du Colombier if((u32int)d.mtime != (u32int)~0){ 9629a747e4fSDavid du Colombier struct utimbuf t; 9639a747e4fSDavid du Colombier 9649a747e4fSDavid du Colombier t.actime = 0; 9659a747e4fSDavid du Colombier t.modtime = d.mtime; 9669a747e4fSDavid du Colombier if(utime(fid->path, &t) < 0){ 9679a747e4fSDavid du Colombier if(chatty9p) 9689a747e4fSDavid du Colombier fprint(2, "utime(%s) failed\n", fid->path); 9699a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9709a747e4fSDavid du Colombier return; 9719a747e4fSDavid du Colombier } 9729a747e4fSDavid du Colombier } 9739a747e4fSDavid du Colombier 9749a747e4fSDavid du Colombier if(gid != (gid_t)-1 && gid != fid->st.st_gid){ 9759a747e4fSDavid du Colombier if(chown(fid->path, (uid_t)-1, gid) < 0){ 9769a747e4fSDavid du Colombier if(chatty9p) 9779a747e4fSDavid du Colombier fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); 9789a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9799a747e4fSDavid du Colombier return; 9809a747e4fSDavid du Colombier } 9819a747e4fSDavid du Colombier } 9829a747e4fSDavid du Colombier 9839a747e4fSDavid du Colombier if(d.name[0]){ 9849a747e4fSDavid du Colombier old = fid->path; 9859a747e4fSDavid du Colombier dir = estrdup(fid->path); 9869a747e4fSDavid du Colombier if((p = strrchr(dir, '/')) > dir) 9879a747e4fSDavid du Colombier *p = '\0'; 9883e12c5d1SDavid du Colombier else{ 9899a747e4fSDavid du Colombier seterror(tx, "whoops: can't happen in u9fs"); 9909a747e4fSDavid du Colombier return; 9913e12c5d1SDavid du Colombier } 992*dfda52d8SDavid du Colombier new = estrpath(dir, d.name, 1); 9939a747e4fSDavid du Colombier if(strcmp(old, new) != 0 && rename(old, new) < 0){ 9949a747e4fSDavid du Colombier if(chatty9p) 9959a747e4fSDavid du Colombier fprint(2, "rename(%s, %s) failed\n", old, new); 9969a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9979a747e4fSDavid du Colombier free(new); 9989a747e4fSDavid du Colombier free(dir); 9999a747e4fSDavid du Colombier return; 10009a747e4fSDavid du Colombier } 10019a747e4fSDavid du Colombier fid->path = new; 10029a747e4fSDavid du Colombier free(old); 10039a747e4fSDavid du Colombier free(dir); 10049a747e4fSDavid du Colombier } 10059a747e4fSDavid du Colombier 10069a747e4fSDavid du Colombier if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ 10079a747e4fSDavid du Colombier fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); 10089a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 10099a747e4fSDavid du Colombier return; 10109a747e4fSDavid du Colombier } 10119a747e4fSDavid du Colombier } 10129a747e4fSDavid du Colombier 10139a747e4fSDavid du Colombier /* 10149a747e4fSDavid du Colombier * we keep a table by numeric id. by name lookups happen infrequently 10159a747e4fSDavid du Colombier * while by-number lookups happen once for every directory entry read 10169a747e4fSDavid du Colombier * and every stat request. 10179a747e4fSDavid du Colombier */ 10189a747e4fSDavid du Colombier User *utab[64]; 10199a747e4fSDavid du Colombier User *gtab[64]; 10209a747e4fSDavid du Colombier 10219a747e4fSDavid du Colombier User* 10229a747e4fSDavid du Colombier adduser(struct passwd *p) 10233e12c5d1SDavid du Colombier { 10249a747e4fSDavid du Colombier User *u; 10253e12c5d1SDavid du Colombier 10269a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 10279a747e4fSDavid du Colombier u->id = p->pw_uid; 10289a747e4fSDavid du Colombier u->name = estrdup(p->pw_name); 10299a747e4fSDavid du Colombier u->next = utab[p->pw_uid%nelem(utab)]; 10309a747e4fSDavid du Colombier u->defaultgid = p->pw_gid; 10319a747e4fSDavid du Colombier utab[p->pw_uid%nelem(utab)] = u; 10329a747e4fSDavid du Colombier return u; 10333e12c5d1SDavid du Colombier } 10343e12c5d1SDavid du Colombier 10353e12c5d1SDavid du Colombier int 10369a747e4fSDavid du Colombier useringroup(User *u, User *g) 10373e12c5d1SDavid du Colombier { 10389a747e4fSDavid du Colombier int i; 10399a747e4fSDavid du Colombier 10409a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++) 10419a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0) 10423e12c5d1SDavid du Colombier return 1; 10439a747e4fSDavid du Colombier 10449a747e4fSDavid du Colombier /* 10459a747e4fSDavid du Colombier * Hack around common Unix problem that everyone has 10469a747e4fSDavid du Colombier * default group "user" but /etc/group lists no members. 10479a747e4fSDavid du Colombier */ 10489a747e4fSDavid du Colombier if(u->defaultgid == g->id) 10499a747e4fSDavid du Colombier return 1; 10503e12c5d1SDavid du Colombier return 0; 10513e12c5d1SDavid du Colombier } 10523e12c5d1SDavid du Colombier 10539a747e4fSDavid du Colombier User* 10549a747e4fSDavid du Colombier addgroup(struct group *g) 10553e12c5d1SDavid du Colombier { 10569a747e4fSDavid du Colombier User *u; 10579a747e4fSDavid du Colombier char **p; 10583e12c5d1SDavid du Colombier int n; 10593e12c5d1SDavid du Colombier 10609a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 10619a747e4fSDavid du Colombier n = 0; 10629a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 10639a747e4fSDavid du Colombier n++; 10649a747e4fSDavid du Colombier u->mem = emalloc(sizeof(u->mem[0])*n); 10659a747e4fSDavid du Colombier n = 0; 10669a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 10679a747e4fSDavid du Colombier u->mem[n++] = estrdup(*p); 10689a747e4fSDavid du Colombier u->nmem = n; 10699a747e4fSDavid du Colombier u->id = g->gr_gid; 10709a747e4fSDavid du Colombier u->name = estrdup(g->gr_name); 10719a747e4fSDavid du Colombier u->next = gtab[g->gr_gid%nelem(gtab)]; 10729a747e4fSDavid du Colombier gtab[g->gr_gid%nelem(gtab)] = u; 10739a747e4fSDavid du Colombier return u; 10743e12c5d1SDavid du Colombier } 10753e12c5d1SDavid du Colombier 10769a747e4fSDavid du Colombier User* 10779a747e4fSDavid du Colombier uname2user(char *name) 10787dd7cddfSDavid du Colombier { 10797dd7cddfSDavid du Colombier int i; 10809a747e4fSDavid du Colombier User *u; 10819a747e4fSDavid du Colombier struct passwd *p; 10827dd7cddfSDavid du Colombier 10839a747e4fSDavid du Colombier for(i=0; i<nelem(utab); i++) 10849a747e4fSDavid du Colombier for(u=utab[i]; u; u=u->next) 10859a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 10869a747e4fSDavid du Colombier return u; 10879a747e4fSDavid du Colombier 10889a747e4fSDavid du Colombier if((p = getpwnam(name)) == nil) 10899a747e4fSDavid du Colombier return nil; 10909a747e4fSDavid du Colombier return adduser(p); 10917dd7cddfSDavid du Colombier } 10927dd7cddfSDavid du Colombier 10939a747e4fSDavid du Colombier User* 10949a747e4fSDavid du Colombier uid2user(int id) 10959a747e4fSDavid du Colombier { 10969a747e4fSDavid du Colombier User *u; 10979a747e4fSDavid du Colombier struct passwd *p; 10989a747e4fSDavid du Colombier 10999a747e4fSDavid du Colombier for(u=utab[id%nelem(utab)]; u; u=u->next) 11009a747e4fSDavid du Colombier if(u->id == id) 11019a747e4fSDavid du Colombier return u; 11029a747e4fSDavid du Colombier 11039a747e4fSDavid du Colombier if((p = getpwuid(id)) == nil) 11049a747e4fSDavid du Colombier return nil; 11059a747e4fSDavid du Colombier return adduser(p); 11069a747e4fSDavid du Colombier } 11079a747e4fSDavid du Colombier 11089a747e4fSDavid du Colombier User* 11099a747e4fSDavid du Colombier gname2user(char *name) 11103e12c5d1SDavid du Colombier { 11113e12c5d1SDavid du Colombier int i; 11129a747e4fSDavid du Colombier User *u; 11139a747e4fSDavid du Colombier struct group *g; 11143e12c5d1SDavid du Colombier 11159a747e4fSDavid du Colombier for(i=0; i<nelem(gtab); i++) 11169a747e4fSDavid du Colombier for(u=gtab[i]; u; u=u->next) 11179a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 11189a747e4fSDavid du Colombier return u; 11199a747e4fSDavid du Colombier 11209a747e4fSDavid du Colombier if((g = getgrnam(name)) == nil) 11219a747e4fSDavid du Colombier return nil; 11229a747e4fSDavid du Colombier return addgroup(g); 11239a747e4fSDavid du Colombier } 11249a747e4fSDavid du Colombier 11259a747e4fSDavid du Colombier User* 11269a747e4fSDavid du Colombier gid2user(int id) 11279a747e4fSDavid du Colombier { 11289a747e4fSDavid du Colombier User *u; 11299a747e4fSDavid du Colombier struct group *g; 11309a747e4fSDavid du Colombier 11319a747e4fSDavid du Colombier for(u=gtab[id%nelem(gtab)]; u; u=u->next) 11329a747e4fSDavid du Colombier if(u->id == id) 11339a747e4fSDavid du Colombier return u; 11349a747e4fSDavid du Colombier 11359a747e4fSDavid du Colombier if((g = getgrgid(id)) == nil) 11369a747e4fSDavid du Colombier return nil; 11379a747e4fSDavid du Colombier return addgroup(g); 11383e12c5d1SDavid du Colombier } 11393e12c5d1SDavid du Colombier 11403e12c5d1SDavid du Colombier void 11419a747e4fSDavid du Colombier sysfatal(char *fmt, ...) 11423e12c5d1SDavid du Colombier { 11439a747e4fSDavid du Colombier char buf[1024]; 11449df35464SDavid du Colombier va_list va, temp; 11453e12c5d1SDavid du Colombier 11469a747e4fSDavid du Colombier va_start(va, fmt); 11479df35464SDavid du Colombier va_copy(temp, va); 11489df35464SDavid du Colombier doprint(buf, buf+sizeof buf, fmt, &temp); 11499df35464SDavid du Colombier va_end(temp); 11509a747e4fSDavid du Colombier va_end(va); 11519a747e4fSDavid du Colombier fprint(2, "u9fs: %s\n", buf); 11529a747e4fSDavid du Colombier fprint(2, "last unix error: %s\n", strerror(errno)); 11533e12c5d1SDavid du Colombier exit(1); 11543e12c5d1SDavid du Colombier } 11553e12c5d1SDavid du Colombier 11563e12c5d1SDavid du Colombier void* 11579a747e4fSDavid du Colombier emalloc(size_t n) 11589a747e4fSDavid du Colombier { 11599a747e4fSDavid du Colombier void *p; 11609a747e4fSDavid du Colombier 1161d9306527SDavid du Colombier if(n == 0) 1162d9306527SDavid du Colombier n = 1; 11639a747e4fSDavid du Colombier p = malloc(n); 11649a747e4fSDavid du Colombier if(p == 0) 11659a747e4fSDavid du Colombier sysfatal("malloc(%ld) fails", (long)n); 11669a747e4fSDavid du Colombier memset(p, 0, n); 11679a747e4fSDavid du Colombier return p; 11689a747e4fSDavid du Colombier } 11699a747e4fSDavid du Colombier 11709a747e4fSDavid du Colombier void* 11719a747e4fSDavid du Colombier erealloc(void *p, size_t n) 11723e12c5d1SDavid du Colombier { 11733e12c5d1SDavid du Colombier if(p == 0) 11743e12c5d1SDavid du Colombier p = malloc(n); 11753e12c5d1SDavid du Colombier else 11763e12c5d1SDavid du Colombier p = realloc(p, n); 11773e12c5d1SDavid du Colombier if(p == 0) 11789a747e4fSDavid du Colombier sysfatal("realloc(..., %ld) fails", (long)n); 11793e12c5d1SDavid du Colombier return p; 11803e12c5d1SDavid du Colombier } 11813e12c5d1SDavid du Colombier 11823e12c5d1SDavid du Colombier char* 11833e12c5d1SDavid du Colombier estrdup(char *p) 11843e12c5d1SDavid du Colombier { 11853e12c5d1SDavid du Colombier p = strdup(p); 11863e12c5d1SDavid du Colombier if(p == 0) 11879a747e4fSDavid du Colombier sysfatal("strdup(%.20s) fails", p); 11883e12c5d1SDavid du Colombier return p; 11893e12c5d1SDavid du Colombier } 1190219b2ee8SDavid du Colombier 11919a747e4fSDavid du Colombier char* 1192*dfda52d8SDavid du Colombier estrpath(char *p, char *q, int frog) 1193219b2ee8SDavid du Colombier { 11949a747e4fSDavid du Colombier char *r, *s; 1195219b2ee8SDavid du Colombier 11969a747e4fSDavid du Colombier if(strcmp(q, "..") == 0){ 11979a747e4fSDavid du Colombier r = estrdup(p); 11989a747e4fSDavid du Colombier if((s = strrchr(r, '/')) && s > r) 11999a747e4fSDavid du Colombier *s = '\0'; 12009a747e4fSDavid du Colombier else if(s == r) 12019a747e4fSDavid du Colombier s[1] = '\0'; 12029a747e4fSDavid du Colombier return r; 1203219b2ee8SDavid du Colombier } 12049a747e4fSDavid du Colombier 1205*dfda52d8SDavid du Colombier if(frog) 1206*dfda52d8SDavid du Colombier q = defrog(q); 1207*dfda52d8SDavid du Colombier else 1208*dfda52d8SDavid du Colombier q = strdup(q); 12099a747e4fSDavid du Colombier r = emalloc(strlen(p)+1+strlen(q)+1); 12109a747e4fSDavid du Colombier strcpy(r, p); 12119a747e4fSDavid du Colombier if(r[0]=='\0' || r[strlen(r)-1] != '/') 12129a747e4fSDavid du Colombier strcat(r, "/"); 12139a747e4fSDavid du Colombier strcat(r, q); 1214*dfda52d8SDavid du Colombier free(q); 12159a747e4fSDavid du Colombier return r; 12169a747e4fSDavid du Colombier } 12179a747e4fSDavid du Colombier 12189a747e4fSDavid du Colombier Fid *fidtab[1]; 12199a747e4fSDavid du Colombier 12209a747e4fSDavid du Colombier Fid* 12219a747e4fSDavid du Colombier lookupfid(int fid) 12229a747e4fSDavid du Colombier { 12239a747e4fSDavid du Colombier Fid *f; 12249a747e4fSDavid du Colombier 12259a747e4fSDavid du Colombier for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 12269a747e4fSDavid du Colombier if(f->fid == fid) 12279a747e4fSDavid du Colombier return f; 12289a747e4fSDavid du Colombier return nil; 12299a747e4fSDavid du Colombier } 12309a747e4fSDavid du Colombier 12319a747e4fSDavid du Colombier Fid* 12329a747e4fSDavid du Colombier newfid(int fid, char **ep) 12339a747e4fSDavid du Colombier { 12349a747e4fSDavid du Colombier Fid *f; 12359a747e4fSDavid du Colombier 12369a747e4fSDavid du Colombier if(lookupfid(fid) != nil){ 12379a747e4fSDavid du Colombier *ep = Efidactive; 12389a747e4fSDavid du Colombier return nil; 12399a747e4fSDavid du Colombier } 12409a747e4fSDavid du Colombier 12419a747e4fSDavid du Colombier f = emalloc(sizeof(*f)); 12429a747e4fSDavid du Colombier f->next = fidtab[fid%nelem(fidtab)]; 12439a747e4fSDavid du Colombier if(f->next) 12449a747e4fSDavid du Colombier f->next->prev = f; 12459a747e4fSDavid du Colombier fidtab[fid%nelem(fidtab)] = f; 12469a747e4fSDavid du Colombier f->fid = fid; 12479a747e4fSDavid du Colombier f->fd = -1; 12489a747e4fSDavid du Colombier f->omode = -1; 12499a747e4fSDavid du Colombier return f; 12509a747e4fSDavid du Colombier } 12519a747e4fSDavid du Colombier 12529a747e4fSDavid du Colombier Fid* 125350a9bdd4SDavid du Colombier newauthfid(int fid, void *magic, char **ep) 125450a9bdd4SDavid du Colombier { 125550a9bdd4SDavid du Colombier Fid *af; 125650a9bdd4SDavid du Colombier af = newfid(fid, ep); 125750a9bdd4SDavid du Colombier if (af == nil) 125850a9bdd4SDavid du Colombier return nil; 125950a9bdd4SDavid du Colombier af->auth = 1; 126050a9bdd4SDavid du Colombier af->authmagic = magic; 126150a9bdd4SDavid du Colombier return af; 126250a9bdd4SDavid du Colombier } 126350a9bdd4SDavid du Colombier 126450a9bdd4SDavid du Colombier Fid* 126550a9bdd4SDavid du Colombier oldfidex(int fid, int auth, char **ep) 12669a747e4fSDavid du Colombier { 12679a747e4fSDavid du Colombier Fid *f; 12689a747e4fSDavid du Colombier 12699a747e4fSDavid du Colombier if((f = lookupfid(fid)) == nil){ 12709a747e4fSDavid du Colombier *ep = Ebadfid; 12719a747e4fSDavid du Colombier return nil; 12729a747e4fSDavid du Colombier } 12739a747e4fSDavid du Colombier 127450a9bdd4SDavid du Colombier if (auth != -1 && f->auth != auth) { 127550a9bdd4SDavid du Colombier *ep = Ebadfid; 127650a9bdd4SDavid du Colombier return nil; 127750a9bdd4SDavid du Colombier } 127850a9bdd4SDavid du Colombier 127950a9bdd4SDavid du Colombier if (!f->auth) { 12809a747e4fSDavid du Colombier if(userchange(f->u, ep) < 0) 12819a747e4fSDavid du Colombier return nil; 128250a9bdd4SDavid du Colombier } 12839a747e4fSDavid du Colombier 12849a747e4fSDavid du Colombier return f; 12859a747e4fSDavid du Colombier } 12869a747e4fSDavid du Colombier 128750a9bdd4SDavid du Colombier Fid* 128850a9bdd4SDavid du Colombier oldfid(int fid, char **ep) 128950a9bdd4SDavid du Colombier { 129050a9bdd4SDavid du Colombier return oldfidex(fid, 0, ep); 129150a9bdd4SDavid du Colombier } 129250a9bdd4SDavid du Colombier 129350a9bdd4SDavid du Colombier Fid* 129450a9bdd4SDavid du Colombier oldauthfid(int fid, void **magic, char **ep) 129550a9bdd4SDavid du Colombier { 129650a9bdd4SDavid du Colombier Fid *af; 129750a9bdd4SDavid du Colombier af = oldfidex(fid, 1, ep); 129850a9bdd4SDavid du Colombier if (af == nil) 129950a9bdd4SDavid du Colombier return nil; 130050a9bdd4SDavid du Colombier *magic = af->authmagic; 130150a9bdd4SDavid du Colombier return af; 130250a9bdd4SDavid du Colombier } 130350a9bdd4SDavid du Colombier 13049a747e4fSDavid du Colombier void 13059a747e4fSDavid du Colombier freefid(Fid *f) 13069a747e4fSDavid du Colombier { 13079a747e4fSDavid du Colombier if(f->prev) 13089a747e4fSDavid du Colombier f->prev->next = f->next; 13099a747e4fSDavid du Colombier else 13109a747e4fSDavid du Colombier fidtab[f->fid%nelem(fidtab)] = f->next; 13119a747e4fSDavid du Colombier if(f->next) 13129a747e4fSDavid du Colombier f->next->prev = f->prev; 13139a747e4fSDavid du Colombier if(f->dir) 13149a747e4fSDavid du Colombier closedir(f->dir); 13159a747e4fSDavid du Colombier if(f->fd) 13169a747e4fSDavid du Colombier close(f->fd); 13179a747e4fSDavid du Colombier free(f->path); 13189a747e4fSDavid du Colombier free(f); 13199a747e4fSDavid du Colombier } 13209a747e4fSDavid du Colombier 13219a747e4fSDavid du Colombier int 13229a747e4fSDavid du Colombier fidstat(Fid *fid, char **ep) 13239a747e4fSDavid du Colombier { 13249a747e4fSDavid du Colombier if(stat(fid->path, &fid->st) < 0){ 13259a747e4fSDavid du Colombier fprint(2, "fidstat(%s) failed\n", fid->path); 13269a747e4fSDavid du Colombier if(ep) 13279a747e4fSDavid du Colombier *ep = strerror(errno); 13289a747e4fSDavid du Colombier return -1; 13299a747e4fSDavid du Colombier } 13309a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)) 13319a747e4fSDavid du Colombier fid->st.st_size = 0; 13329a747e4fSDavid du Colombier return 0; 13339a747e4fSDavid du Colombier } 13349a747e4fSDavid du Colombier 13359a747e4fSDavid du Colombier int 13369a747e4fSDavid du Colombier userchange(User *u, char **ep) 13379a747e4fSDavid du Colombier { 1338d9306527SDavid du Colombier if(defaultuser) 1339d9306527SDavid du Colombier return 0; 1340d9306527SDavid du Colombier 1341d9306527SDavid du Colombier if(setreuid(0, 0) < 0){ 13429a747e4fSDavid du Colombier fprint(2, "setreuid(0, 0) failed\n"); 13439a747e4fSDavid du Colombier *ep = "cannot setuid back to root"; 13449a747e4fSDavid du Colombier return -1; 13459a747e4fSDavid du Colombier } 13469a747e4fSDavid du Colombier 13479a747e4fSDavid du Colombier /* 13489a747e4fSDavid du Colombier * Initgroups does not appear to be SUSV standard. 13499a747e4fSDavid du Colombier * But it exists on SGI and on Linux, which makes me 13509a747e4fSDavid du Colombier * think it's standard enough. We have to do something 13519a747e4fSDavid du Colombier * like this, and the closest other function I can find is 13529a747e4fSDavid du Colombier * setgroups (which initgroups eventually calls). 13539a747e4fSDavid du Colombier * Setgroups is the same as far as standardization though, 13549a747e4fSDavid du Colombier * so we're stuck using a non-SUSV call. Sigh. 13559a747e4fSDavid du Colombier */ 13569a747e4fSDavid du Colombier if(initgroups(u->name, u->defaultgid) < 0) 13579a747e4fSDavid du Colombier fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 13589a747e4fSDavid du Colombier 13599a747e4fSDavid du Colombier if(setreuid(-1, u->id) < 0){ 13609a747e4fSDavid du Colombier fprint(2, "setreuid(-1, %s) failed\n", u->name); 13619a747e4fSDavid du Colombier *ep = strerror(errno); 13629a747e4fSDavid du Colombier return -1; 13639a747e4fSDavid du Colombier } 13649a747e4fSDavid du Colombier 13659a747e4fSDavid du Colombier return 0; 13669a747e4fSDavid du Colombier } 13679a747e4fSDavid du Colombier 13689a747e4fSDavid du Colombier /* 13699a747e4fSDavid du Colombier * We do our own checking here, then switch to root temporarily 13709a747e4fSDavid du Colombier * to set our gid. In a perfect world, you'd be allowed to set your 13719a747e4fSDavid du Colombier * egid to any of the supplemental groups of your euid, but this 13729a747e4fSDavid du Colombier * is not the case on Linux 2.2.14 (and perhaps others). 13739a747e4fSDavid du Colombier * 13749a747e4fSDavid du Colombier * This is a race, of course, but it's a race against processes 13759a747e4fSDavid du Colombier * that can edit the group lists. If you can do that, you can 13769a747e4fSDavid du Colombier * change your own group without our help. 13779a747e4fSDavid du Colombier */ 13789a747e4fSDavid du Colombier int 13799a747e4fSDavid du Colombier groupchange(User *u, User *g, char **ep) 13809a747e4fSDavid du Colombier { 1381dc5a79c1SDavid du Colombier if(g == nil) 1382dc5a79c1SDavid du Colombier return -1; 13839a747e4fSDavid du Colombier if(!useringroup(u, g)){ 13849a747e4fSDavid du Colombier if(chatty9p) 13859a747e4fSDavid du Colombier fprint(2, "%s not in group %s\n", u->name, g->name); 13869a747e4fSDavid du Colombier *ep = Enotingroup; 13879a747e4fSDavid du Colombier return -1; 13889a747e4fSDavid du Colombier } 13899a747e4fSDavid du Colombier 13909a747e4fSDavid du Colombier setreuid(0,0); 13919a747e4fSDavid du Colombier if(setregid(-1, g->id) < 0){ 13929a747e4fSDavid du Colombier fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 13939a747e4fSDavid du Colombier *ep = strerror(errno); 13949a747e4fSDavid du Colombier return -1; 13959a747e4fSDavid du Colombier } 13969a747e4fSDavid du Colombier if(userchange(u, ep) < 0) 13979a747e4fSDavid du Colombier return -1; 13989a747e4fSDavid du Colombier 13999a747e4fSDavid du Colombier return 0; 14009a747e4fSDavid du Colombier } 14019a747e4fSDavid du Colombier 14029a747e4fSDavid du Colombier 14039a747e4fSDavid du Colombier /* 14049a747e4fSDavid du Colombier * An attempt to enforce permissions by looking at the 14059a747e4fSDavid du Colombier * file system. Separation of checking permission and 14069a747e4fSDavid du Colombier * actually performing the action is a terrible idea, of 14079a747e4fSDavid du Colombier * course, so we use setreuid for most of the permission 14089a747e4fSDavid du Colombier * enforcement. This is here only so we can give errors 14099a747e4fSDavid du Colombier * on open(ORCLOSE) in some cases. 14109a747e4fSDavid du Colombier */ 14119a747e4fSDavid du Colombier int 14129a747e4fSDavid du Colombier userperm(User *u, char *path, int type, int need) 14139a747e4fSDavid du Colombier { 14149a747e4fSDavid du Colombier char *p, *q; 14159a747e4fSDavid du Colombier int i, have; 14169a747e4fSDavid du Colombier struct stat st; 14179a747e4fSDavid du Colombier User *g; 14189a747e4fSDavid du Colombier 14199a747e4fSDavid du Colombier switch(type){ 14209a747e4fSDavid du Colombier default: 14219a747e4fSDavid du Colombier fprint(2, "bad type %d in userperm\n", type); 14229a747e4fSDavid du Colombier return -1; 14239a747e4fSDavid du Colombier case Tdot: 14249a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 14259a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) failed\n", path); 14269a747e4fSDavid du Colombier return -1; 14279a747e4fSDavid du Colombier } 14289a747e4fSDavid du Colombier break; 14299a747e4fSDavid du Colombier case Tdotdot: 14309a747e4fSDavid du Colombier p = estrdup(path); 14319a747e4fSDavid du Colombier if((q = strrchr(p, '/'))==nil){ 14329a747e4fSDavid du Colombier fprint(2, "userperm(%s, ..): bad path\n", p); 14339a747e4fSDavid du Colombier free(p); 14349a747e4fSDavid du Colombier return -1; 14359a747e4fSDavid du Colombier } 14369a747e4fSDavid du Colombier if(q > p) 14379a747e4fSDavid du Colombier *q = '\0'; 14389a747e4fSDavid du Colombier else 14399a747e4fSDavid du Colombier *(q+1) = '\0'; 14409a747e4fSDavid du Colombier if(stat(p, &st) < 0){ 14419a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 14429a747e4fSDavid du Colombier p, path); 14439a747e4fSDavid du Colombier free(p); 14449a747e4fSDavid du Colombier return -1; 14459a747e4fSDavid du Colombier } 14469a747e4fSDavid du Colombier free(p); 14479a747e4fSDavid du Colombier break; 14489a747e4fSDavid du Colombier } 14499a747e4fSDavid du Colombier 14509a747e4fSDavid du Colombier if(u == none){ 14519a747e4fSDavid du Colombier fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 14529a747e4fSDavid du Colombier have = st.st_mode&7; 14539a747e4fSDavid du Colombier if((have&need)==need) 14549a747e4fSDavid du Colombier return 0; 14559a747e4fSDavid du Colombier return -1; 14569a747e4fSDavid du Colombier } 14579a747e4fSDavid du Colombier have = st.st_mode&7; 14589a747e4fSDavid du Colombier if((uid_t)u->id == st.st_uid) 14599a747e4fSDavid du Colombier have |= (st.st_mode>>6)&7; 14609a747e4fSDavid du Colombier if((have&need)==need) 14619a747e4fSDavid du Colombier return 0; 14629a747e4fSDavid du Colombier if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 14639a747e4fSDavid du Colombier return -1; 14649a747e4fSDavid du Colombier g = gid2user(st.st_gid); 14659a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++){ 14669a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0){ 14679a747e4fSDavid du Colombier have |= (st.st_mode>>3)&7; 14689a747e4fSDavid du Colombier break; 14699a747e4fSDavid du Colombier } 14709a747e4fSDavid du Colombier } 14719a747e4fSDavid du Colombier if((have&need)==need) 14729a747e4fSDavid du Colombier return 0; 14739a747e4fSDavid du Colombier return -1; 14749a747e4fSDavid du Colombier } 14759a747e4fSDavid du Colombier 14769a747e4fSDavid du Colombier int 14779a747e4fSDavid du Colombier userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 14789a747e4fSDavid du Colombier { 14799a747e4fSDavid du Colombier char *npath; 14809a747e4fSDavid du Colombier struct stat st; 14819a747e4fSDavid du Colombier 1482*dfda52d8SDavid du Colombier npath = estrpath(*path, elem, 1); 14839a747e4fSDavid du Colombier if(stat(npath, &st) < 0){ 14849a747e4fSDavid du Colombier free(npath); 14859a747e4fSDavid du Colombier *ep = strerror(errno); 14869a747e4fSDavid du Colombier return -1; 14879a747e4fSDavid du Colombier } 14889a747e4fSDavid du Colombier *qid = stat2qid(&st); 14899a747e4fSDavid du Colombier free(*path); 14909a747e4fSDavid du Colombier *path = npath; 14919a747e4fSDavid du Colombier return 0; 14929a747e4fSDavid du Colombier } 14939a747e4fSDavid du Colombier 14949a747e4fSDavid du Colombier int 14959a747e4fSDavid du Colombier useropen(Fid *fid, int omode, char **ep) 14969a747e4fSDavid du Colombier { 14979a747e4fSDavid du Colombier int a, o; 14989a747e4fSDavid du Colombier 14999a747e4fSDavid du Colombier /* 15009a747e4fSDavid du Colombier * Check this anyway, to try to head off problems later. 15019a747e4fSDavid du Colombier */ 15029a747e4fSDavid du Colombier if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 15039a747e4fSDavid du Colombier *ep = Eperm; 15049a747e4fSDavid du Colombier return -1; 15059a747e4fSDavid du Colombier } 15069a747e4fSDavid du Colombier 15079a747e4fSDavid du Colombier switch(omode&3){ 15089a747e4fSDavid du Colombier default: 15099a747e4fSDavid du Colombier *ep = "programmer error"; 15109a747e4fSDavid du Colombier return -1; 15119a747e4fSDavid du Colombier case OREAD: 15121118d624SDavid du Colombier a = R_OK; 15139a747e4fSDavid du Colombier o = O_RDONLY; 15149a747e4fSDavid du Colombier break; 15159a747e4fSDavid du Colombier case ORDWR: 15169a747e4fSDavid du Colombier a = R_OK|W_OK; 15179a747e4fSDavid du Colombier o = O_RDWR; 15189a747e4fSDavid du Colombier break; 15199a747e4fSDavid du Colombier case OWRITE: 1520e5495c06SDavid du Colombier a = W_OK; 15219a747e4fSDavid du Colombier o = O_WRONLY; 15229a747e4fSDavid du Colombier break; 15239a747e4fSDavid du Colombier case OEXEC: 15249a747e4fSDavid du Colombier a = X_OK; 15259a747e4fSDavid du Colombier o = O_RDONLY; 15269a747e4fSDavid du Colombier break; 15279a747e4fSDavid du Colombier } 15289a747e4fSDavid du Colombier if(omode & OTRUNC){ 15299a747e4fSDavid du Colombier a |= W_OK; 15309a747e4fSDavid du Colombier o |= O_TRUNC; 15319a747e4fSDavid du Colombier } 15329a747e4fSDavid du Colombier 15339a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)){ 15349a747e4fSDavid du Colombier if(a != R_OK){ 15359a747e4fSDavid du Colombier fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 15369a747e4fSDavid du Colombier *ep = Eperm; 15379a747e4fSDavid du Colombier return -1; 15389a747e4fSDavid du Colombier } 15399a747e4fSDavid du Colombier if((fid->dir = opendir(fid->path)) == nil){ 15409a747e4fSDavid du Colombier *ep = strerror(errno); 15419a747e4fSDavid du Colombier return -1; 15429a747e4fSDavid du Colombier } 15439a747e4fSDavid du Colombier }else{ 15440c0e9c72SDavid du Colombier /* 15450c0e9c72SDavid du Colombier * This is wrong because access used the real uid 15460c0e9c72SDavid du Colombier * and not the effective uid. Let the open sort it out. 15470c0e9c72SDavid du Colombier * 15489a747e4fSDavid du Colombier if(access(fid->path, a) < 0){ 15499a747e4fSDavid du Colombier *ep = strerror(errno); 15509a747e4fSDavid du Colombier return -1; 15519a747e4fSDavid du Colombier } 15520c0e9c72SDavid du Colombier * 15530c0e9c72SDavid du Colombier */ 15549a747e4fSDavid du Colombier if((fid->fd = open(fid->path, o)) < 0){ 15559a747e4fSDavid du Colombier *ep = strerror(errno); 15569a747e4fSDavid du Colombier return -1; 15579a747e4fSDavid du Colombier } 15589a747e4fSDavid du Colombier } 15599a747e4fSDavid du Colombier fid->omode = omode; 15609a747e4fSDavid du Colombier return 0; 15619a747e4fSDavid du Colombier } 15629a747e4fSDavid du Colombier 15639a747e4fSDavid du Colombier int 15649a747e4fSDavid du Colombier usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 15659a747e4fSDavid du Colombier { 15669a747e4fSDavid du Colombier int o, m; 15679a747e4fSDavid du Colombier char *opath, *npath; 15689a747e4fSDavid du Colombier struct stat st, parent; 15699a747e4fSDavid du Colombier 15709a747e4fSDavid du Colombier if(stat(fid->path, &parent) < 0){ 15719a747e4fSDavid du Colombier *ep = strerror(errno); 15729a747e4fSDavid du Colombier return -1; 15739a747e4fSDavid du Colombier } 15749a747e4fSDavid du Colombier 15759a747e4fSDavid du Colombier /* 15769a747e4fSDavid du Colombier * Change group so that created file has expected group 15779a747e4fSDavid du Colombier * by Plan 9 semantics. If that fails, might as well go 15789a747e4fSDavid du Colombier * with the user's default group. 15799a747e4fSDavid du Colombier */ 15809a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 15819a747e4fSDavid du Colombier && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 15829a747e4fSDavid du Colombier return -1; 15839a747e4fSDavid du Colombier 15849a747e4fSDavid du Colombier m = (perm & DMDIR) ? 0777 : 0666; 15859a747e4fSDavid du Colombier perm = perm & (~m | (fid->st.st_mode & m)); 15869a747e4fSDavid du Colombier 1587*dfda52d8SDavid du Colombier npath = estrpath(fid->path, elem, 1); 15889a747e4fSDavid du Colombier if(perm & DMDIR){ 15899a747e4fSDavid du Colombier if((omode&~ORCLOSE) != OREAD){ 15909a747e4fSDavid du Colombier *ep = Eperm; 15919a747e4fSDavid du Colombier free(npath); 15929a747e4fSDavid du Colombier return -1; 15939a747e4fSDavid du Colombier } 15949a747e4fSDavid du Colombier if(stat(npath, &st) >= 0 || errno != ENOENT){ 15959a747e4fSDavid du Colombier *ep = Eexist; 15969a747e4fSDavid du Colombier free(npath); 15979a747e4fSDavid du Colombier return -1; 15989a747e4fSDavid du Colombier } 15999a747e4fSDavid du Colombier /* race */ 16009a747e4fSDavid du Colombier if(mkdir(npath, perm&0777) < 0){ 16019a747e4fSDavid du Colombier *ep = strerror(errno); 16029a747e4fSDavid du Colombier free(npath); 16039a747e4fSDavid du Colombier return -1; 16049a747e4fSDavid du Colombier } 16059a747e4fSDavid du Colombier if((fid->dir = opendir(npath)) == nil){ 16069a747e4fSDavid du Colombier *ep = strerror(errno); 16079a747e4fSDavid du Colombier remove(npath); /* race */ 16089a747e4fSDavid du Colombier free(npath); 16099a747e4fSDavid du Colombier return -1; 16109a747e4fSDavid du Colombier } 16119a747e4fSDavid du Colombier }else{ 16129a747e4fSDavid du Colombier o = O_CREAT|O_EXCL; 16139a747e4fSDavid du Colombier switch(omode&3){ 16149a747e4fSDavid du Colombier default: 16159a747e4fSDavid du Colombier *ep = "programmer error"; 16169a747e4fSDavid du Colombier return -1; 16179a747e4fSDavid du Colombier case OREAD: 16189a747e4fSDavid du Colombier case OEXEC: 16199a747e4fSDavid du Colombier o |= O_RDONLY; 16209a747e4fSDavid du Colombier break; 16219a747e4fSDavid du Colombier case ORDWR: 16229a747e4fSDavid du Colombier o |= O_RDWR; 16239a747e4fSDavid du Colombier break; 16249a747e4fSDavid du Colombier case OWRITE: 16259a747e4fSDavid du Colombier o |= O_WRONLY; 16269a747e4fSDavid du Colombier break; 16279a747e4fSDavid du Colombier } 16289a747e4fSDavid du Colombier if(omode & OTRUNC) 16299a747e4fSDavid du Colombier o |= O_TRUNC; 16309a747e4fSDavid du Colombier if((fid->fd = open(npath, o, perm&0777)) < 0){ 16319a747e4fSDavid du Colombier if(chatty9p) 16329a747e4fSDavid du Colombier fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 16339a747e4fSDavid du Colombier *ep = strerror(errno); 16349a747e4fSDavid du Colombier free(npath); 16359a747e4fSDavid du Colombier return -1; 16369a747e4fSDavid du Colombier } 16379a747e4fSDavid du Colombier } 16389a747e4fSDavid du Colombier 16399a747e4fSDavid du Colombier opath = fid->path; 16409a747e4fSDavid du Colombier fid->path = npath; 16419a747e4fSDavid du Colombier if(fidstat(fid, ep) < 0){ 16429a747e4fSDavid du Colombier fprint(2, "stat after create on %s failed\n", npath); 16439a747e4fSDavid du Colombier remove(npath); /* race */ 16449a747e4fSDavid du Colombier free(npath); 16459a747e4fSDavid du Colombier fid->path = opath; 16469a747e4fSDavid du Colombier if(fid->fd >= 0){ 16479a747e4fSDavid du Colombier close(fid->fd); 16489a747e4fSDavid du Colombier fid->fd = -1; 16499a747e4fSDavid du Colombier }else{ 16509a747e4fSDavid du Colombier closedir(fid->dir); 16519a747e4fSDavid du Colombier fid->dir = nil; 16529a747e4fSDavid du Colombier } 16539a747e4fSDavid du Colombier return -1; 16549a747e4fSDavid du Colombier } 16559a747e4fSDavid du Colombier fid->omode = omode; 16569a747e4fSDavid du Colombier free(opath); 16579a747e4fSDavid du Colombier return 0; 16589a747e4fSDavid du Colombier } 16599a747e4fSDavid du Colombier 16609a747e4fSDavid du Colombier int 16619a747e4fSDavid du Colombier userremove(Fid *fid, char **ep) 16629a747e4fSDavid du Colombier { 16639a747e4fSDavid du Colombier if(remove(fid->path) < 0){ 16649a747e4fSDavid du Colombier *ep = strerror(errno); 16659a747e4fSDavid du Colombier return -1; 16669a747e4fSDavid du Colombier } 16679a747e4fSDavid du Colombier return 0; 16689a747e4fSDavid du Colombier } 16699a747e4fSDavid du Colombier 16709a747e4fSDavid du Colombier void 16719a747e4fSDavid du Colombier usage(void) 16729a747e4fSDavid du Colombier { 16739a747e4fSDavid du Colombier fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 16749a747e4fSDavid du Colombier exit(1); 16759a747e4fSDavid du Colombier } 16769a747e4fSDavid du Colombier 16779a747e4fSDavid du Colombier int 16789a747e4fSDavid du Colombier main(int argc, char **argv) 16799a747e4fSDavid du Colombier { 16809a747e4fSDavid du Colombier char *authtype; 16819a747e4fSDavid du Colombier int i; 16829a747e4fSDavid du Colombier int fd; 16839a747e4fSDavid du Colombier int logflag; 16849a747e4fSDavid du Colombier 16859a747e4fSDavid du Colombier auth = authmethods[0]; 16869a747e4fSDavid du Colombier logflag = O_WRONLY|O_APPEND|O_CREAT; 16879a747e4fSDavid du Colombier ARGBEGIN{ 16889a747e4fSDavid du Colombier case 'D': 16899a747e4fSDavid du Colombier chatty9p = 1; 16909a747e4fSDavid du Colombier break; 16919a747e4fSDavid du Colombier case 'a': 16929a747e4fSDavid du Colombier authtype = EARGF(usage()); 16939a747e4fSDavid du Colombier auth = nil; 16949a747e4fSDavid du Colombier for(i=0; i<nelem(authmethods); i++) 16959a747e4fSDavid du Colombier if(strcmp(authmethods[i]->name, authtype)==0) 16969a747e4fSDavid du Colombier auth = authmethods[i]; 16979a747e4fSDavid du Colombier if(auth == nil) 16989a747e4fSDavid du Colombier sysfatal("unknown auth type '%s'", authtype); 16999a747e4fSDavid du Colombier break; 17009a747e4fSDavid du Colombier case 'A': 17019a747e4fSDavid du Colombier autharg = EARGF(usage()); 17029a747e4fSDavid du Colombier break; 17039a747e4fSDavid du Colombier case 'l': 17049a747e4fSDavid du Colombier logfile = EARGF(usage()); 17059a747e4fSDavid du Colombier break; 17069a747e4fSDavid du Colombier case 'm': 17079a747e4fSDavid du Colombier msize = strtol(EARGF(usage()), 0, 0); 17089a747e4fSDavid du Colombier break; 17099a747e4fSDavid du Colombier case 'n': 17109a747e4fSDavid du Colombier network = 0; 17119a747e4fSDavid du Colombier break; 17129a747e4fSDavid du Colombier case 'u': 17139a747e4fSDavid du Colombier defaultuser = EARGF(usage()); 17149a747e4fSDavid du Colombier break; 17159a747e4fSDavid du Colombier case 'z': 17169a747e4fSDavid du Colombier logflag |= O_TRUNC; 17179a747e4fSDavid du Colombier }ARGEND 17189a747e4fSDavid du Colombier 17199a747e4fSDavid du Colombier if(argc > 1) 17209a747e4fSDavid du Colombier usage(); 17219a747e4fSDavid du Colombier 17229a747e4fSDavid du Colombier fd = open(logfile, logflag, 0666); 17239a747e4fSDavid du Colombier if(fd < 0) 17249a747e4fSDavid du Colombier sysfatal("cannot open log '%s'", logfile); 17259a747e4fSDavid du Colombier 17269a747e4fSDavid du Colombier if(dup2(fd, 2) < 0) 17279a747e4fSDavid du Colombier sysfatal("cannot dup fd onto stderr"); 17289a747e4fSDavid du Colombier fprint(2, "u9fs\nkill %d\n", (int)getpid()); 17299a747e4fSDavid du Colombier 17309a747e4fSDavid du Colombier fmtinstall('F', fcallconv); 17319a747e4fSDavid du Colombier fmtinstall('D', dirconv); 17329a747e4fSDavid du Colombier fmtinstall('M', dirmodeconv); 17339a747e4fSDavid du Colombier 17349a747e4fSDavid du Colombier rxbuf = emalloc(msize); 17359a747e4fSDavid du Colombier txbuf = emalloc(msize); 17369a747e4fSDavid du Colombier databuf = emalloc(msize); 17379a747e4fSDavid du Colombier 17389a747e4fSDavid du Colombier if(auth->init) 17399a747e4fSDavid du Colombier auth->init(); 17409a747e4fSDavid du Colombier 17419a747e4fSDavid du Colombier if(network) 17429a747e4fSDavid du Colombier getremotehostname(remotehostname, sizeof remotehostname); 17439a747e4fSDavid du Colombier 17449a747e4fSDavid du Colombier if(gethostname(hostname, sizeof hostname) < 0) 17459a747e4fSDavid du Colombier strcpy(hostname, "gnot"); 17469a747e4fSDavid du Colombier 17479a747e4fSDavid du Colombier umask(0); 17489a747e4fSDavid du Colombier 17499a747e4fSDavid du Colombier if(argc == 1) 17509a747e4fSDavid du Colombier if(chroot(argv[0]) < 0) 17519a747e4fSDavid du Colombier sysfatal("chroot '%s' failed", argv[0]); 17529a747e4fSDavid du Colombier 17539a747e4fSDavid du Colombier none = uname2user("none"); 17549df35464SDavid du Colombier 17559a747e4fSDavid du Colombier serve(0, 1); 17569a747e4fSDavid du Colombier return 0; 17579a747e4fSDavid du Colombier } 1758