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 struct Fid { 539a747e4fSDavid du Colombier int fid; 549a747e4fSDavid du Colombier char *path; 559a747e4fSDavid du Colombier struct stat st; 569a747e4fSDavid du Colombier User *u; 579a747e4fSDavid du Colombier int omode; 589a747e4fSDavid du Colombier DIR *dir; 599a747e4fSDavid du Colombier int diroffset; 609a747e4fSDavid du Colombier int fd; 619a747e4fSDavid du Colombier struct dirent *dirent; 629a747e4fSDavid du Colombier Fid *next; 639a747e4fSDavid du Colombier Fid *prev; 6450a9bdd4SDavid du Colombier int auth; 6550a9bdd4SDavid du Colombier void *authmagic; 669a747e4fSDavid du Colombier }; 673e12c5d1SDavid du Colombier 689a747e4fSDavid du Colombier void* emalloc(size_t); 699a747e4fSDavid du Colombier void* erealloc(void*, size_t); 703e12c5d1SDavid du Colombier char* estrdup(char*); 719a747e4fSDavid du Colombier char* estrpath(char*, char*); 729a747e4fSDavid du Colombier void sysfatal(char*, ...); 739a747e4fSDavid du Colombier int okuser(char*); 743e12c5d1SDavid du Colombier 759a747e4fSDavid du Colombier void rversion(Fcall*, Fcall*); 769a747e4fSDavid du Colombier void rauth(Fcall*, Fcall*); 779a747e4fSDavid du Colombier void rattach(Fcall*, Fcall*); 789a747e4fSDavid du Colombier void rflush(Fcall*, Fcall*); 799a747e4fSDavid du Colombier void rclone(Fcall*, Fcall*); 809a747e4fSDavid du Colombier void rwalk(Fcall*, Fcall*); 819a747e4fSDavid du Colombier void ropen(Fcall*, Fcall*); 829a747e4fSDavid du Colombier void rcreate(Fcall*, Fcall*); 839a747e4fSDavid du Colombier void rread(Fcall*, Fcall*); 849a747e4fSDavid du Colombier void rwrite(Fcall*, Fcall*); 859a747e4fSDavid du Colombier void rclunk(Fcall*, Fcall*); 869a747e4fSDavid du Colombier void rstat(Fcall*, Fcall*); 879a747e4fSDavid du Colombier void rwstat(Fcall*, Fcall*); 889a747e4fSDavid du Colombier void rclwalk(Fcall*, Fcall*); 899a747e4fSDavid du Colombier void rremove(Fcall*, Fcall*); 909a747e4fSDavid du Colombier 919a747e4fSDavid du Colombier User* uname2user(char*); 929a747e4fSDavid du Colombier User* gname2user(char*); 939a747e4fSDavid du Colombier User* uid2user(int); 949a747e4fSDavid du Colombier User* gid2user(int); 959a747e4fSDavid du Colombier 969a747e4fSDavid du Colombier Fid* newfid(int, char**); 9750a9bdd4SDavid du Colombier Fid* oldfidex(int, int, char**); 989a747e4fSDavid du Colombier Fid* oldfid(int, char**); 999a747e4fSDavid du Colombier int fidstat(Fid*, char**); 1009a747e4fSDavid du Colombier void freefid(Fid*); 1019a747e4fSDavid du Colombier 1029a747e4fSDavid du Colombier int userchange(User*, char**); 1039a747e4fSDavid du Colombier int userwalk(User*, char**, char*, Qid*, char**); 1049a747e4fSDavid du Colombier int useropen(Fid*, int, char**); 1059a747e4fSDavid du Colombier int usercreate(Fid*, char*, int, long, char**); 1069a747e4fSDavid du Colombier int userremove(Fid*, char**); 1079a747e4fSDavid du Colombier int userperm(User*, char*, int, int); 1089a747e4fSDavid du Colombier int useringroup(User*, User*); 1099a747e4fSDavid du Colombier 1109a747e4fSDavid du Colombier Qid stat2qid(struct stat*); 1119a747e4fSDavid du Colombier 1129a747e4fSDavid du Colombier void getfcallold(int, Fcall*, int); 1139a747e4fSDavid du Colombier void putfcallold(int, Fcall*); 1143e12c5d1SDavid du Colombier 1153e12c5d1SDavid du Colombier char Eauth[] = "authentication failed"; 1163e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range"; 1179a747e4fSDavid du Colombier char Ebadoffset[] = "bad offset in directory read"; 1189a747e4fSDavid du Colombier char Ebadusefid[] = "bad use of fid"; 1199a747e4fSDavid du Colombier char Edirchange[] = "wstat can't convert between files and directories"; 1209a747e4fSDavid du Colombier char Eexist[] = "file or directory already exists"; 1213e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use"; 1229a747e4fSDavid du Colombier char Enotdir[] = "not a directory"; 1239a747e4fSDavid du Colombier char Enotingroup[] = "not a member of proposed group"; 1249a747e4fSDavid du Colombier char Enotowner[] = "only owner can change group in wstat"; 1259a747e4fSDavid du Colombier char Eperm[] = "permission denied"; 1263e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files"; 1273e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files"; 1289a747e4fSDavid du Colombier char Especial[] = "no access to special file"; 1293e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large"; 1309a747e4fSDavid du Colombier char Eunknowngroup[] = "unknown group"; 1319a747e4fSDavid du Colombier char Eunknownuser[] = "unknown user"; 1329a747e4fSDavid du Colombier char Ewstatbuffer[] = "bogus wstat buffer"; 1339a747e4fSDavid du Colombier 1349a747e4fSDavid du Colombier ulong msize = IOHDRSZ+8192; 1359a747e4fSDavid du Colombier uchar* rxbuf; 1369a747e4fSDavid du Colombier uchar* txbuf; 1379a747e4fSDavid du Colombier void* databuf; 1389a747e4fSDavid du Colombier int connected; 1399a747e4fSDavid du Colombier int devallowed; 1409a747e4fSDavid du Colombier char* autharg; 1419a747e4fSDavid du Colombier char* defaultuser; 1429a747e4fSDavid du Colombier char hostname[256]; 1439a747e4fSDavid du Colombier char remotehostname[256]; 1449a747e4fSDavid du Colombier int chatty9p = 0; 1459a747e4fSDavid du Colombier int network = 1; 1469a747e4fSDavid du Colombier int old9p = -1; 1479a747e4fSDavid du Colombier int authed; 1489a747e4fSDavid du Colombier User* none; 1499a747e4fSDavid du Colombier 1509a747e4fSDavid du Colombier Auth *authmethods[] = { /* first is default */ 1519a747e4fSDavid du Colombier &authrhosts, 15250a9bdd4SDavid du Colombier &authp9any, 1539a747e4fSDavid du Colombier &authnone, 1549a747e4fSDavid du Colombier }; 1559a747e4fSDavid du Colombier 1569a747e4fSDavid du Colombier Auth *auth; 1573e12c5d1SDavid du Colombier 1587dd7cddfSDavid du Colombier void 1599a747e4fSDavid du Colombier getfcallnew(int fd, Fcall *fc, int have) 1607dd7cddfSDavid du Colombier { 1619a747e4fSDavid du Colombier int len; 1629a747e4fSDavid du Colombier 1639a747e4fSDavid du Colombier if(have > BIT32SZ) 1649a747e4fSDavid du Colombier sysfatal("cannot happen"); 1659a747e4fSDavid du Colombier 1669a747e4fSDavid du Colombier if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) 1679a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1689a747e4fSDavid du Colombier 1699a747e4fSDavid du Colombier len = GBIT32(rxbuf); 1709a747e4fSDavid du Colombier if(len <= BIT32SZ) 1719a747e4fSDavid du Colombier sysfatal("bogus message"); 1729a747e4fSDavid du Colombier 1739a747e4fSDavid du Colombier len -= BIT32SZ; 1749a747e4fSDavid du Colombier if(readn(fd, rxbuf+BIT32SZ, len) != len) 1759a747e4fSDavid du Colombier sysfatal("short message"); 1769a747e4fSDavid du Colombier 1779a747e4fSDavid du Colombier if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) 1789a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 1799a747e4fSDavid du Colombier } 1809a747e4fSDavid du Colombier 1819a747e4fSDavid du Colombier void 1829a747e4fSDavid du Colombier getfcallold(int fd, Fcall *fc, int have) 1839a747e4fSDavid du Colombier { 1849a747e4fSDavid du Colombier int len, n; 1859a747e4fSDavid du Colombier 1869a747e4fSDavid du Colombier if(have > 3) 1879a747e4fSDavid du Colombier sysfatal("cannot happen"); 1889a747e4fSDavid du Colombier 1899a747e4fSDavid du Colombier if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) 1909a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1919a747e4fSDavid du Colombier 1929a747e4fSDavid du Colombier len = oldhdrsize(rxbuf[0]); 1939a747e4fSDavid du Colombier if(len < 3) 1949a747e4fSDavid du Colombier sysfatal("bad message %d", rxbuf[0]); 1959a747e4fSDavid du Colombier if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) 1969a747e4fSDavid du Colombier sysfatal("couldn't read message"); 1979a747e4fSDavid du Colombier 1989a747e4fSDavid du Colombier n = iosize(rxbuf); 1999a747e4fSDavid du Colombier if(readn(fd, rxbuf+len, n) != n) 2009a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2019a747e4fSDavid du Colombier len += n; 2029a747e4fSDavid du Colombier 2039a747e4fSDavid du Colombier if(convM2Sold(rxbuf, len, fc) != len) 2049a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 2059a747e4fSDavid du Colombier } 2069a747e4fSDavid du Colombier 2079a747e4fSDavid du Colombier void 2089a747e4fSDavid du Colombier putfcallnew(int wfd, Fcall *tx) 2099a747e4fSDavid du Colombier { 2109a747e4fSDavid du Colombier uint n; 2119a747e4fSDavid du Colombier 2129a747e4fSDavid du Colombier if((n = convS2M(tx, txbuf, msize)) == 0) 2139a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2149a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2159a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2169a747e4fSDavid du Colombier } 2179a747e4fSDavid du Colombier 2189a747e4fSDavid du Colombier void 2199a747e4fSDavid du Colombier putfcallold(int wfd, Fcall *tx) 2209a747e4fSDavid du Colombier { 2219a747e4fSDavid du Colombier uint n; 2229a747e4fSDavid du Colombier 2239a747e4fSDavid du Colombier if((n = convS2Mold(tx, txbuf, msize)) == 0) 2249a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 2259a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 2269a747e4fSDavid du Colombier sysfatal("couldn't send message"); 2279a747e4fSDavid du Colombier } 2289a747e4fSDavid du Colombier 2299a747e4fSDavid du Colombier void 2309a747e4fSDavid du Colombier getfcall(int fd, Fcall *fc) 2319a747e4fSDavid du Colombier { 2329a747e4fSDavid du Colombier if(old9p == 1){ 2339a747e4fSDavid du Colombier getfcallold(fd, fc, 0); 2349a747e4fSDavid du Colombier return; 2359a747e4fSDavid du Colombier } 2369a747e4fSDavid du Colombier if(old9p == 0){ 2379a747e4fSDavid du Colombier getfcallnew(fd, fc, 0); 2389a747e4fSDavid du Colombier return; 2399a747e4fSDavid du Colombier } 2409a747e4fSDavid du Colombier 2419a747e4fSDavid du Colombier /* auto-detect */ 2429a747e4fSDavid du Colombier 2439a747e4fSDavid du Colombier if(readn(fd, rxbuf, 3) != 3) 2449a747e4fSDavid du Colombier sysfatal("couldn't read message"); 2459a747e4fSDavid du Colombier 2469a747e4fSDavid du Colombier /* is it an old (9P1) message? */ 2479a747e4fSDavid du Colombier if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ 2489a747e4fSDavid du Colombier old9p = 1; 2499a747e4fSDavid du Colombier getfcallold(fd, fc, 3); 2509a747e4fSDavid du Colombier return; 2519a747e4fSDavid du Colombier } 2529a747e4fSDavid du Colombier 2539a747e4fSDavid du Colombier getfcallnew(fd, fc, 3); 2549a747e4fSDavid du Colombier old9p = 0; 2559a747e4fSDavid du Colombier } 2569a747e4fSDavid du Colombier 2579a747e4fSDavid du Colombier void 2589a747e4fSDavid du Colombier seterror(Fcall *f, char *error) 2599a747e4fSDavid du Colombier { 2609a747e4fSDavid du Colombier f->type = Rerror; 2619a747e4fSDavid du Colombier f->ename = error ? error : "programmer error"; 2627dd7cddfSDavid du Colombier } 2637dd7cddfSDavid du Colombier 2643e12c5d1SDavid du Colombier int 2659a747e4fSDavid du Colombier isowner(User *u, Fid *f) 2663e12c5d1SDavid du Colombier { 2679a747e4fSDavid du Colombier return u->id == f->st.st_uid; 2683e12c5d1SDavid du Colombier } 2693e12c5d1SDavid du Colombier 2703e12c5d1SDavid du Colombier void 2719a747e4fSDavid du Colombier serve(int rfd, int wfd) 2723e12c5d1SDavid du Colombier { 2739a747e4fSDavid du Colombier Fcall rx, tx; 2743e12c5d1SDavid du Colombier 2753e12c5d1SDavid du Colombier for(;;){ 2769a747e4fSDavid du Colombier getfcall(rfd, &rx); 2773e12c5d1SDavid du Colombier 2789a747e4fSDavid du Colombier if(chatty9p) 2799a747e4fSDavid du Colombier fprint(2, "<- %F\n", &rx); 2809a747e4fSDavid du Colombier 2819a747e4fSDavid du Colombier memset(&tx, 0, sizeof tx); 2829a747e4fSDavid du Colombier tx.type = rx.type+1; 2839a747e4fSDavid du Colombier tx.tag = rx.tag; 2849a747e4fSDavid du Colombier switch(rx.type){ 2859a747e4fSDavid du Colombier case Tflush: 2863e12c5d1SDavid du Colombier break; 2879a747e4fSDavid du Colombier case Tversion: 2889a747e4fSDavid du Colombier rversion(&rx, &tx); 2899a747e4fSDavid du Colombier break; 2909a747e4fSDavid du Colombier case Tauth: 2919a747e4fSDavid du Colombier rauth(&rx, &tx); 2923e12c5d1SDavid du Colombier break; 2933e12c5d1SDavid du Colombier case Tattach: 2949a747e4fSDavid du Colombier rattach(&rx, &tx); 2953e12c5d1SDavid du Colombier break; 2963e12c5d1SDavid du Colombier case Twalk: 2979a747e4fSDavid du Colombier rwalk(&rx, &tx); 2983e12c5d1SDavid du Colombier break; 2993e12c5d1SDavid du Colombier case Tstat: 3009a747e4fSDavid du Colombier tx.stat = databuf; 3019a747e4fSDavid du Colombier rstat(&rx, &tx); 3023e12c5d1SDavid du Colombier break; 3033e12c5d1SDavid du Colombier case Twstat: 3049a747e4fSDavid du Colombier rwstat(&rx, &tx); 3053e12c5d1SDavid du Colombier break; 3063e12c5d1SDavid du Colombier case Topen: 3079a747e4fSDavid du Colombier ropen(&rx, &tx); 3083e12c5d1SDavid du Colombier break; 3093e12c5d1SDavid du Colombier case Tcreate: 3109a747e4fSDavid du Colombier rcreate(&rx, &tx); 3113e12c5d1SDavid du Colombier break; 3123e12c5d1SDavid du Colombier case Tread: 3139a747e4fSDavid du Colombier tx.data = databuf; 3149a747e4fSDavid du Colombier rread(&rx, &tx); 3153e12c5d1SDavid du Colombier break; 3163e12c5d1SDavid du Colombier case Twrite: 3179a747e4fSDavid du Colombier rwrite(&rx, &tx); 3183e12c5d1SDavid du Colombier break; 3193e12c5d1SDavid du Colombier case Tclunk: 3209a747e4fSDavid du Colombier rclunk(&rx, &tx); 3213e12c5d1SDavid du Colombier break; 3223e12c5d1SDavid du Colombier case Tremove: 3239a747e4fSDavid du Colombier rremove(&rx, &tx); 3243e12c5d1SDavid du Colombier break; 3253e12c5d1SDavid du Colombier default: 3269a747e4fSDavid du Colombier fprint(2, "unknown message %F\n", &rx); 3279a747e4fSDavid du Colombier seterror(&tx, "bad message"); 3289a747e4fSDavid du Colombier break; 3293e12c5d1SDavid du Colombier } 3309a747e4fSDavid du Colombier 3319a747e4fSDavid du Colombier if(chatty9p) 3329a747e4fSDavid du Colombier fprint(2, "-> %F\n", &tx); 3339a747e4fSDavid du Colombier 3349a747e4fSDavid du Colombier (old9p ? putfcallold : putfcallnew)(wfd, &tx); 3359a747e4fSDavid du Colombier } 3363e12c5d1SDavid du Colombier } 3373e12c5d1SDavid du Colombier 3383e12c5d1SDavid du Colombier void 3399a747e4fSDavid du Colombier rversion(Fcall *rx, Fcall *tx) 3403e12c5d1SDavid du Colombier { 3419a747e4fSDavid du Colombier if(msize > rx->msize) 3429a747e4fSDavid du Colombier msize = rx->msize; 3439a747e4fSDavid du Colombier tx->msize = msize; 3449a747e4fSDavid du Colombier if(strncmp(rx->version, "9P", 2) != 0) 3459a747e4fSDavid du Colombier tx->version = "unknown"; 3469a747e4fSDavid du Colombier else 3479a747e4fSDavid du Colombier tx->version = "9P2000"; 3483e12c5d1SDavid du Colombier } 3493e12c5d1SDavid du Colombier 3503e12c5d1SDavid du Colombier void 3519a747e4fSDavid du Colombier rauth(Fcall *rx, Fcall *tx) 3523e12c5d1SDavid du Colombier { 3539a747e4fSDavid du Colombier char *e; 3543e12c5d1SDavid du Colombier 3559a747e4fSDavid du Colombier if((e = auth->auth(rx, tx)) != nil) 3569a747e4fSDavid du Colombier seterror(tx, e); 3573e12c5d1SDavid du Colombier } 3589a747e4fSDavid du Colombier 3599a747e4fSDavid du Colombier void 3609a747e4fSDavid du Colombier rattach(Fcall *rx, Fcall *tx) 3619a747e4fSDavid du Colombier { 3629a747e4fSDavid du Colombier char *e; 3639a747e4fSDavid du Colombier Fid *fid; 3649a747e4fSDavid du Colombier User *u; 3659a747e4fSDavid du Colombier 3669a747e4fSDavid du Colombier if(rx->aname == nil) 3679a747e4fSDavid du Colombier rx->aname = ""; 3689a747e4fSDavid du Colombier 3699a747e4fSDavid du Colombier if(strcmp(rx->aname, "device") == 0){ 3709a747e4fSDavid du Colombier if(connected && !devallowed){ 3719a747e4fSDavid du Colombier seterror(tx, Especial0); 3729a747e4fSDavid du Colombier return; 3739a747e4fSDavid du Colombier } 3743e12c5d1SDavid du Colombier devallowed = 1; 3753e12c5d1SDavid du Colombier }else{ 3769a747e4fSDavid du Colombier if(connected && devallowed){ 3779a747e4fSDavid du Colombier seterror(tx, Especial1); 3789a747e4fSDavid du Colombier return; 3793e12c5d1SDavid du Colombier } 3809a747e4fSDavid du Colombier } 3819a747e4fSDavid du Colombier 3829a747e4fSDavid du Colombier if(strcmp(rx->uname, "none") == 0){ 3839a747e4fSDavid du Colombier if(authed == 0){ 3849a747e4fSDavid du Colombier seterror(tx, Eauth); 3859a747e4fSDavid du Colombier return; 3869a747e4fSDavid du Colombier } 3879a747e4fSDavid du Colombier } else { 3889a747e4fSDavid du Colombier if((e = auth->attach(rx, tx)) != nil){ 3899a747e4fSDavid du Colombier seterror(tx, e); 3909a747e4fSDavid du Colombier return; 3919a747e4fSDavid du Colombier } 3929a747e4fSDavid du Colombier authed++; 3939a747e4fSDavid du Colombier } 3949a747e4fSDavid du Colombier 3959a747e4fSDavid du Colombier if((fid = newfid(rx->fid, &e)) == nil){ 3969a747e4fSDavid du Colombier seterror(tx, e); 3979a747e4fSDavid du Colombier return; 3989a747e4fSDavid du Colombier } 3999a747e4fSDavid du Colombier fid->path = estrdup("/"); 4009a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4019a747e4fSDavid du Colombier seterror(tx, e); 4029a747e4fSDavid du Colombier freefid(fid); 4039a747e4fSDavid du Colombier return; 4049a747e4fSDavid du Colombier } 4059a747e4fSDavid du Colombier 4069a747e4fSDavid du Colombier if(defaultuser) 4079a747e4fSDavid du Colombier rx->uname = defaultuser; 4089a747e4fSDavid du Colombier 4099a747e4fSDavid du Colombier if((u = uname2user(rx->uname)) == nil || u->id == 0){ 4109a747e4fSDavid du Colombier /* we don't know anyone named root... */ 4119a747e4fSDavid du Colombier seterror(tx, Eunknownuser); 4129a747e4fSDavid du Colombier freefid(fid); 4139a747e4fSDavid du Colombier return; 4149a747e4fSDavid du Colombier } 4159a747e4fSDavid du Colombier 4169a747e4fSDavid du Colombier fid->u = u; 4179a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 4189a747e4fSDavid du Colombier return; 4193e12c5d1SDavid du Colombier } 4203e12c5d1SDavid du Colombier 4213e12c5d1SDavid du Colombier void 4229a747e4fSDavid du Colombier rwalk(Fcall *rx, Fcall *tx) 4233e12c5d1SDavid du Colombier { 4249a747e4fSDavid du Colombier int i; 4259a747e4fSDavid du Colombier char *path, *e; 4269a747e4fSDavid du Colombier Fid *fid, *nfid; 4273e12c5d1SDavid du Colombier 4289a747e4fSDavid du Colombier e = nil; 4299a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 4309a747e4fSDavid du Colombier seterror(tx, e); 4319a747e4fSDavid du Colombier return; 4323e12c5d1SDavid du Colombier } 4333e12c5d1SDavid du Colombier 4349a747e4fSDavid du Colombier if(fid->omode != -1){ 4359a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 4369a747e4fSDavid du Colombier return; 4373e12c5d1SDavid du Colombier } 4383e12c5d1SDavid du Colombier 4399a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 4409a747e4fSDavid du Colombier seterror(tx, e); 4419a747e4fSDavid du Colombier return; 4429a747e4fSDavid du Colombier } 4433e12c5d1SDavid du Colombier 4449a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ 4459a747e4fSDavid du Colombier seterror(tx, Enotdir); 4469a747e4fSDavid du Colombier return; 4479a747e4fSDavid du Colombier } 4489a747e4fSDavid du Colombier 4499a747e4fSDavid du Colombier nfid = nil; 4509a747e4fSDavid du Colombier if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ 4519a747e4fSDavid du Colombier seterror(tx, e); 4529a747e4fSDavid du Colombier return; 4539a747e4fSDavid du Colombier } 4549a747e4fSDavid du Colombier 4559a747e4fSDavid du Colombier path = estrdup(fid->path); 4569a747e4fSDavid du Colombier e = nil; 4579a747e4fSDavid du Colombier for(i=0; i<rx->nwname; i++) 4589a747e4fSDavid du Colombier if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) 4593e12c5d1SDavid du Colombier break; 4603e12c5d1SDavid du Colombier 4619a747e4fSDavid du Colombier if(i == rx->nwname){ /* successful clone or walk */ 4629a747e4fSDavid du Colombier tx->nwqid = i; 4639a747e4fSDavid du Colombier if(nfid){ 4649a747e4fSDavid du Colombier nfid->path = path; 4659a747e4fSDavid du Colombier nfid->u = fid->u; 4663e12c5d1SDavid du Colombier }else{ 4679a747e4fSDavid du Colombier free(fid->path); 4689a747e4fSDavid du Colombier fid->path = path; 4693e12c5d1SDavid du Colombier } 4709a747e4fSDavid du Colombier }else{ 4719a747e4fSDavid du Colombier if(i > 0) /* partial walk? */ 4729a747e4fSDavid du Colombier tx->nwqid = i; 4739a747e4fSDavid du Colombier else 4749a747e4fSDavid du Colombier seterror(tx, e); 4759a747e4fSDavid du Colombier 4769a747e4fSDavid du Colombier if(nfid) /* clone implicit new fid */ 4779a747e4fSDavid du Colombier freefid(nfid); 4789a747e4fSDavid du Colombier free(path); 4793e12c5d1SDavid du Colombier } 4809a747e4fSDavid du Colombier return; 4813e12c5d1SDavid du Colombier } 4823e12c5d1SDavid du Colombier 4833e12c5d1SDavid du Colombier void 4849a747e4fSDavid du Colombier ropen(Fcall *rx, Fcall *tx) 4853e12c5d1SDavid du Colombier { 4869a747e4fSDavid du Colombier char *e; 4879a747e4fSDavid du Colombier Fid *fid; 4883e12c5d1SDavid du Colombier 4899a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 4909a747e4fSDavid du Colombier seterror(tx, e); 4919a747e4fSDavid du Colombier return; 4923e12c5d1SDavid du Colombier } 4939a747e4fSDavid du Colombier 4949a747e4fSDavid du Colombier if(fid->omode != -1){ 4959a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 4969a747e4fSDavid du Colombier return; 4973e12c5d1SDavid du Colombier } 4989a747e4fSDavid du Colombier 4999a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5009a747e4fSDavid du Colombier seterror(tx, e); 5019a747e4fSDavid du Colombier return; 5023e12c5d1SDavid du Colombier } 5039a747e4fSDavid du Colombier 5049a747e4fSDavid du Colombier if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ 5059a747e4fSDavid du Colombier seterror(tx, Especial); 5069a747e4fSDavid du Colombier return; 5073e12c5d1SDavid du Colombier } 5089a747e4fSDavid du Colombier 5099a747e4fSDavid du Colombier if(useropen(fid, rx->mode, &e) < 0){ 5109a747e4fSDavid du Colombier seterror(tx, e); 5119a747e4fSDavid du Colombier return; 5123e12c5d1SDavid du Colombier } 5139a747e4fSDavid du Colombier 5149a747e4fSDavid du Colombier tx->iounit = 0; 5159a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5163e12c5d1SDavid du Colombier } 5173e12c5d1SDavid du Colombier 5183e12c5d1SDavid du Colombier void 5199a747e4fSDavid du Colombier rcreate(Fcall *rx, Fcall *tx) 5203e12c5d1SDavid du Colombier { 5219a747e4fSDavid du Colombier char *e; 5229a747e4fSDavid du Colombier Fid *fid; 5239a747e4fSDavid du Colombier 5249a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 5259a747e4fSDavid du Colombier seterror(tx, e); 5269a747e4fSDavid du Colombier return; 5279a747e4fSDavid du Colombier } 5289a747e4fSDavid du Colombier 5299a747e4fSDavid du Colombier if(fid->omode != -1){ 5309a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 5319a747e4fSDavid du Colombier return; 5329a747e4fSDavid du Colombier } 5339a747e4fSDavid du Colombier 5349a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5359a747e4fSDavid du Colombier seterror(tx, e); 5369a747e4fSDavid du Colombier return; 5379a747e4fSDavid du Colombier } 5389a747e4fSDavid du Colombier 5399a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode)){ 5409a747e4fSDavid du Colombier seterror(tx, Enotdir); 5419a747e4fSDavid du Colombier return; 5429a747e4fSDavid du Colombier } 5439a747e4fSDavid du Colombier 5449a747e4fSDavid du Colombier if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ 5459a747e4fSDavid du Colombier seterror(tx, e); 5469a747e4fSDavid du Colombier return; 5479a747e4fSDavid du Colombier } 5489a747e4fSDavid du Colombier 5499a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 5509a747e4fSDavid du Colombier seterror(tx, e); 5519a747e4fSDavid du Colombier return; 5529a747e4fSDavid du Colombier } 5539a747e4fSDavid du Colombier 5549a747e4fSDavid du Colombier tx->iounit = 0; 5559a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5569a747e4fSDavid du Colombier } 5579a747e4fSDavid du Colombier 5589a747e4fSDavid du Colombier uchar 5599a747e4fSDavid du Colombier modebyte(struct stat *st) 5609a747e4fSDavid du Colombier { 5619a747e4fSDavid du Colombier uchar b; 5629a747e4fSDavid du Colombier 5639a747e4fSDavid du Colombier b = 0; 5649a747e4fSDavid du Colombier 5659a747e4fSDavid du Colombier if(S_ISDIR(st->st_mode)) 5669a747e4fSDavid du Colombier b |= QTDIR; 5679a747e4fSDavid du Colombier 5689a747e4fSDavid du Colombier /* no way to test append-only */ 5699a747e4fSDavid du Colombier /* no real way to test exclusive use, but mark devices as such */ 5709a747e4fSDavid du Colombier if(S_ISSPECIAL(st->st_mode)) 5719a747e4fSDavid du Colombier b |= QTEXCL; 5729a747e4fSDavid du Colombier 5739a747e4fSDavid du Colombier return b; 5749a747e4fSDavid du Colombier } 5759a747e4fSDavid du Colombier 5769a747e4fSDavid du Colombier ulong 5779a747e4fSDavid du Colombier plan9mode(struct stat *st) 5789a747e4fSDavid du Colombier { 5799a747e4fSDavid du Colombier return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777); 5809a747e4fSDavid du Colombier } 5819a747e4fSDavid du Colombier 5829a747e4fSDavid du Colombier /* 5839a747e4fSDavid du Colombier * this is for chmod, so don't worry about S_IFDIR 5849a747e4fSDavid du Colombier */ 5859a747e4fSDavid du Colombier mode_t 5869a747e4fSDavid du Colombier unixmode(Dir *d) 5879a747e4fSDavid du Colombier { 5889a747e4fSDavid du Colombier return (mode_t)(d->mode&0777); 5899a747e4fSDavid du Colombier } 5909a747e4fSDavid du Colombier 5919a747e4fSDavid du Colombier Qid 5929a747e4fSDavid du Colombier stat2qid(struct stat *st) 5939a747e4fSDavid du Colombier { 5949a747e4fSDavid du Colombier uchar *p, *ep, *q; 5959a747e4fSDavid du Colombier Qid qid; 5969a747e4fSDavid du Colombier 5979a747e4fSDavid du Colombier /* 5989a747e4fSDavid du Colombier * For now, ignore the device number. 5999a747e4fSDavid du Colombier */ 6009a747e4fSDavid du Colombier qid.path = 0; 6019a747e4fSDavid du Colombier p = (uchar*)&qid.path; 6029a747e4fSDavid du Colombier ep = p+sizeof(qid.path); 6039a747e4fSDavid du Colombier q = p+sizeof(ino_t); 6049a747e4fSDavid du Colombier if(q > ep){ 6059a747e4fSDavid du Colombier fprint(2, "warning: inode number too big\n"); 6069a747e4fSDavid du Colombier q = ep; 6079a747e4fSDavid du Colombier } 6089a747e4fSDavid du Colombier memmove(p, &st->st_ino, q-p); 6099a747e4fSDavid du Colombier q = q+sizeof(dev_t); 6109a747e4fSDavid du Colombier if(q > ep){ 6119a747e4fSDavid du Colombier /* fprint(2, "warning: inode number + device number too big %d+%d\n", sizeof(ino_t), sizeof(dev_t)); */ 6129a747e4fSDavid du Colombier q = ep - sizeof(dev_t); 6139a747e4fSDavid du Colombier if(q < p) 6149a747e4fSDavid du Colombier fprint(2, "warning: device number too big by itself\n"); 6159a747e4fSDavid du Colombier else 6169a747e4fSDavid du Colombier *(dev_t*)q ^= st->st_dev; 6179a747e4fSDavid du Colombier } 6189a747e4fSDavid du Colombier 6199a747e4fSDavid du Colombier qid.vers = st->st_mtime ^ (st->st_size << 8); 6209a747e4fSDavid du Colombier qid.type = modebyte(st); 6219a747e4fSDavid du Colombier return qid; 6229a747e4fSDavid du Colombier } 6239a747e4fSDavid du Colombier 6249a747e4fSDavid du Colombier void 6259a747e4fSDavid du Colombier stat2dir(char *path, struct stat *st, Dir *d) 6269a747e4fSDavid du Colombier { 6279a747e4fSDavid du Colombier User *u; 6289a747e4fSDavid du Colombier char *q; 6299a747e4fSDavid du Colombier 6309a747e4fSDavid du Colombier memset(d, 0, sizeof(*d)); 6319a747e4fSDavid du Colombier d->qid = stat2qid(st); 6329a747e4fSDavid du Colombier d->mode = plan9mode(st); 6339a747e4fSDavid du Colombier d->atime = st->st_atime; 6349a747e4fSDavid du Colombier d->mtime = st->st_mtime; 6359a747e4fSDavid du Colombier d->length = st->st_size; 6369a747e4fSDavid du Colombier 6379a747e4fSDavid du Colombier d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; 6389a747e4fSDavid du Colombier d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; 6399a747e4fSDavid du Colombier d->muid = ""; 6409a747e4fSDavid du Colombier 6419a747e4fSDavid du Colombier if((q = strrchr(path, '/')) != nil) 6429a747e4fSDavid du Colombier d->name = q+1; 6439a747e4fSDavid du Colombier else 6449a747e4fSDavid du Colombier d->name = path; 6459a747e4fSDavid du Colombier } 6469a747e4fSDavid du Colombier 6479a747e4fSDavid du Colombier void 6489a747e4fSDavid du Colombier rread(Fcall *rx, Fcall *tx) 6499a747e4fSDavid du Colombier { 6509a747e4fSDavid du Colombier char *e, *path; 6519a747e4fSDavid du Colombier uchar *p, *ep; 6529a747e4fSDavid du Colombier int n; 6539a747e4fSDavid du Colombier Fid *fid; 6543e12c5d1SDavid du Colombier Dir d; 6559a747e4fSDavid du Colombier struct stat st; 6563e12c5d1SDavid du Colombier 6579a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 6589a747e4fSDavid du Colombier seterror(tx, Etoolarge); 6599a747e4fSDavid du Colombier return; 6603e12c5d1SDavid du Colombier } 6619a747e4fSDavid du Colombier 66250a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 66350a9bdd4SDavid du Colombier seterror(tx, e); 66450a9bdd4SDavid du Colombier return; 66550a9bdd4SDavid du Colombier } 66650a9bdd4SDavid du Colombier 66750a9bdd4SDavid du Colombier if (fid->auth) { 66850a9bdd4SDavid du Colombier char *e; 66950a9bdd4SDavid du Colombier e = auth->read(rx, tx); 67050a9bdd4SDavid du Colombier if (e) 6719a747e4fSDavid du Colombier seterror(tx, e); 6729a747e4fSDavid du Colombier return; 6733e12c5d1SDavid du Colombier } 6749a747e4fSDavid du Colombier 6759a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OWRITE){ 6769a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 6779a747e4fSDavid du Colombier return; 6789a747e4fSDavid du Colombier } 6799a747e4fSDavid du Colombier 6809a747e4fSDavid du Colombier if(fid->dir){ 6819a747e4fSDavid du Colombier if(rx->offset != fid->diroffset){ 6829a747e4fSDavid du Colombier if(rx->offset != 0){ 6839a747e4fSDavid du Colombier seterror(tx, Ebadoffset); 6849a747e4fSDavid du Colombier return; 6859a747e4fSDavid du Colombier } 6869a747e4fSDavid du Colombier rewinddir(fid->dir); 6879a747e4fSDavid du Colombier fid->diroffset = 0; 6889a747e4fSDavid du Colombier } 6899a747e4fSDavid du Colombier 6909a747e4fSDavid du Colombier p = (uchar*)tx->data; 6919a747e4fSDavid du Colombier ep = (uchar*)tx->data+rx->count; 6929a747e4fSDavid du Colombier for(;;){ 6939a747e4fSDavid du Colombier if(p+BIT16SZ >= ep) 6943e12c5d1SDavid du Colombier break; 6959a747e4fSDavid du Colombier if(fid->dirent == nil) /* one entry cache for when convD2M fails */ 6969a747e4fSDavid du Colombier if((fid->dirent = readdir(fid->dir)) == nil) 6979a747e4fSDavid du Colombier break; 6989a747e4fSDavid du Colombier if(strcmp(fid->dirent->d_name, ".") == 0 6999a747e4fSDavid du Colombier || strcmp(fid->dirent->d_name, "..") == 0){ 7009a747e4fSDavid du Colombier fid->dirent = nil; 7013e12c5d1SDavid du Colombier continue; 7029a747e4fSDavid du Colombier } 7039a747e4fSDavid du Colombier path = estrpath(fid->path, fid->dirent->d_name); 7049a747e4fSDavid du Colombier memset(&st, 0, sizeof st); 7059a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 7069a747e4fSDavid du Colombier fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); 7079a747e4fSDavid du Colombier fid->dirent = nil; 7089a747e4fSDavid du Colombier free(path); 7093e12c5d1SDavid du Colombier continue; 7103e12c5d1SDavid du Colombier } 7113e12c5d1SDavid du Colombier free(path); 7129a747e4fSDavid du Colombier stat2dir(fid->dirent->d_name, &st, &d); 7139a747e4fSDavid du Colombier if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) 7149a747e4fSDavid du Colombier break; 7159a747e4fSDavid du Colombier p += n; 7169a747e4fSDavid du Colombier fid->dirent = nil; 7173e12c5d1SDavid du Colombier } 7189a747e4fSDavid du Colombier tx->count = p - (uchar*)tx->data; 7199a747e4fSDavid du Colombier fid->diroffset += tx->count; 7203e12c5d1SDavid du Colombier }else{ 7219a747e4fSDavid du Colombier if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ 7229a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 7239a747e4fSDavid du Colombier return; 724219b2ee8SDavid du Colombier } 7259a747e4fSDavid du Colombier tx->count = n; 7263e12c5d1SDavid du Colombier } 7273e12c5d1SDavid du Colombier } 7283e12c5d1SDavid du Colombier 7293e12c5d1SDavid du Colombier void 7309a747e4fSDavid du Colombier rwrite(Fcall *rx, Fcall *tx) 7313e12c5d1SDavid du Colombier { 7329a747e4fSDavid du Colombier char *e; 7339a747e4fSDavid du Colombier Fid *fid; 7343e12c5d1SDavid du Colombier int n; 7353e12c5d1SDavid du Colombier 7369a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 7379a747e4fSDavid du Colombier seterror(tx, Etoolarge); 7387dd7cddfSDavid du Colombier return; 7397dd7cddfSDavid du Colombier } 7409a747e4fSDavid du Colombier 74150a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 74250a9bdd4SDavid du Colombier seterror(tx, e); 74350a9bdd4SDavid du Colombier return; 74450a9bdd4SDavid du Colombier } 74550a9bdd4SDavid du Colombier 74650a9bdd4SDavid du Colombier if (fid->auth) { 74750a9bdd4SDavid du Colombier char *e; 74850a9bdd4SDavid du Colombier e = auth->write(rx, tx); 74950a9bdd4SDavid du Colombier if (e) 7509a747e4fSDavid du Colombier seterror(tx, e); 7519a747e4fSDavid du Colombier return; 7523e12c5d1SDavid du Colombier } 7539a747e4fSDavid du Colombier 7549a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ 7559a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 7569a747e4fSDavid du Colombier return; 7579a747e4fSDavid du Colombier } 7589a747e4fSDavid du Colombier 7599a747e4fSDavid du Colombier if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ 7609a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 7619a747e4fSDavid du Colombier return; 7629a747e4fSDavid du Colombier } 7639a747e4fSDavid du Colombier tx->count = n; 7643e12c5d1SDavid du Colombier } 7653e12c5d1SDavid du Colombier 7663e12c5d1SDavid du Colombier void 7679a747e4fSDavid du Colombier rclunk(Fcall *rx, Fcall *tx) 7683e12c5d1SDavid du Colombier { 7699a747e4fSDavid du Colombier char *e; 7709a747e4fSDavid du Colombier Fid *fid; 7713e12c5d1SDavid du Colombier 77250a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){ 7739a747e4fSDavid du Colombier seterror(tx, e); 7749a747e4fSDavid du Colombier return; 7759a747e4fSDavid du Colombier } 77650a9bdd4SDavid du Colombier if (fid->auth) { 77750a9bdd4SDavid du Colombier if (auth->clunk) { 77850a9bdd4SDavid du Colombier e = (*auth->clunk)(rx, tx); 77950a9bdd4SDavid du Colombier if (e) { 78050a9bdd4SDavid du Colombier seterror(tx, e); 78150a9bdd4SDavid du Colombier return; 78250a9bdd4SDavid du Colombier } 78350a9bdd4SDavid du Colombier } 78450a9bdd4SDavid du Colombier } 78550a9bdd4SDavid du Colombier else if(fid->omode != -1 && fid->omode&ORCLOSE) 7869a747e4fSDavid du Colombier remove(fid->path); 7879a747e4fSDavid du Colombier freefid(fid); 7883e12c5d1SDavid du Colombier } 789219b2ee8SDavid du Colombier 7909a747e4fSDavid du Colombier void 7919a747e4fSDavid du Colombier rremove(Fcall *rx, Fcall *tx) 7923e12c5d1SDavid du Colombier { 7939a747e4fSDavid du Colombier char *e; 7949a747e4fSDavid du Colombier Fid *fid; 7953e12c5d1SDavid du Colombier 7969a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 7979a747e4fSDavid du Colombier seterror(tx, e); 7989a747e4fSDavid du Colombier return; 7993e12c5d1SDavid du Colombier } 8009a747e4fSDavid du Colombier if(userremove(fid, &e) < 0) 8019a747e4fSDavid du Colombier seterror(tx, e); 8029a747e4fSDavid du Colombier freefid(fid); 8039a747e4fSDavid du Colombier } 8049a747e4fSDavid du Colombier 8059a747e4fSDavid du Colombier void 8069a747e4fSDavid du Colombier rstat(Fcall *rx, Fcall *tx) 8079a747e4fSDavid du Colombier { 8089a747e4fSDavid du Colombier char *e; 8099a747e4fSDavid du Colombier Fid *fid; 8109a747e4fSDavid du Colombier Dir d; 8119a747e4fSDavid du Colombier 8129a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8139a747e4fSDavid du Colombier seterror(tx, e); 8149a747e4fSDavid du Colombier return; 8159a747e4fSDavid du Colombier } 8169a747e4fSDavid du Colombier 8179a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 8189a747e4fSDavid du Colombier seterror(tx, e); 8199a747e4fSDavid du Colombier return; 8209a747e4fSDavid du Colombier } 8219a747e4fSDavid du Colombier 8229a747e4fSDavid du Colombier stat2dir(fid->path, &fid->st, &d); 8239a747e4fSDavid du Colombier if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) 8249a747e4fSDavid du Colombier seterror(tx, "convD2M fails"); 8259a747e4fSDavid du Colombier } 8269a747e4fSDavid du Colombier 8279a747e4fSDavid du Colombier void 8289a747e4fSDavid du Colombier rwstat(Fcall *rx, Fcall *tx) 8299a747e4fSDavid du Colombier { 8309a747e4fSDavid du Colombier char *e; 8319a747e4fSDavid du Colombier char *p, *old, *new, *dir; 8329a747e4fSDavid du Colombier gid_t gid; 8339a747e4fSDavid du Colombier Dir d; 8349a747e4fSDavid du Colombier Fid *fid; 8359a747e4fSDavid du Colombier 8369a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 8379a747e4fSDavid du Colombier seterror(tx, e); 8389a747e4fSDavid du Colombier return; 8399a747e4fSDavid du Colombier } 8409a747e4fSDavid du Colombier 8419a747e4fSDavid du Colombier /* 8429a747e4fSDavid du Colombier * wstat is supposed to be atomic. 8439a747e4fSDavid du Colombier * we check all the things we can before trying anything. 8449a747e4fSDavid du Colombier * still, if we are told to truncate a file and rename it and only 8459a747e4fSDavid du Colombier * one works, we're screwed. in such cases we leave things 8469a747e4fSDavid du Colombier * half broken and return an error. it's hardly perfect. 8479a747e4fSDavid du Colombier */ 8489a747e4fSDavid du Colombier if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ 8499a747e4fSDavid du Colombier seterror(tx, Ewstatbuffer); 8509a747e4fSDavid du Colombier return; 8519a747e4fSDavid du Colombier } 8529a747e4fSDavid du Colombier 8539a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 8549a747e4fSDavid du Colombier seterror(tx, e); 8559a747e4fSDavid du Colombier return; 8569a747e4fSDavid du Colombier } 8579a747e4fSDavid du Colombier 8589a747e4fSDavid du Colombier /* 8599a747e4fSDavid du Colombier * The casting is necessary because d.mode is ulong and might, 8609a747e4fSDavid du Colombier * on some systems, be 64 bits. We only want to compare the 8619a747e4fSDavid du Colombier * bottom 32 bits, since that's all that gets sent in the protocol. 8629a747e4fSDavid du Colombier * 8639a747e4fSDavid du Colombier * Same situation for d.mtime and d.length (although that last check 8649a747e4fSDavid du Colombier * is admittedly superfluous, given the current lack of 128-bit machines). 8659a747e4fSDavid du Colombier */ 8669a747e4fSDavid du Colombier gid = (gid_t)-1; 8679a747e4fSDavid du Colombier if(d.gid[0] != '\0'){ 8689a747e4fSDavid du Colombier User *g; 8699a747e4fSDavid du Colombier 8709a747e4fSDavid du Colombier g = gname2user(d.gid); 8719a747e4fSDavid du Colombier if(g == nil){ 8729a747e4fSDavid du Colombier seterror(tx, Eunknowngroup); 8739a747e4fSDavid du Colombier return; 8749a747e4fSDavid du Colombier } 8759a747e4fSDavid du Colombier gid = (gid_t)g->id; 8769a747e4fSDavid du Colombier 8779a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(gid), &e) < 0){ 8789a747e4fSDavid du Colombier seterror(tx, e); 8799a747e4fSDavid du Colombier return; 8809a747e4fSDavid du Colombier } 8819a747e4fSDavid du Colombier } 8829a747e4fSDavid du Colombier 8839a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ 8849a747e4fSDavid du Colombier seterror(tx, Edirchange); 8859a747e4fSDavid du Colombier return; 8869a747e4fSDavid du Colombier } 8879a747e4fSDavid du Colombier 8889a747e4fSDavid du Colombier if(strcmp(fid->path, "/") == 0){ 8899a747e4fSDavid du Colombier seterror(tx, "no wstat of root"); 8909a747e4fSDavid du Colombier return; 8919a747e4fSDavid du Colombier } 8929a747e4fSDavid du Colombier 8939a747e4fSDavid du Colombier /* 8949a747e4fSDavid du Colombier * try things in increasing order of harm to the file. 8959a747e4fSDavid du Colombier * mtime should come after truncate so that if you 8969a747e4fSDavid du Colombier * do both the mtime actually takes effect, but i'd rather 8979a747e4fSDavid du Colombier * leave truncate until last. 8989a747e4fSDavid du Colombier * (see above comment about atomicity). 8999a747e4fSDavid du Colombier */ 9009a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ 9019a747e4fSDavid du Colombier if(chatty9p) 9029a747e4fSDavid du Colombier fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); 9039a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9049a747e4fSDavid du Colombier return; 9059a747e4fSDavid du Colombier } 9069a747e4fSDavid du Colombier 9079a747e4fSDavid du Colombier if((u32int)d.mtime != (u32int)~0){ 9089a747e4fSDavid du Colombier struct utimbuf t; 9099a747e4fSDavid du Colombier 9109a747e4fSDavid du Colombier t.actime = 0; 9119a747e4fSDavid du Colombier t.modtime = d.mtime; 9129a747e4fSDavid du Colombier if(utime(fid->path, &t) < 0){ 9139a747e4fSDavid du Colombier if(chatty9p) 9149a747e4fSDavid du Colombier fprint(2, "utime(%s) failed\n", fid->path); 9159a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9169a747e4fSDavid du Colombier return; 9179a747e4fSDavid du Colombier } 9189a747e4fSDavid du Colombier } 9199a747e4fSDavid du Colombier 9209a747e4fSDavid du Colombier if(gid != (gid_t)-1 && gid != fid->st.st_gid){ 9219a747e4fSDavid du Colombier if(chown(fid->path, (uid_t)-1, gid) < 0){ 9229a747e4fSDavid du Colombier if(chatty9p) 9239a747e4fSDavid du Colombier fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); 9249a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9259a747e4fSDavid du Colombier return; 9269a747e4fSDavid du Colombier } 9279a747e4fSDavid du Colombier } 9289a747e4fSDavid du Colombier 9299a747e4fSDavid du Colombier if(d.name[0]){ 9309a747e4fSDavid du Colombier old = fid->path; 9319a747e4fSDavid du Colombier dir = estrdup(fid->path); 9329a747e4fSDavid du Colombier if((p = strrchr(dir, '/')) > dir) 9339a747e4fSDavid du Colombier *p = '\0'; 9343e12c5d1SDavid du Colombier else{ 9359a747e4fSDavid du Colombier seterror(tx, "whoops: can't happen in u9fs"); 9369a747e4fSDavid du Colombier return; 9373e12c5d1SDavid du Colombier } 9383e12c5d1SDavid du Colombier 9399a747e4fSDavid du Colombier new = estrpath(dir, d.name); 9409a747e4fSDavid du Colombier if(strcmp(old, new) != 0 && rename(old, new) < 0){ 9419a747e4fSDavid du Colombier if(chatty9p) 9429a747e4fSDavid du Colombier fprint(2, "rename(%s, %s) failed\n", old, new); 9439a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9449a747e4fSDavid du Colombier free(new); 9459a747e4fSDavid du Colombier free(dir); 9469a747e4fSDavid du Colombier return; 9479a747e4fSDavid du Colombier } 9489a747e4fSDavid du Colombier fid->path = new; 9499a747e4fSDavid du Colombier free(old); 9509a747e4fSDavid du Colombier free(dir); 9519a747e4fSDavid du Colombier } 9529a747e4fSDavid du Colombier 9539a747e4fSDavid du Colombier if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ 9549a747e4fSDavid du Colombier fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); 9559a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 9569a747e4fSDavid du Colombier return; 9579a747e4fSDavid du Colombier } 9589a747e4fSDavid du Colombier } 9599a747e4fSDavid du Colombier 9609a747e4fSDavid du Colombier /* 9619a747e4fSDavid du Colombier * we keep a table by numeric id. by name lookups happen infrequently 9629a747e4fSDavid du Colombier * while by-number lookups happen once for every directory entry read 9639a747e4fSDavid du Colombier * and every stat request. 9649a747e4fSDavid du Colombier */ 9659a747e4fSDavid du Colombier User *utab[64]; 9669a747e4fSDavid du Colombier User *gtab[64]; 9679a747e4fSDavid du Colombier 9689a747e4fSDavid du Colombier User* 9699a747e4fSDavid du Colombier adduser(struct passwd *p) 9703e12c5d1SDavid du Colombier { 9719a747e4fSDavid du Colombier User *u; 9723e12c5d1SDavid du Colombier 9739a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 9749a747e4fSDavid du Colombier u->id = p->pw_uid; 9759a747e4fSDavid du Colombier u->name = estrdup(p->pw_name); 9769a747e4fSDavid du Colombier u->next = utab[p->pw_uid%nelem(utab)]; 9779a747e4fSDavid du Colombier u->defaultgid = p->pw_gid; 9789a747e4fSDavid du Colombier utab[p->pw_uid%nelem(utab)] = u; 9799a747e4fSDavid du Colombier return u; 9803e12c5d1SDavid du Colombier } 9813e12c5d1SDavid du Colombier 9823e12c5d1SDavid du Colombier int 9839a747e4fSDavid du Colombier useringroup(User *u, User *g) 9843e12c5d1SDavid du Colombier { 9859a747e4fSDavid du Colombier int i; 9869a747e4fSDavid du Colombier 9879a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++) 9889a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0) 9893e12c5d1SDavid du Colombier return 1; 9909a747e4fSDavid du Colombier 9919a747e4fSDavid du Colombier /* 9929a747e4fSDavid du Colombier * Hack around common Unix problem that everyone has 9939a747e4fSDavid du Colombier * default group "user" but /etc/group lists no members. 9949a747e4fSDavid du Colombier */ 9959a747e4fSDavid du Colombier if(u->defaultgid == g->id) 9969a747e4fSDavid du Colombier return 1; 9973e12c5d1SDavid du Colombier return 0; 9983e12c5d1SDavid du Colombier } 9993e12c5d1SDavid du Colombier 10009a747e4fSDavid du Colombier User* 10019a747e4fSDavid du Colombier addgroup(struct group *g) 10023e12c5d1SDavid du Colombier { 10039a747e4fSDavid du Colombier User *u; 10049a747e4fSDavid du Colombier char **p; 10053e12c5d1SDavid du Colombier int n; 10063e12c5d1SDavid du Colombier 10079a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 10089a747e4fSDavid du Colombier n = 0; 10099a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 10109a747e4fSDavid du Colombier n++; 10119a747e4fSDavid du Colombier u->mem = emalloc(sizeof(u->mem[0])*n); 10129a747e4fSDavid du Colombier n = 0; 10139a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 10149a747e4fSDavid du Colombier u->mem[n++] = estrdup(*p); 10159a747e4fSDavid du Colombier u->nmem = n; 10169a747e4fSDavid du Colombier u->id = g->gr_gid; 10179a747e4fSDavid du Colombier u->name = estrdup(g->gr_name); 10189a747e4fSDavid du Colombier u->next = gtab[g->gr_gid%nelem(gtab)]; 10199a747e4fSDavid du Colombier gtab[g->gr_gid%nelem(gtab)] = u; 10209a747e4fSDavid du Colombier return u; 10213e12c5d1SDavid du Colombier } 10223e12c5d1SDavid du Colombier 10239a747e4fSDavid du Colombier User* 10249a747e4fSDavid du Colombier uname2user(char *name) 10257dd7cddfSDavid du Colombier { 10267dd7cddfSDavid du Colombier int i; 10279a747e4fSDavid du Colombier User *u; 10289a747e4fSDavid du Colombier struct passwd *p; 10297dd7cddfSDavid du Colombier 10309a747e4fSDavid du Colombier for(i=0; i<nelem(utab); i++) 10319a747e4fSDavid du Colombier for(u=utab[i]; u; u=u->next) 10329a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 10339a747e4fSDavid du Colombier return u; 10349a747e4fSDavid du Colombier 10359a747e4fSDavid du Colombier if((p = getpwnam(name)) == nil) 10369a747e4fSDavid du Colombier return nil; 10379a747e4fSDavid du Colombier return adduser(p); 10387dd7cddfSDavid du Colombier } 10397dd7cddfSDavid du Colombier 10409a747e4fSDavid du Colombier User* 10419a747e4fSDavid du Colombier uid2user(int id) 10429a747e4fSDavid du Colombier { 10439a747e4fSDavid du Colombier User *u; 10449a747e4fSDavid du Colombier struct passwd *p; 10459a747e4fSDavid du Colombier 10469a747e4fSDavid du Colombier for(u=utab[id%nelem(utab)]; u; u=u->next) 10479a747e4fSDavid du Colombier if(u->id == id) 10489a747e4fSDavid du Colombier return u; 10499a747e4fSDavid du Colombier 10509a747e4fSDavid du Colombier if((p = getpwuid(id)) == nil) 10519a747e4fSDavid du Colombier return nil; 10529a747e4fSDavid du Colombier return adduser(p); 10539a747e4fSDavid du Colombier } 10549a747e4fSDavid du Colombier 10559a747e4fSDavid du Colombier User* 10569a747e4fSDavid du Colombier gname2user(char *name) 10573e12c5d1SDavid du Colombier { 10583e12c5d1SDavid du Colombier int i; 10599a747e4fSDavid du Colombier User *u; 10609a747e4fSDavid du Colombier struct group *g; 10613e12c5d1SDavid du Colombier 10629a747e4fSDavid du Colombier for(i=0; i<nelem(gtab); i++) 10639a747e4fSDavid du Colombier for(u=gtab[i]; u; u=u->next) 10649a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 10659a747e4fSDavid du Colombier return u; 10669a747e4fSDavid du Colombier 10679a747e4fSDavid du Colombier if((g = getgrnam(name)) == nil) 10689a747e4fSDavid du Colombier return nil; 10699a747e4fSDavid du Colombier return addgroup(g); 10709a747e4fSDavid du Colombier } 10719a747e4fSDavid du Colombier 10729a747e4fSDavid du Colombier User* 10739a747e4fSDavid du Colombier gid2user(int id) 10749a747e4fSDavid du Colombier { 10759a747e4fSDavid du Colombier User *u; 10769a747e4fSDavid du Colombier struct group *g; 10779a747e4fSDavid du Colombier 10789a747e4fSDavid du Colombier for(u=gtab[id%nelem(gtab)]; u; u=u->next) 10799a747e4fSDavid du Colombier if(u->id == id) 10809a747e4fSDavid du Colombier return u; 10819a747e4fSDavid du Colombier 10829a747e4fSDavid du Colombier if((g = getgrgid(id)) == nil) 10839a747e4fSDavid du Colombier return nil; 10849a747e4fSDavid du Colombier return addgroup(g); 10853e12c5d1SDavid du Colombier } 10863e12c5d1SDavid du Colombier 10873e12c5d1SDavid du Colombier void 10889a747e4fSDavid du Colombier sysfatal(char *fmt, ...) 10893e12c5d1SDavid du Colombier { 10909a747e4fSDavid du Colombier char buf[1024]; 10919a747e4fSDavid du Colombier va_list va; 10923e12c5d1SDavid du Colombier 10939a747e4fSDavid du Colombier va_start(va, fmt); 10949a747e4fSDavid du Colombier doprint(buf, buf+sizeof buf, fmt, va); 10959a747e4fSDavid du Colombier va_end(va); 10969a747e4fSDavid du Colombier fprint(2, "u9fs: %s\n", buf); 10979a747e4fSDavid du Colombier fprint(2, "last unix error: %s\n", strerror(errno)); 10983e12c5d1SDavid du Colombier exit(1); 10993e12c5d1SDavid du Colombier } 11003e12c5d1SDavid du Colombier 11013e12c5d1SDavid du Colombier void* 11029a747e4fSDavid du Colombier emalloc(size_t n) 11039a747e4fSDavid du Colombier { 11049a747e4fSDavid du Colombier void *p; 11059a747e4fSDavid du Colombier 1106d9306527SDavid du Colombier if(n == 0) 1107d9306527SDavid du Colombier n = 1; 11089a747e4fSDavid du Colombier p = malloc(n); 11099a747e4fSDavid du Colombier if(p == 0) 11109a747e4fSDavid du Colombier sysfatal("malloc(%ld) fails", (long)n); 11119a747e4fSDavid du Colombier memset(p, 0, n); 11129a747e4fSDavid du Colombier return p; 11139a747e4fSDavid du Colombier } 11149a747e4fSDavid du Colombier 11159a747e4fSDavid du Colombier void* 11169a747e4fSDavid du Colombier erealloc(void *p, size_t n) 11173e12c5d1SDavid du Colombier { 11183e12c5d1SDavid du Colombier if(p == 0) 11193e12c5d1SDavid du Colombier p = malloc(n); 11203e12c5d1SDavid du Colombier else 11213e12c5d1SDavid du Colombier p = realloc(p, n); 11223e12c5d1SDavid du Colombier if(p == 0) 11239a747e4fSDavid du Colombier sysfatal("realloc(..., %ld) fails", (long)n); 11243e12c5d1SDavid du Colombier return p; 11253e12c5d1SDavid du Colombier } 11263e12c5d1SDavid du Colombier 11273e12c5d1SDavid du Colombier char* 11283e12c5d1SDavid du Colombier estrdup(char *p) 11293e12c5d1SDavid du Colombier { 11303e12c5d1SDavid du Colombier p = strdup(p); 11313e12c5d1SDavid du Colombier if(p == 0) 11329a747e4fSDavid du Colombier sysfatal("strdup(%.20s) fails", p); 11333e12c5d1SDavid du Colombier return p; 11343e12c5d1SDavid du Colombier } 1135219b2ee8SDavid du Colombier 11369a747e4fSDavid du Colombier char* 11379a747e4fSDavid du Colombier estrpath(char *p, char *q) 1138219b2ee8SDavid du Colombier { 11399a747e4fSDavid du Colombier char *r, *s; 1140219b2ee8SDavid du Colombier 11419a747e4fSDavid du Colombier if(strcmp(q, "..") == 0){ 11429a747e4fSDavid du Colombier r = estrdup(p); 11439a747e4fSDavid du Colombier if((s = strrchr(r, '/')) && s > r) 11449a747e4fSDavid du Colombier *s = '\0'; 11459a747e4fSDavid du Colombier else if(s == r) 11469a747e4fSDavid du Colombier s[1] = '\0'; 11479a747e4fSDavid du Colombier return r; 1148219b2ee8SDavid du Colombier } 11499a747e4fSDavid du Colombier 11509a747e4fSDavid du Colombier r = emalloc(strlen(p)+1+strlen(q)+1); 11519a747e4fSDavid du Colombier strcpy(r, p); 11529a747e4fSDavid du Colombier if(r[0]=='\0' || r[strlen(r)-1] != '/') 11539a747e4fSDavid du Colombier strcat(r, "/"); 11549a747e4fSDavid du Colombier strcat(r, q); 11559a747e4fSDavid du Colombier return r; 11569a747e4fSDavid du Colombier } 11579a747e4fSDavid du Colombier 11589a747e4fSDavid du Colombier Fid *fidtab[1]; 11599a747e4fSDavid du Colombier 11609a747e4fSDavid du Colombier Fid* 11619a747e4fSDavid du Colombier lookupfid(int fid) 11629a747e4fSDavid du Colombier { 11639a747e4fSDavid du Colombier Fid *f; 11649a747e4fSDavid du Colombier 11659a747e4fSDavid du Colombier for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 11669a747e4fSDavid du Colombier if(f->fid == fid) 11679a747e4fSDavid du Colombier return f; 11689a747e4fSDavid du Colombier return nil; 11699a747e4fSDavid du Colombier } 11709a747e4fSDavid du Colombier 11719a747e4fSDavid du Colombier Fid* 11729a747e4fSDavid du Colombier newfid(int fid, char **ep) 11739a747e4fSDavid du Colombier { 11749a747e4fSDavid du Colombier Fid *f; 11759a747e4fSDavid du Colombier 11769a747e4fSDavid du Colombier if(lookupfid(fid) != nil){ 11779a747e4fSDavid du Colombier *ep = Efidactive; 11789a747e4fSDavid du Colombier return nil; 11799a747e4fSDavid du Colombier } 11809a747e4fSDavid du Colombier 11819a747e4fSDavid du Colombier f = emalloc(sizeof(*f)); 11829a747e4fSDavid du Colombier f->next = fidtab[fid%nelem(fidtab)]; 11839a747e4fSDavid du Colombier if(f->next) 11849a747e4fSDavid du Colombier f->next->prev = f; 11859a747e4fSDavid du Colombier fidtab[fid%nelem(fidtab)] = f; 11869a747e4fSDavid du Colombier f->fid = fid; 11879a747e4fSDavid du Colombier f->fd = -1; 11889a747e4fSDavid du Colombier f->omode = -1; 11899a747e4fSDavid du Colombier return f; 11909a747e4fSDavid du Colombier } 11919a747e4fSDavid du Colombier 11929a747e4fSDavid du Colombier Fid* 119350a9bdd4SDavid du Colombier newauthfid(int fid, void *magic, char **ep) 119450a9bdd4SDavid du Colombier { 119550a9bdd4SDavid du Colombier Fid *af; 119650a9bdd4SDavid du Colombier af = newfid(fid, ep); 119750a9bdd4SDavid du Colombier if (af == nil) 119850a9bdd4SDavid du Colombier return nil; 119950a9bdd4SDavid du Colombier af->auth = 1; 120050a9bdd4SDavid du Colombier af->authmagic = magic; 120150a9bdd4SDavid du Colombier return af; 120250a9bdd4SDavid du Colombier } 120350a9bdd4SDavid du Colombier 120450a9bdd4SDavid du Colombier Fid* 120550a9bdd4SDavid du Colombier oldfidex(int fid, int auth, char **ep) 12069a747e4fSDavid du Colombier { 12079a747e4fSDavid du Colombier Fid *f; 12089a747e4fSDavid du Colombier 12099a747e4fSDavid du Colombier if((f = lookupfid(fid)) == nil){ 12109a747e4fSDavid du Colombier *ep = Ebadfid; 12119a747e4fSDavid du Colombier return nil; 12129a747e4fSDavid du Colombier } 12139a747e4fSDavid du Colombier 121450a9bdd4SDavid du Colombier if (auth != -1 && f->auth != auth) { 121550a9bdd4SDavid du Colombier *ep = Ebadfid; 121650a9bdd4SDavid du Colombier return nil; 121750a9bdd4SDavid du Colombier } 121850a9bdd4SDavid du Colombier 121950a9bdd4SDavid du Colombier if (!f->auth) { 12209a747e4fSDavid du Colombier if(userchange(f->u, ep) < 0) 12219a747e4fSDavid du Colombier return nil; 122250a9bdd4SDavid du Colombier } 12239a747e4fSDavid du Colombier 12249a747e4fSDavid du Colombier return f; 12259a747e4fSDavid du Colombier } 12269a747e4fSDavid du Colombier 122750a9bdd4SDavid du Colombier Fid* 122850a9bdd4SDavid du Colombier oldfid(int fid, char **ep) 122950a9bdd4SDavid du Colombier { 123050a9bdd4SDavid du Colombier return oldfidex(fid, 0, ep); 123150a9bdd4SDavid du Colombier } 123250a9bdd4SDavid du Colombier 123350a9bdd4SDavid du Colombier Fid* 123450a9bdd4SDavid du Colombier oldauthfid(int fid, void **magic, char **ep) 123550a9bdd4SDavid du Colombier { 123650a9bdd4SDavid du Colombier Fid *af; 123750a9bdd4SDavid du Colombier af = oldfidex(fid, 1, ep); 123850a9bdd4SDavid du Colombier if (af == nil) 123950a9bdd4SDavid du Colombier return nil; 124050a9bdd4SDavid du Colombier *magic = af->authmagic; 124150a9bdd4SDavid du Colombier return af; 124250a9bdd4SDavid du Colombier } 124350a9bdd4SDavid du Colombier 12449a747e4fSDavid du Colombier void 12459a747e4fSDavid du Colombier freefid(Fid *f) 12469a747e4fSDavid du Colombier { 12479a747e4fSDavid du Colombier if(f->prev) 12489a747e4fSDavid du Colombier f->prev->next = f->next; 12499a747e4fSDavid du Colombier else 12509a747e4fSDavid du Colombier fidtab[f->fid%nelem(fidtab)] = f->next; 12519a747e4fSDavid du Colombier if(f->next) 12529a747e4fSDavid du Colombier f->next->prev = f->prev; 12539a747e4fSDavid du Colombier if(f->dir) 12549a747e4fSDavid du Colombier closedir(f->dir); 12559a747e4fSDavid du Colombier if(f->fd) 12569a747e4fSDavid du Colombier close(f->fd); 12579a747e4fSDavid du Colombier free(f->path); 12589a747e4fSDavid du Colombier free(f); 12599a747e4fSDavid du Colombier } 12609a747e4fSDavid du Colombier 12619a747e4fSDavid du Colombier int 12629a747e4fSDavid du Colombier fidstat(Fid *fid, char **ep) 12639a747e4fSDavid du Colombier { 12649a747e4fSDavid du Colombier if(stat(fid->path, &fid->st) < 0){ 12659a747e4fSDavid du Colombier fprint(2, "fidstat(%s) failed\n", fid->path); 12669a747e4fSDavid du Colombier if(ep) 12679a747e4fSDavid du Colombier *ep = strerror(errno); 12689a747e4fSDavid du Colombier return -1; 12699a747e4fSDavid du Colombier } 12709a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)) 12719a747e4fSDavid du Colombier fid->st.st_size = 0; 12729a747e4fSDavid du Colombier return 0; 12739a747e4fSDavid du Colombier } 12749a747e4fSDavid du Colombier 12759a747e4fSDavid du Colombier int 12769a747e4fSDavid du Colombier userchange(User *u, char **ep) 12779a747e4fSDavid du Colombier { 1278d9306527SDavid du Colombier if(defaultuser) 1279d9306527SDavid du Colombier return 0; 1280d9306527SDavid du Colombier 1281d9306527SDavid du Colombier if(setreuid(0, 0) < 0){ 12829a747e4fSDavid du Colombier fprint(2, "setreuid(0, 0) failed\n"); 12839a747e4fSDavid du Colombier *ep = "cannot setuid back to root"; 12849a747e4fSDavid du Colombier return -1; 12859a747e4fSDavid du Colombier } 12869a747e4fSDavid du Colombier 12879a747e4fSDavid du Colombier /* 12889a747e4fSDavid du Colombier * Initgroups does not appear to be SUSV standard. 12899a747e4fSDavid du Colombier * But it exists on SGI and on Linux, which makes me 12909a747e4fSDavid du Colombier * think it's standard enough. We have to do something 12919a747e4fSDavid du Colombier * like this, and the closest other function I can find is 12929a747e4fSDavid du Colombier * setgroups (which initgroups eventually calls). 12939a747e4fSDavid du Colombier * Setgroups is the same as far as standardization though, 12949a747e4fSDavid du Colombier * so we're stuck using a non-SUSV call. Sigh. 12959a747e4fSDavid du Colombier */ 12969a747e4fSDavid du Colombier if(initgroups(u->name, u->defaultgid) < 0) 12979a747e4fSDavid du Colombier fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 12989a747e4fSDavid du Colombier 12999a747e4fSDavid du Colombier if(setreuid(-1, u->id) < 0){ 13009a747e4fSDavid du Colombier fprint(2, "setreuid(-1, %s) failed\n", u->name); 13019a747e4fSDavid du Colombier *ep = strerror(errno); 13029a747e4fSDavid du Colombier return -1; 13039a747e4fSDavid du Colombier } 13049a747e4fSDavid du Colombier 13059a747e4fSDavid du Colombier return 0; 13069a747e4fSDavid du Colombier } 13079a747e4fSDavid du Colombier 13089a747e4fSDavid du Colombier /* 13099a747e4fSDavid du Colombier * We do our own checking here, then switch to root temporarily 13109a747e4fSDavid du Colombier * to set our gid. In a perfect world, you'd be allowed to set your 13119a747e4fSDavid du Colombier * egid to any of the supplemental groups of your euid, but this 13129a747e4fSDavid du Colombier * is not the case on Linux 2.2.14 (and perhaps others). 13139a747e4fSDavid du Colombier * 13149a747e4fSDavid du Colombier * This is a race, of course, but it's a race against processes 13159a747e4fSDavid du Colombier * that can edit the group lists. If you can do that, you can 13169a747e4fSDavid du Colombier * change your own group without our help. 13179a747e4fSDavid du Colombier */ 13189a747e4fSDavid du Colombier int 13199a747e4fSDavid du Colombier groupchange(User *u, User *g, char **ep) 13209a747e4fSDavid du Colombier { 13219a747e4fSDavid du Colombier if(!useringroup(u, g)){ 13229a747e4fSDavid du Colombier if(chatty9p) 13239a747e4fSDavid du Colombier fprint(2, "%s not in group %s\n", u->name, g->name); 13249a747e4fSDavid du Colombier *ep = Enotingroup; 13259a747e4fSDavid du Colombier return -1; 13269a747e4fSDavid du Colombier } 13279a747e4fSDavid du Colombier 13289a747e4fSDavid du Colombier setreuid(0,0); 13299a747e4fSDavid du Colombier if(setregid(-1, g->id) < 0){ 13309a747e4fSDavid du Colombier fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 13319a747e4fSDavid du Colombier *ep = strerror(errno); 13329a747e4fSDavid du Colombier return -1; 13339a747e4fSDavid du Colombier } 13349a747e4fSDavid du Colombier if(userchange(u, ep) < 0) 13359a747e4fSDavid du Colombier return -1; 13369a747e4fSDavid du Colombier 13379a747e4fSDavid du Colombier return 0; 13389a747e4fSDavid du Colombier } 13399a747e4fSDavid du Colombier 13409a747e4fSDavid du Colombier 13419a747e4fSDavid du Colombier /* 13429a747e4fSDavid du Colombier * An attempt to enforce permissions by looking at the 13439a747e4fSDavid du Colombier * file system. Separation of checking permission and 13449a747e4fSDavid du Colombier * actually performing the action is a terrible idea, of 13459a747e4fSDavid du Colombier * course, so we use setreuid for most of the permission 13469a747e4fSDavid du Colombier * enforcement. This is here only so we can give errors 13479a747e4fSDavid du Colombier * on open(ORCLOSE) in some cases. 13489a747e4fSDavid du Colombier */ 13499a747e4fSDavid du Colombier int 13509a747e4fSDavid du Colombier userperm(User *u, char *path, int type, int need) 13519a747e4fSDavid du Colombier { 13529a747e4fSDavid du Colombier char *p, *q; 13539a747e4fSDavid du Colombier int i, have; 13549a747e4fSDavid du Colombier struct stat st; 13559a747e4fSDavid du Colombier User *g; 13569a747e4fSDavid du Colombier 13579a747e4fSDavid du Colombier switch(type){ 13589a747e4fSDavid du Colombier default: 13599a747e4fSDavid du Colombier fprint(2, "bad type %d in userperm\n", type); 13609a747e4fSDavid du Colombier return -1; 13619a747e4fSDavid du Colombier case Tdot: 13629a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 13639a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) failed\n", path); 13649a747e4fSDavid du Colombier return -1; 13659a747e4fSDavid du Colombier } 13669a747e4fSDavid du Colombier break; 13679a747e4fSDavid du Colombier case Tdotdot: 13689a747e4fSDavid du Colombier p = estrdup(path); 13699a747e4fSDavid du Colombier if((q = strrchr(p, '/'))==nil){ 13709a747e4fSDavid du Colombier fprint(2, "userperm(%s, ..): bad path\n", p); 13719a747e4fSDavid du Colombier free(p); 13729a747e4fSDavid du Colombier return -1; 13739a747e4fSDavid du Colombier } 13749a747e4fSDavid du Colombier if(q > p) 13759a747e4fSDavid du Colombier *q = '\0'; 13769a747e4fSDavid du Colombier else 13779a747e4fSDavid du Colombier *(q+1) = '\0'; 13789a747e4fSDavid du Colombier if(stat(p, &st) < 0){ 13799a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 13809a747e4fSDavid du Colombier p, path); 13819a747e4fSDavid du Colombier free(p); 13829a747e4fSDavid du Colombier return -1; 13839a747e4fSDavid du Colombier } 13849a747e4fSDavid du Colombier free(p); 13859a747e4fSDavid du Colombier break; 13869a747e4fSDavid du Colombier } 13879a747e4fSDavid du Colombier 13889a747e4fSDavid du Colombier if(u == none){ 13899a747e4fSDavid du Colombier fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 13909a747e4fSDavid du Colombier have = st.st_mode&7; 13919a747e4fSDavid du Colombier if((have&need)==need) 13929a747e4fSDavid du Colombier return 0; 13939a747e4fSDavid du Colombier return -1; 13949a747e4fSDavid du Colombier } 13959a747e4fSDavid du Colombier have = st.st_mode&7; 13969a747e4fSDavid du Colombier if((uid_t)u->id == st.st_uid) 13979a747e4fSDavid du Colombier have |= (st.st_mode>>6)&7; 13989a747e4fSDavid du Colombier if((have&need)==need) 13999a747e4fSDavid du Colombier return 0; 14009a747e4fSDavid du Colombier if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 14019a747e4fSDavid du Colombier return -1; 14029a747e4fSDavid du Colombier g = gid2user(st.st_gid); 14039a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++){ 14049a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0){ 14059a747e4fSDavid du Colombier have |= (st.st_mode>>3)&7; 14069a747e4fSDavid du Colombier break; 14079a747e4fSDavid du Colombier } 14089a747e4fSDavid du Colombier } 14099a747e4fSDavid du Colombier if((have&need)==need) 14109a747e4fSDavid du Colombier return 0; 14119a747e4fSDavid du Colombier return -1; 14129a747e4fSDavid du Colombier } 14139a747e4fSDavid du Colombier 14149a747e4fSDavid du Colombier int 14159a747e4fSDavid du Colombier userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 14169a747e4fSDavid du Colombier { 14179a747e4fSDavid du Colombier char *npath; 14189a747e4fSDavid du Colombier struct stat st; 14199a747e4fSDavid du Colombier 14209a747e4fSDavid du Colombier npath = estrpath(*path, elem); 14219a747e4fSDavid du Colombier if(stat(npath, &st) < 0){ 14229a747e4fSDavid du Colombier free(npath); 14239a747e4fSDavid du Colombier *ep = strerror(errno); 14249a747e4fSDavid du Colombier return -1; 14259a747e4fSDavid du Colombier } 14269a747e4fSDavid du Colombier *qid = stat2qid(&st); 14279a747e4fSDavid du Colombier free(*path); 14289a747e4fSDavid du Colombier *path = npath; 14299a747e4fSDavid du Colombier return 0; 14309a747e4fSDavid du Colombier } 14319a747e4fSDavid du Colombier 14329a747e4fSDavid du Colombier int 14339a747e4fSDavid du Colombier useropen(Fid *fid, int omode, char **ep) 14349a747e4fSDavid du Colombier { 14359a747e4fSDavid du Colombier int a, o; 14369a747e4fSDavid du Colombier 14379a747e4fSDavid du Colombier /* 14389a747e4fSDavid du Colombier * Check this anyway, to try to head off problems later. 14399a747e4fSDavid du Colombier */ 14409a747e4fSDavid du Colombier if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 14419a747e4fSDavid du Colombier *ep = Eperm; 14429a747e4fSDavid du Colombier return -1; 14439a747e4fSDavid du Colombier } 14449a747e4fSDavid du Colombier 14459a747e4fSDavid du Colombier switch(omode&3){ 14469a747e4fSDavid du Colombier default: 14479a747e4fSDavid du Colombier *ep = "programmer error"; 14489a747e4fSDavid du Colombier return -1; 14499a747e4fSDavid du Colombier case OREAD: 1450*e5495c06SDavid du Colombier a = W_OK; 14519a747e4fSDavid du Colombier o = O_RDONLY; 14529a747e4fSDavid du Colombier break; 14539a747e4fSDavid du Colombier case ORDWR: 14549a747e4fSDavid du Colombier a = R_OK|W_OK; 14559a747e4fSDavid du Colombier o = O_RDWR; 14569a747e4fSDavid du Colombier break; 14579a747e4fSDavid du Colombier case OWRITE: 1458*e5495c06SDavid du Colombier a = W_OK; 14599a747e4fSDavid du Colombier o = O_WRONLY; 14609a747e4fSDavid du Colombier break; 14619a747e4fSDavid du Colombier case OEXEC: 14629a747e4fSDavid du Colombier a = X_OK; 14639a747e4fSDavid du Colombier o = O_RDONLY; 14649a747e4fSDavid du Colombier break; 14659a747e4fSDavid du Colombier } 14669a747e4fSDavid du Colombier if(omode & OTRUNC){ 14679a747e4fSDavid du Colombier a |= W_OK; 14689a747e4fSDavid du Colombier o |= O_TRUNC; 14699a747e4fSDavid du Colombier } 14709a747e4fSDavid du Colombier 14719a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)){ 14729a747e4fSDavid du Colombier if(a != R_OK){ 14739a747e4fSDavid du Colombier fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 14749a747e4fSDavid du Colombier *ep = Eperm; 14759a747e4fSDavid du Colombier return -1; 14769a747e4fSDavid du Colombier } 14779a747e4fSDavid du Colombier if((fid->dir = opendir(fid->path)) == nil){ 14789a747e4fSDavid du Colombier *ep = strerror(errno); 14799a747e4fSDavid du Colombier return -1; 14809a747e4fSDavid du Colombier } 14819a747e4fSDavid du Colombier }else{ 14820c0e9c72SDavid du Colombier /* 14830c0e9c72SDavid du Colombier * This is wrong because access used the real uid 14840c0e9c72SDavid du Colombier * and not the effective uid. Let the open sort it out. 14850c0e9c72SDavid du Colombier * 14869a747e4fSDavid du Colombier if(access(fid->path, a) < 0){ 14879a747e4fSDavid du Colombier *ep = strerror(errno); 14889a747e4fSDavid du Colombier return -1; 14899a747e4fSDavid du Colombier } 14900c0e9c72SDavid du Colombier * 14910c0e9c72SDavid du Colombier */ 14929a747e4fSDavid du Colombier if((fid->fd = open(fid->path, o)) < 0){ 14939a747e4fSDavid du Colombier *ep = strerror(errno); 14949a747e4fSDavid du Colombier return -1; 14959a747e4fSDavid du Colombier } 14969a747e4fSDavid du Colombier } 14979a747e4fSDavid du Colombier fid->omode = omode; 14989a747e4fSDavid du Colombier return 0; 14999a747e4fSDavid du Colombier } 15009a747e4fSDavid du Colombier 15019a747e4fSDavid du Colombier int 15029a747e4fSDavid du Colombier usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 15039a747e4fSDavid du Colombier { 15049a747e4fSDavid du Colombier int o, m; 15059a747e4fSDavid du Colombier char *opath, *npath; 15069a747e4fSDavid du Colombier struct stat st, parent; 15079a747e4fSDavid du Colombier 15089a747e4fSDavid du Colombier if(stat(fid->path, &parent) < 0){ 15099a747e4fSDavid du Colombier *ep = strerror(errno); 15109a747e4fSDavid du Colombier return -1; 15119a747e4fSDavid du Colombier } 15129a747e4fSDavid du Colombier 15139a747e4fSDavid du Colombier /* 15149a747e4fSDavid du Colombier * Change group so that created file has expected group 15159a747e4fSDavid du Colombier * by Plan 9 semantics. If that fails, might as well go 15169a747e4fSDavid du Colombier * with the user's default group. 15179a747e4fSDavid du Colombier */ 15189a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 15199a747e4fSDavid du Colombier && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 15209a747e4fSDavid du Colombier return -1; 15219a747e4fSDavid du Colombier 15229a747e4fSDavid du Colombier m = (perm & DMDIR) ? 0777 : 0666; 15239a747e4fSDavid du Colombier perm = perm & (~m | (fid->st.st_mode & m)); 15249a747e4fSDavid du Colombier 15259a747e4fSDavid du Colombier npath = estrpath(fid->path, elem); 15269a747e4fSDavid du Colombier if(perm & DMDIR){ 15279a747e4fSDavid du Colombier if((omode&~ORCLOSE) != OREAD){ 15289a747e4fSDavid du Colombier *ep = Eperm; 15299a747e4fSDavid du Colombier free(npath); 15309a747e4fSDavid du Colombier return -1; 15319a747e4fSDavid du Colombier } 15329a747e4fSDavid du Colombier if(stat(npath, &st) >= 0 || errno != ENOENT){ 15339a747e4fSDavid du Colombier *ep = Eexist; 15349a747e4fSDavid du Colombier free(npath); 15359a747e4fSDavid du Colombier return -1; 15369a747e4fSDavid du Colombier } 15379a747e4fSDavid du Colombier /* race */ 15389a747e4fSDavid du Colombier if(mkdir(npath, perm&0777) < 0){ 15399a747e4fSDavid du Colombier *ep = strerror(errno); 15409a747e4fSDavid du Colombier free(npath); 15419a747e4fSDavid du Colombier return -1; 15429a747e4fSDavid du Colombier } 15439a747e4fSDavid du Colombier if((fid->dir = opendir(npath)) == nil){ 15449a747e4fSDavid du Colombier *ep = strerror(errno); 15459a747e4fSDavid du Colombier remove(npath); /* race */ 15469a747e4fSDavid du Colombier free(npath); 15479a747e4fSDavid du Colombier return -1; 15489a747e4fSDavid du Colombier } 15499a747e4fSDavid du Colombier }else{ 15509a747e4fSDavid du Colombier o = O_CREAT|O_EXCL; 15519a747e4fSDavid du Colombier switch(omode&3){ 15529a747e4fSDavid du Colombier default: 15539a747e4fSDavid du Colombier *ep = "programmer error"; 15549a747e4fSDavid du Colombier return -1; 15559a747e4fSDavid du Colombier case OREAD: 15569a747e4fSDavid du Colombier case OEXEC: 15579a747e4fSDavid du Colombier o |= O_RDONLY; 15589a747e4fSDavid du Colombier break; 15599a747e4fSDavid du Colombier case ORDWR: 15609a747e4fSDavid du Colombier o |= O_RDWR; 15619a747e4fSDavid du Colombier break; 15629a747e4fSDavid du Colombier case OWRITE: 15639a747e4fSDavid du Colombier o |= O_WRONLY; 15649a747e4fSDavid du Colombier break; 15659a747e4fSDavid du Colombier } 15669a747e4fSDavid du Colombier if(omode & OTRUNC) 15679a747e4fSDavid du Colombier o |= O_TRUNC; 15689a747e4fSDavid du Colombier if((fid->fd = open(npath, o, perm&0777)) < 0){ 15699a747e4fSDavid du Colombier if(chatty9p) 15709a747e4fSDavid du Colombier fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 15719a747e4fSDavid du Colombier *ep = strerror(errno); 15729a747e4fSDavid du Colombier free(npath); 15739a747e4fSDavid du Colombier return -1; 15749a747e4fSDavid du Colombier } 15759a747e4fSDavid du Colombier } 15769a747e4fSDavid du Colombier 15779a747e4fSDavid du Colombier opath = fid->path; 15789a747e4fSDavid du Colombier fid->path = npath; 15799a747e4fSDavid du Colombier if(fidstat(fid, ep) < 0){ 15809a747e4fSDavid du Colombier fprint(2, "stat after create on %s failed\n", npath); 15819a747e4fSDavid du Colombier remove(npath); /* race */ 15829a747e4fSDavid du Colombier free(npath); 15839a747e4fSDavid du Colombier fid->path = opath; 15849a747e4fSDavid du Colombier if(fid->fd >= 0){ 15859a747e4fSDavid du Colombier close(fid->fd); 15869a747e4fSDavid du Colombier fid->fd = -1; 15879a747e4fSDavid du Colombier }else{ 15889a747e4fSDavid du Colombier closedir(fid->dir); 15899a747e4fSDavid du Colombier fid->dir = nil; 15909a747e4fSDavid du Colombier } 15919a747e4fSDavid du Colombier return -1; 15929a747e4fSDavid du Colombier } 15939a747e4fSDavid du Colombier fid->omode = omode; 15949a747e4fSDavid du Colombier free(opath); 15959a747e4fSDavid du Colombier return 0; 15969a747e4fSDavid du Colombier } 15979a747e4fSDavid du Colombier 15989a747e4fSDavid du Colombier int 15999a747e4fSDavid du Colombier userremove(Fid *fid, char **ep) 16009a747e4fSDavid du Colombier { 16019a747e4fSDavid du Colombier if(remove(fid->path) < 0){ 16029a747e4fSDavid du Colombier *ep = strerror(errno); 16039a747e4fSDavid du Colombier return -1; 16049a747e4fSDavid du Colombier } 16059a747e4fSDavid du Colombier return 0; 16069a747e4fSDavid du Colombier } 16079a747e4fSDavid du Colombier 16089a747e4fSDavid du Colombier void 16099a747e4fSDavid du Colombier usage(void) 16109a747e4fSDavid du Colombier { 16119a747e4fSDavid du Colombier fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 16129a747e4fSDavid du Colombier exit(1); 16139a747e4fSDavid du Colombier } 16149a747e4fSDavid du Colombier 16159a747e4fSDavid du Colombier int 16169a747e4fSDavid du Colombier main(int argc, char **argv) 16179a747e4fSDavid du Colombier { 16189a747e4fSDavid du Colombier char *authtype; 16199a747e4fSDavid du Colombier int i; 16209a747e4fSDavid du Colombier int fd; 16219a747e4fSDavid du Colombier int logflag; 16229a747e4fSDavid du Colombier 16239a747e4fSDavid du Colombier auth = authmethods[0]; 16249a747e4fSDavid du Colombier logflag = O_WRONLY|O_APPEND|O_CREAT; 16259a747e4fSDavid du Colombier ARGBEGIN{ 16269a747e4fSDavid du Colombier case 'D': 16279a747e4fSDavid du Colombier chatty9p = 1; 16289a747e4fSDavid du Colombier break; 16299a747e4fSDavid du Colombier case 'a': 16309a747e4fSDavid du Colombier authtype = EARGF(usage()); 16319a747e4fSDavid du Colombier auth = nil; 16329a747e4fSDavid du Colombier for(i=0; i<nelem(authmethods); i++) 16339a747e4fSDavid du Colombier if(strcmp(authmethods[i]->name, authtype)==0) 16349a747e4fSDavid du Colombier auth = authmethods[i]; 16359a747e4fSDavid du Colombier if(auth == nil) 16369a747e4fSDavid du Colombier sysfatal("unknown auth type '%s'", authtype); 16379a747e4fSDavid du Colombier break; 16389a747e4fSDavid du Colombier case 'A': 16399a747e4fSDavid du Colombier autharg = EARGF(usage()); 16409a747e4fSDavid du Colombier break; 16419a747e4fSDavid du Colombier case 'l': 16429a747e4fSDavid du Colombier logfile = EARGF(usage()); 16439a747e4fSDavid du Colombier break; 16449a747e4fSDavid du Colombier case 'm': 16459a747e4fSDavid du Colombier msize = strtol(EARGF(usage()), 0, 0); 16469a747e4fSDavid du Colombier break; 16479a747e4fSDavid du Colombier case 'n': 16489a747e4fSDavid du Colombier network = 0; 16499a747e4fSDavid du Colombier break; 16509a747e4fSDavid du Colombier case 'u': 16519a747e4fSDavid du Colombier defaultuser = EARGF(usage()); 16529a747e4fSDavid du Colombier break; 16539a747e4fSDavid du Colombier case 'z': 16549a747e4fSDavid du Colombier logflag |= O_TRUNC; 16559a747e4fSDavid du Colombier }ARGEND 16569a747e4fSDavid du Colombier 16579a747e4fSDavid du Colombier if(argc > 1) 16589a747e4fSDavid du Colombier usage(); 16599a747e4fSDavid du Colombier 16609a747e4fSDavid du Colombier fd = open(logfile, logflag, 0666); 16619a747e4fSDavid du Colombier if(fd < 0) 16629a747e4fSDavid du Colombier sysfatal("cannot open log '%s'", logfile); 16639a747e4fSDavid du Colombier 16649a747e4fSDavid du Colombier if(dup2(fd, 2) < 0) 16659a747e4fSDavid du Colombier sysfatal("cannot dup fd onto stderr"); 16669a747e4fSDavid du Colombier fprint(2, "u9fs\nkill %d\n", (int)getpid()); 16679a747e4fSDavid du Colombier 16689a747e4fSDavid du Colombier fmtinstall('F', fcallconv); 16699a747e4fSDavid du Colombier fmtinstall('D', dirconv); 16709a747e4fSDavid du Colombier fmtinstall('M', dirmodeconv); 16719a747e4fSDavid du Colombier 16729a747e4fSDavid du Colombier rxbuf = emalloc(msize); 16739a747e4fSDavid du Colombier txbuf = emalloc(msize); 16749a747e4fSDavid du Colombier databuf = emalloc(msize); 16759a747e4fSDavid du Colombier 16769a747e4fSDavid du Colombier if(auth->init) 16779a747e4fSDavid du Colombier auth->init(); 16789a747e4fSDavid du Colombier 16799a747e4fSDavid du Colombier if(network) 16809a747e4fSDavid du Colombier getremotehostname(remotehostname, sizeof remotehostname); 16819a747e4fSDavid du Colombier 16829a747e4fSDavid du Colombier if(gethostname(hostname, sizeof hostname) < 0) 16839a747e4fSDavid du Colombier strcpy(hostname, "gnot"); 16849a747e4fSDavid du Colombier 16859a747e4fSDavid du Colombier umask(0); 16869a747e4fSDavid du Colombier 16879a747e4fSDavid du Colombier if(argc == 1) 16889a747e4fSDavid du Colombier if(chroot(argv[0]) < 0) 16899a747e4fSDavid du Colombier sysfatal("chroot '%s' failed", argv[0]); 16909a747e4fSDavid du Colombier 16919a747e4fSDavid du Colombier none = uname2user("none"); 16929a747e4fSDavid du Colombier serve(0, 1); 16939a747e4fSDavid du Colombier return 0; 16949a747e4fSDavid du Colombier } 1695