1*9a747e4fSDavid du Colombier /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */ 2*9a747e4fSDavid du Colombier #include <sys/stat.h> /* for stat, umask */ 3*9a747e4fSDavid du Colombier #include <stdlib.h> /* for malloc */ 4*9a747e4fSDavid du Colombier #include <string.h> /* for strcpy, memmove */ 5*9a747e4fSDavid du Colombier #include <pwd.h> /* for getpwnam, getpwuid */ 6*9a747e4fSDavid du Colombier #include <grp.h> /* for getgrnam, getgrgid */ 7*9a747e4fSDavid du Colombier #include <unistd.h> /* for gethostname, pread, pwrite, read, write */ 8*9a747e4fSDavid du Colombier #include <utime.h> /* for utime */ 9*9a747e4fSDavid du Colombier #include <dirent.h> /* for readdir */ 10*9a747e4fSDavid du Colombier #include <errno.h> /* for errno */ 11*9a747e4fSDavid du Colombier #include <stdio.h> /* for remove [sic] */ 12*9a747e4fSDavid du Colombier #include <fcntl.h> /* for O_RDONLY, etc. */ 133e12c5d1SDavid du Colombier 14*9a747e4fSDavid du Colombier #include <sys/socket.h> /* various networking crud */ 15219b2ee8SDavid du Colombier #include <netinet/in.h> 16219b2ee8SDavid du Colombier #include <netdb.h> 17*9a747e4fSDavid du Colombier 18*9a747e4fSDavid du Colombier #include <plan9.h> 19*9a747e4fSDavid du Colombier #include <fcall.h> 20*9a747e4fSDavid du Colombier #include <oldfcall.h> 21*9a747e4fSDavid du Colombier #include <u9fs.h> 22*9a747e4fSDavid du Colombier 23*9a747e4fSDavid du Colombier /* #ifndef because can be given in makefile */ 24*9a747e4fSDavid du Colombier #ifndef DEFAULTLOG 25*9a747e4fSDavid du Colombier #define DEFAULTLOG "/tmp/u9fs.log" 263e12c5d1SDavid du Colombier #endif 273e12c5d1SDavid du Colombier 28*9a747e4fSDavid du Colombier char *logfile = DEFAULTLOG; 293e12c5d1SDavid du Colombier 30*9a747e4fSDavid du Colombier #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m)) 31*9a747e4fSDavid du Colombier 32*9a747e4fSDavid du Colombier enum { 33*9a747e4fSDavid du Colombier Tdot = 1, 34*9a747e4fSDavid du Colombier Tdotdot 353e12c5d1SDavid du Colombier }; 363e12c5d1SDavid du Colombier 37*9a747e4fSDavid du Colombier enum { 38*9a747e4fSDavid du Colombier P9P1, 39*9a747e4fSDavid du Colombier P9P2000 403e12c5d1SDavid du Colombier }; 413e12c5d1SDavid du Colombier 42*9a747e4fSDavid du Colombier typedef struct User User; 43*9a747e4fSDavid du Colombier struct User { 443e12c5d1SDavid du Colombier int id; 45*9a747e4fSDavid du Colombier gid_t defaultgid; 463e12c5d1SDavid du Colombier char *name; 47*9a747e4fSDavid du Colombier char **mem; /* group members */ 487dd7cddfSDavid du Colombier int nmem; 49*9a747e4fSDavid du Colombier User *next; 503e12c5d1SDavid du Colombier }; 513e12c5d1SDavid du Colombier 52*9a747e4fSDavid du Colombier typedef struct Fid Fid; 53*9a747e4fSDavid du Colombier struct Fid { 54*9a747e4fSDavid du Colombier int fid; 55*9a747e4fSDavid du Colombier char *path; 56*9a747e4fSDavid du Colombier struct stat st; 57*9a747e4fSDavid du Colombier User *u; 58*9a747e4fSDavid du Colombier int omode; 59*9a747e4fSDavid du Colombier DIR *dir; 60*9a747e4fSDavid du Colombier int diroffset; 61*9a747e4fSDavid du Colombier int fd; 62*9a747e4fSDavid du Colombier struct dirent *dirent; 63*9a747e4fSDavid du Colombier Fid *next; 64*9a747e4fSDavid du Colombier Fid *prev; 65*9a747e4fSDavid du Colombier }; 663e12c5d1SDavid du Colombier 67*9a747e4fSDavid du Colombier void* emalloc(size_t); 68*9a747e4fSDavid du Colombier void* erealloc(void*, size_t); 693e12c5d1SDavid du Colombier char* estrdup(char*); 70*9a747e4fSDavid du Colombier char* estrpath(char*, char*); 71*9a747e4fSDavid du Colombier void sysfatal(char*, ...); 72*9a747e4fSDavid du Colombier int okuser(char*); 733e12c5d1SDavid du Colombier 74*9a747e4fSDavid du Colombier void rversion(Fcall*, Fcall*); 75*9a747e4fSDavid du Colombier void rauth(Fcall*, Fcall*); 76*9a747e4fSDavid du Colombier void rattach(Fcall*, Fcall*); 77*9a747e4fSDavid du Colombier void rflush(Fcall*, Fcall*); 78*9a747e4fSDavid du Colombier void rclone(Fcall*, Fcall*); 79*9a747e4fSDavid du Colombier void rwalk(Fcall*, Fcall*); 80*9a747e4fSDavid du Colombier void ropen(Fcall*, Fcall*); 81*9a747e4fSDavid du Colombier void rcreate(Fcall*, Fcall*); 82*9a747e4fSDavid du Colombier void rread(Fcall*, Fcall*); 83*9a747e4fSDavid du Colombier void rwrite(Fcall*, Fcall*); 84*9a747e4fSDavid du Colombier void rclunk(Fcall*, Fcall*); 85*9a747e4fSDavid du Colombier void rstat(Fcall*, Fcall*); 86*9a747e4fSDavid du Colombier void rwstat(Fcall*, Fcall*); 87*9a747e4fSDavid du Colombier void rclwalk(Fcall*, Fcall*); 88*9a747e4fSDavid du Colombier void rremove(Fcall*, Fcall*); 89*9a747e4fSDavid du Colombier 90*9a747e4fSDavid du Colombier User* uname2user(char*); 91*9a747e4fSDavid du Colombier User* gname2user(char*); 92*9a747e4fSDavid du Colombier User* uid2user(int); 93*9a747e4fSDavid du Colombier User* gid2user(int); 94*9a747e4fSDavid du Colombier 95*9a747e4fSDavid du Colombier Fid* newfid(int, char**); 96*9a747e4fSDavid du Colombier Fid* oldfid(int, char**); 97*9a747e4fSDavid du Colombier int fidstat(Fid*, char**); 98*9a747e4fSDavid du Colombier void freefid(Fid*); 99*9a747e4fSDavid du Colombier 100*9a747e4fSDavid du Colombier int userchange(User*, char**); 101*9a747e4fSDavid du Colombier int userwalk(User*, char**, char*, Qid*, char**); 102*9a747e4fSDavid du Colombier int useropen(Fid*, int, char**); 103*9a747e4fSDavid du Colombier int usercreate(Fid*, char*, int, long, char**); 104*9a747e4fSDavid du Colombier int userremove(Fid*, char**); 105*9a747e4fSDavid du Colombier int userperm(User*, char*, int, int); 106*9a747e4fSDavid du Colombier int useringroup(User*, User*); 107*9a747e4fSDavid du Colombier 108*9a747e4fSDavid du Colombier Qid stat2qid(struct stat*); 109*9a747e4fSDavid du Colombier 110*9a747e4fSDavid du Colombier void getfcallold(int, Fcall*, int); 111*9a747e4fSDavid du Colombier void putfcallold(int, Fcall*); 1123e12c5d1SDavid du Colombier 1133e12c5d1SDavid du Colombier char Eauth[] = "authentication failed"; 1143e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range"; 115*9a747e4fSDavid du Colombier char Ebadoffset[] = "bad offset in directory read"; 116*9a747e4fSDavid du Colombier char Ebadusefid[] = "bad use of fid"; 117*9a747e4fSDavid du Colombier char Edirchange[] = "wstat can't convert between files and directories"; 118*9a747e4fSDavid du Colombier char Eexist[] = "file or directory already exists"; 1193e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use"; 120*9a747e4fSDavid du Colombier char Enotdir[] = "not a directory"; 121*9a747e4fSDavid du Colombier char Enotingroup[] = "not a member of proposed group"; 122*9a747e4fSDavid du Colombier char Enotowner[] = "only owner can change group in wstat"; 123*9a747e4fSDavid du Colombier char Eperm[] = "permission denied"; 1243e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files"; 1253e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files"; 126*9a747e4fSDavid du Colombier char Especial[] = "no access to special file"; 1273e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large"; 128*9a747e4fSDavid du Colombier char Eunknowngroup[] = "unknown group"; 129*9a747e4fSDavid du Colombier char Eunknownuser[] = "unknown user"; 130*9a747e4fSDavid du Colombier char Ewstatbuffer[] = "bogus wstat buffer"; 131*9a747e4fSDavid du Colombier 132*9a747e4fSDavid du Colombier ulong msize = IOHDRSZ+8192; 133*9a747e4fSDavid du Colombier uchar* rxbuf; 134*9a747e4fSDavid du Colombier uchar* txbuf; 135*9a747e4fSDavid du Colombier void* databuf; 136*9a747e4fSDavid du Colombier int connected; 137*9a747e4fSDavid du Colombier int devallowed; 138*9a747e4fSDavid du Colombier char* autharg; 139*9a747e4fSDavid du Colombier char* defaultuser; 140*9a747e4fSDavid du Colombier char hostname[256]; 141*9a747e4fSDavid du Colombier char remotehostname[256]; 142*9a747e4fSDavid du Colombier int chatty9p = 0; 143*9a747e4fSDavid du Colombier int network = 1; 144*9a747e4fSDavid du Colombier int old9p = -1; 145*9a747e4fSDavid du Colombier int authed; 146*9a747e4fSDavid du Colombier User* none; 147*9a747e4fSDavid du Colombier 148*9a747e4fSDavid du Colombier Auth *authmethods[] = { /* first is default */ 149*9a747e4fSDavid du Colombier &authrhosts, 150*9a747e4fSDavid du Colombier &authnone, 151*9a747e4fSDavid du Colombier }; 152*9a747e4fSDavid du Colombier 153*9a747e4fSDavid du Colombier Auth *auth; 1543e12c5d1SDavid du Colombier 1557dd7cddfSDavid du Colombier void 156*9a747e4fSDavid du Colombier getfcallnew(int fd, Fcall *fc, int have) 1577dd7cddfSDavid du Colombier { 158*9a747e4fSDavid du Colombier int len; 159*9a747e4fSDavid du Colombier 160*9a747e4fSDavid du Colombier if(have > BIT32SZ) 161*9a747e4fSDavid du Colombier sysfatal("cannot happen"); 162*9a747e4fSDavid du Colombier 163*9a747e4fSDavid du Colombier if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) 164*9a747e4fSDavid du Colombier sysfatal("couldn't read message"); 165*9a747e4fSDavid du Colombier 166*9a747e4fSDavid du Colombier len = GBIT32(rxbuf); 167*9a747e4fSDavid du Colombier if(len <= BIT32SZ) 168*9a747e4fSDavid du Colombier sysfatal("bogus message"); 169*9a747e4fSDavid du Colombier 170*9a747e4fSDavid du Colombier len -= BIT32SZ; 171*9a747e4fSDavid du Colombier if(readn(fd, rxbuf+BIT32SZ, len) != len) 172*9a747e4fSDavid du Colombier sysfatal("short message"); 173*9a747e4fSDavid du Colombier 174*9a747e4fSDavid du Colombier if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) 175*9a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 176*9a747e4fSDavid du Colombier } 177*9a747e4fSDavid du Colombier 178*9a747e4fSDavid du Colombier void 179*9a747e4fSDavid du Colombier getfcallold(int fd, Fcall *fc, int have) 180*9a747e4fSDavid du Colombier { 181*9a747e4fSDavid du Colombier int len, n; 182*9a747e4fSDavid du Colombier 183*9a747e4fSDavid du Colombier if(have > 3) 184*9a747e4fSDavid du Colombier sysfatal("cannot happen"); 185*9a747e4fSDavid du Colombier 186*9a747e4fSDavid du Colombier if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) 187*9a747e4fSDavid du Colombier sysfatal("couldn't read message"); 188*9a747e4fSDavid du Colombier 189*9a747e4fSDavid du Colombier len = oldhdrsize(rxbuf[0]); 190*9a747e4fSDavid du Colombier if(len < 3) 191*9a747e4fSDavid du Colombier sysfatal("bad message %d", rxbuf[0]); 192*9a747e4fSDavid du Colombier if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) 193*9a747e4fSDavid du Colombier sysfatal("couldn't read message"); 194*9a747e4fSDavid du Colombier 195*9a747e4fSDavid du Colombier n = iosize(rxbuf); 196*9a747e4fSDavid du Colombier if(readn(fd, rxbuf+len, n) != n) 197*9a747e4fSDavid du Colombier sysfatal("couldn't read message"); 198*9a747e4fSDavid du Colombier len += n; 199*9a747e4fSDavid du Colombier 200*9a747e4fSDavid du Colombier if(convM2Sold(rxbuf, len, fc) != len) 201*9a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]); 202*9a747e4fSDavid du Colombier } 203*9a747e4fSDavid du Colombier 204*9a747e4fSDavid du Colombier void 205*9a747e4fSDavid du Colombier putfcallnew(int wfd, Fcall *tx) 206*9a747e4fSDavid du Colombier { 207*9a747e4fSDavid du Colombier uint n; 208*9a747e4fSDavid du Colombier 209*9a747e4fSDavid du Colombier if((n = convS2M(tx, txbuf, msize)) == 0) 210*9a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 211*9a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 212*9a747e4fSDavid du Colombier sysfatal("couldn't send message"); 213*9a747e4fSDavid du Colombier } 214*9a747e4fSDavid du Colombier 215*9a747e4fSDavid du Colombier void 216*9a747e4fSDavid du Colombier putfcallold(int wfd, Fcall *tx) 217*9a747e4fSDavid du Colombier { 218*9a747e4fSDavid du Colombier uint n; 219*9a747e4fSDavid du Colombier 220*9a747e4fSDavid du Colombier if((n = convS2Mold(tx, txbuf, msize)) == 0) 221*9a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type); 222*9a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n) 223*9a747e4fSDavid du Colombier sysfatal("couldn't send message"); 224*9a747e4fSDavid du Colombier } 225*9a747e4fSDavid du Colombier 226*9a747e4fSDavid du Colombier void 227*9a747e4fSDavid du Colombier getfcall(int fd, Fcall *fc) 228*9a747e4fSDavid du Colombier { 229*9a747e4fSDavid du Colombier if(old9p == 1){ 230*9a747e4fSDavid du Colombier getfcallold(fd, fc, 0); 231*9a747e4fSDavid du Colombier return; 232*9a747e4fSDavid du Colombier } 233*9a747e4fSDavid du Colombier if(old9p == 0){ 234*9a747e4fSDavid du Colombier getfcallnew(fd, fc, 0); 235*9a747e4fSDavid du Colombier return; 236*9a747e4fSDavid du Colombier } 237*9a747e4fSDavid du Colombier 238*9a747e4fSDavid du Colombier /* auto-detect */ 239*9a747e4fSDavid du Colombier 240*9a747e4fSDavid du Colombier if(readn(fd, rxbuf, 3) != 3) 241*9a747e4fSDavid du Colombier sysfatal("couldn't read message"); 242*9a747e4fSDavid du Colombier 243*9a747e4fSDavid du Colombier /* is it an old (9P1) message? */ 244*9a747e4fSDavid du Colombier if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ 245*9a747e4fSDavid du Colombier old9p = 1; 246*9a747e4fSDavid du Colombier getfcallold(fd, fc, 3); 247*9a747e4fSDavid du Colombier return; 248*9a747e4fSDavid du Colombier } 249*9a747e4fSDavid du Colombier 250*9a747e4fSDavid du Colombier getfcallnew(fd, fc, 3); 251*9a747e4fSDavid du Colombier old9p = 0; 252*9a747e4fSDavid du Colombier } 253*9a747e4fSDavid du Colombier 254*9a747e4fSDavid du Colombier void 255*9a747e4fSDavid du Colombier seterror(Fcall *f, char *error) 256*9a747e4fSDavid du Colombier { 257*9a747e4fSDavid du Colombier f->type = Rerror; 258*9a747e4fSDavid du Colombier f->ename = error ? error : "programmer error"; 2597dd7cddfSDavid du Colombier } 2607dd7cddfSDavid du Colombier 2613e12c5d1SDavid du Colombier int 262*9a747e4fSDavid du Colombier isowner(User *u, Fid *f) 2633e12c5d1SDavid du Colombier { 264*9a747e4fSDavid du Colombier return u->id == f->st.st_uid; 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier 2673e12c5d1SDavid du Colombier void 268*9a747e4fSDavid du Colombier serve(int rfd, int wfd) 2693e12c5d1SDavid du Colombier { 270*9a747e4fSDavid du Colombier Fcall rx, tx; 2713e12c5d1SDavid du Colombier 2723e12c5d1SDavid du Colombier for(;;){ 273*9a747e4fSDavid du Colombier getfcall(rfd, &rx); 2743e12c5d1SDavid du Colombier 275*9a747e4fSDavid du Colombier if(chatty9p) 276*9a747e4fSDavid du Colombier fprint(2, "<- %F\n", &rx); 277*9a747e4fSDavid du Colombier 278*9a747e4fSDavid du Colombier memset(&tx, 0, sizeof tx); 279*9a747e4fSDavid du Colombier tx.type = rx.type+1; 280*9a747e4fSDavid du Colombier tx.tag = rx.tag; 281*9a747e4fSDavid du Colombier switch(rx.type){ 282*9a747e4fSDavid du Colombier case Tflush: 2833e12c5d1SDavid du Colombier break; 284*9a747e4fSDavid du Colombier case Tversion: 285*9a747e4fSDavid du Colombier rversion(&rx, &tx); 286*9a747e4fSDavid du Colombier break; 287*9a747e4fSDavid du Colombier case Tauth: 288*9a747e4fSDavid du Colombier rauth(&rx, &tx); 2893e12c5d1SDavid du Colombier break; 2903e12c5d1SDavid du Colombier case Tattach: 291*9a747e4fSDavid du Colombier rattach(&rx, &tx); 2923e12c5d1SDavid du Colombier break; 2933e12c5d1SDavid du Colombier case Twalk: 294*9a747e4fSDavid du Colombier rwalk(&rx, &tx); 2953e12c5d1SDavid du Colombier break; 2963e12c5d1SDavid du Colombier case Tstat: 297*9a747e4fSDavid du Colombier tx.stat = databuf; 298*9a747e4fSDavid du Colombier rstat(&rx, &tx); 2993e12c5d1SDavid du Colombier break; 3003e12c5d1SDavid du Colombier case Twstat: 301*9a747e4fSDavid du Colombier rwstat(&rx, &tx); 3023e12c5d1SDavid du Colombier break; 3033e12c5d1SDavid du Colombier case Topen: 304*9a747e4fSDavid du Colombier ropen(&rx, &tx); 3053e12c5d1SDavid du Colombier break; 3063e12c5d1SDavid du Colombier case Tcreate: 307*9a747e4fSDavid du Colombier rcreate(&rx, &tx); 3083e12c5d1SDavid du Colombier break; 3093e12c5d1SDavid du Colombier case Tread: 310*9a747e4fSDavid du Colombier tx.data = databuf; 311*9a747e4fSDavid du Colombier rread(&rx, &tx); 3123e12c5d1SDavid du Colombier break; 3133e12c5d1SDavid du Colombier case Twrite: 314*9a747e4fSDavid du Colombier rwrite(&rx, &tx); 3153e12c5d1SDavid du Colombier break; 3163e12c5d1SDavid du Colombier case Tclunk: 317*9a747e4fSDavid du Colombier rclunk(&rx, &tx); 3183e12c5d1SDavid du Colombier break; 3193e12c5d1SDavid du Colombier case Tremove: 320*9a747e4fSDavid du Colombier rremove(&rx, &tx); 3213e12c5d1SDavid du Colombier break; 3223e12c5d1SDavid du Colombier default: 323*9a747e4fSDavid du Colombier fprint(2, "unknown message %F\n", &rx); 324*9a747e4fSDavid du Colombier seterror(&tx, "bad message"); 325*9a747e4fSDavid du Colombier break; 3263e12c5d1SDavid du Colombier } 327*9a747e4fSDavid du Colombier 328*9a747e4fSDavid du Colombier if(chatty9p) 329*9a747e4fSDavid du Colombier fprint(2, "-> %F\n", &tx); 330*9a747e4fSDavid du Colombier 331*9a747e4fSDavid du Colombier (old9p ? putfcallold : putfcallnew)(wfd, &tx); 332*9a747e4fSDavid du Colombier } 3333e12c5d1SDavid du Colombier } 3343e12c5d1SDavid du Colombier 3353e12c5d1SDavid du Colombier void 336*9a747e4fSDavid du Colombier rversion(Fcall *rx, Fcall *tx) 3373e12c5d1SDavid du Colombier { 338*9a747e4fSDavid du Colombier if(msize > rx->msize) 339*9a747e4fSDavid du Colombier msize = rx->msize; 340*9a747e4fSDavid du Colombier tx->msize = msize; 341*9a747e4fSDavid du Colombier if(strncmp(rx->version, "9P", 2) != 0) 342*9a747e4fSDavid du Colombier tx->version = "unknown"; 343*9a747e4fSDavid du Colombier else 344*9a747e4fSDavid du Colombier tx->version = "9P2000"; 3453e12c5d1SDavid du Colombier } 3463e12c5d1SDavid du Colombier 3473e12c5d1SDavid du Colombier void 348*9a747e4fSDavid du Colombier rauth(Fcall *rx, Fcall *tx) 3493e12c5d1SDavid du Colombier { 350*9a747e4fSDavid du Colombier char *e; 3513e12c5d1SDavid du Colombier 352*9a747e4fSDavid du Colombier if((e = auth->auth(rx, tx)) != nil) 353*9a747e4fSDavid du Colombier seterror(tx, e); 3543e12c5d1SDavid du Colombier } 355*9a747e4fSDavid du Colombier 356*9a747e4fSDavid du Colombier void 357*9a747e4fSDavid du Colombier rattach(Fcall *rx, Fcall *tx) 358*9a747e4fSDavid du Colombier { 359*9a747e4fSDavid du Colombier char *e; 360*9a747e4fSDavid du Colombier Fid *fid; 361*9a747e4fSDavid du Colombier User *u; 362*9a747e4fSDavid du Colombier 363*9a747e4fSDavid du Colombier if(rx->aname == nil) 364*9a747e4fSDavid du Colombier rx->aname = ""; 365*9a747e4fSDavid du Colombier 366*9a747e4fSDavid du Colombier if(strcmp(rx->aname, "device") == 0){ 367*9a747e4fSDavid du Colombier if(connected && !devallowed){ 368*9a747e4fSDavid du Colombier seterror(tx, Especial0); 369*9a747e4fSDavid du Colombier return; 370*9a747e4fSDavid du Colombier } 3713e12c5d1SDavid du Colombier devallowed = 1; 3723e12c5d1SDavid du Colombier }else{ 373*9a747e4fSDavid du Colombier if(connected && devallowed){ 374*9a747e4fSDavid du Colombier seterror(tx, Especial1); 375*9a747e4fSDavid du Colombier return; 3763e12c5d1SDavid du Colombier } 377*9a747e4fSDavid du Colombier } 378*9a747e4fSDavid du Colombier 379*9a747e4fSDavid du Colombier if(strcmp(rx->uname, "none") == 0){ 380*9a747e4fSDavid du Colombier if(authed == 0){ 381*9a747e4fSDavid du Colombier seterror(tx, Eauth); 382*9a747e4fSDavid du Colombier return; 383*9a747e4fSDavid du Colombier } 384*9a747e4fSDavid du Colombier } else { 385*9a747e4fSDavid du Colombier if((e = auth->attach(rx, tx)) != nil){ 386*9a747e4fSDavid du Colombier seterror(tx, e); 387*9a747e4fSDavid du Colombier return; 388*9a747e4fSDavid du Colombier } 389*9a747e4fSDavid du Colombier authed++; 390*9a747e4fSDavid du Colombier } 391*9a747e4fSDavid du Colombier 392*9a747e4fSDavid du Colombier if((fid = newfid(rx->fid, &e)) == nil){ 393*9a747e4fSDavid du Colombier seterror(tx, e); 394*9a747e4fSDavid du Colombier return; 395*9a747e4fSDavid du Colombier } 396*9a747e4fSDavid du Colombier fid->path = estrdup("/"); 397*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 398*9a747e4fSDavid du Colombier seterror(tx, e); 399*9a747e4fSDavid du Colombier freefid(fid); 400*9a747e4fSDavid du Colombier return; 401*9a747e4fSDavid du Colombier } 402*9a747e4fSDavid du Colombier 403*9a747e4fSDavid du Colombier if(defaultuser) 404*9a747e4fSDavid du Colombier rx->uname = defaultuser; 405*9a747e4fSDavid du Colombier 406*9a747e4fSDavid du Colombier if((u = uname2user(rx->uname)) == nil || u->id == 0){ 407*9a747e4fSDavid du Colombier /* we don't know anyone named root... */ 408*9a747e4fSDavid du Colombier seterror(tx, Eunknownuser); 409*9a747e4fSDavid du Colombier freefid(fid); 410*9a747e4fSDavid du Colombier return; 411*9a747e4fSDavid du Colombier } 412*9a747e4fSDavid du Colombier 413*9a747e4fSDavid du Colombier fid->u = u; 414*9a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 415*9a747e4fSDavid du Colombier return; 4163e12c5d1SDavid du Colombier } 4173e12c5d1SDavid du Colombier 4183e12c5d1SDavid du Colombier void 419*9a747e4fSDavid du Colombier rwalk(Fcall *rx, Fcall *tx) 4203e12c5d1SDavid du Colombier { 421*9a747e4fSDavid du Colombier int i; 422*9a747e4fSDavid du Colombier char *path, *e; 423*9a747e4fSDavid du Colombier Fid *fid, *nfid; 4243e12c5d1SDavid du Colombier 425*9a747e4fSDavid du Colombier e = nil; 426*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 427*9a747e4fSDavid du Colombier seterror(tx, e); 428*9a747e4fSDavid du Colombier return; 4293e12c5d1SDavid du Colombier } 4303e12c5d1SDavid du Colombier 431*9a747e4fSDavid du Colombier if(fid->omode != -1){ 432*9a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 433*9a747e4fSDavid du Colombier return; 4343e12c5d1SDavid du Colombier } 4353e12c5d1SDavid du Colombier 436*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 437*9a747e4fSDavid du Colombier seterror(tx, e); 438*9a747e4fSDavid du Colombier return; 439*9a747e4fSDavid du Colombier } 4403e12c5d1SDavid du Colombier 441*9a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ 442*9a747e4fSDavid du Colombier seterror(tx, Enotdir); 443*9a747e4fSDavid du Colombier return; 444*9a747e4fSDavid du Colombier } 445*9a747e4fSDavid du Colombier 446*9a747e4fSDavid du Colombier nfid = nil; 447*9a747e4fSDavid du Colombier if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ 448*9a747e4fSDavid du Colombier seterror(tx, e); 449*9a747e4fSDavid du Colombier return; 450*9a747e4fSDavid du Colombier } 451*9a747e4fSDavid du Colombier 452*9a747e4fSDavid du Colombier path = estrdup(fid->path); 453*9a747e4fSDavid du Colombier e = nil; 454*9a747e4fSDavid du Colombier for(i=0; i<rx->nwname; i++) 455*9a747e4fSDavid du Colombier if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) 4563e12c5d1SDavid du Colombier break; 4573e12c5d1SDavid du Colombier 458*9a747e4fSDavid du Colombier if(i == rx->nwname){ /* successful clone or walk */ 459*9a747e4fSDavid du Colombier tx->nwqid = i; 460*9a747e4fSDavid du Colombier if(nfid){ 461*9a747e4fSDavid du Colombier nfid->path = path; 462*9a747e4fSDavid du Colombier nfid->u = fid->u; 4633e12c5d1SDavid du Colombier }else{ 464*9a747e4fSDavid du Colombier free(fid->path); 465*9a747e4fSDavid du Colombier fid->path = path; 4663e12c5d1SDavid du Colombier } 467*9a747e4fSDavid du Colombier }else{ 468*9a747e4fSDavid du Colombier if(i > 0) /* partial walk? */ 469*9a747e4fSDavid du Colombier tx->nwqid = i; 470*9a747e4fSDavid du Colombier else 471*9a747e4fSDavid du Colombier seterror(tx, e); 472*9a747e4fSDavid du Colombier 473*9a747e4fSDavid du Colombier if(nfid) /* clone implicit new fid */ 474*9a747e4fSDavid du Colombier freefid(nfid); 475*9a747e4fSDavid du Colombier free(path); 4763e12c5d1SDavid du Colombier } 477*9a747e4fSDavid du Colombier return; 4783e12c5d1SDavid du Colombier } 4793e12c5d1SDavid du Colombier 4803e12c5d1SDavid du Colombier void 481*9a747e4fSDavid du Colombier ropen(Fcall *rx, Fcall *tx) 4823e12c5d1SDavid du Colombier { 483*9a747e4fSDavid du Colombier char *e; 484*9a747e4fSDavid du Colombier Fid *fid; 4853e12c5d1SDavid du Colombier 486*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 487*9a747e4fSDavid du Colombier seterror(tx, e); 488*9a747e4fSDavid du Colombier return; 4893e12c5d1SDavid du Colombier } 490*9a747e4fSDavid du Colombier 491*9a747e4fSDavid du Colombier if(fid->omode != -1){ 492*9a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 493*9a747e4fSDavid du Colombier return; 4943e12c5d1SDavid du Colombier } 495*9a747e4fSDavid du Colombier 496*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 497*9a747e4fSDavid du Colombier seterror(tx, e); 498*9a747e4fSDavid du Colombier return; 4993e12c5d1SDavid du Colombier } 500*9a747e4fSDavid du Colombier 501*9a747e4fSDavid du Colombier if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ 502*9a747e4fSDavid du Colombier seterror(tx, Especial); 503*9a747e4fSDavid du Colombier return; 5043e12c5d1SDavid du Colombier } 505*9a747e4fSDavid du Colombier 506*9a747e4fSDavid du Colombier if(useropen(fid, rx->mode, &e) < 0){ 507*9a747e4fSDavid du Colombier seterror(tx, e); 508*9a747e4fSDavid du Colombier return; 5093e12c5d1SDavid du Colombier } 510*9a747e4fSDavid du Colombier 511*9a747e4fSDavid du Colombier tx->iounit = 0; 512*9a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 5133e12c5d1SDavid du Colombier } 5143e12c5d1SDavid du Colombier 5153e12c5d1SDavid du Colombier void 516*9a747e4fSDavid du Colombier rcreate(Fcall *rx, Fcall *tx) 5173e12c5d1SDavid du Colombier { 518*9a747e4fSDavid du Colombier char *e; 519*9a747e4fSDavid du Colombier Fid *fid; 520*9a747e4fSDavid du Colombier 521*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 522*9a747e4fSDavid du Colombier seterror(tx, e); 523*9a747e4fSDavid du Colombier return; 524*9a747e4fSDavid du Colombier } 525*9a747e4fSDavid du Colombier 526*9a747e4fSDavid du Colombier if(fid->omode != -1){ 527*9a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 528*9a747e4fSDavid du Colombier return; 529*9a747e4fSDavid du Colombier } 530*9a747e4fSDavid du Colombier 531*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 532*9a747e4fSDavid du Colombier seterror(tx, e); 533*9a747e4fSDavid du Colombier return; 534*9a747e4fSDavid du Colombier } 535*9a747e4fSDavid du Colombier 536*9a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode)){ 537*9a747e4fSDavid du Colombier seterror(tx, Enotdir); 538*9a747e4fSDavid du Colombier return; 539*9a747e4fSDavid du Colombier } 540*9a747e4fSDavid du Colombier 541*9a747e4fSDavid du Colombier if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ 542*9a747e4fSDavid du Colombier seterror(tx, e); 543*9a747e4fSDavid du Colombier return; 544*9a747e4fSDavid du Colombier } 545*9a747e4fSDavid du Colombier 546*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 547*9a747e4fSDavid du Colombier seterror(tx, e); 548*9a747e4fSDavid du Colombier return; 549*9a747e4fSDavid du Colombier } 550*9a747e4fSDavid du Colombier 551*9a747e4fSDavid du Colombier tx->iounit = 0; 552*9a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st); 553*9a747e4fSDavid du Colombier } 554*9a747e4fSDavid du Colombier 555*9a747e4fSDavid du Colombier uchar 556*9a747e4fSDavid du Colombier modebyte(struct stat *st) 557*9a747e4fSDavid du Colombier { 558*9a747e4fSDavid du Colombier uchar b; 559*9a747e4fSDavid du Colombier 560*9a747e4fSDavid du Colombier b = 0; 561*9a747e4fSDavid du Colombier 562*9a747e4fSDavid du Colombier if(S_ISDIR(st->st_mode)) 563*9a747e4fSDavid du Colombier b |= QTDIR; 564*9a747e4fSDavid du Colombier 565*9a747e4fSDavid du Colombier /* no way to test append-only */ 566*9a747e4fSDavid du Colombier /* no real way to test exclusive use, but mark devices as such */ 567*9a747e4fSDavid du Colombier if(S_ISSPECIAL(st->st_mode)) 568*9a747e4fSDavid du Colombier b |= QTEXCL; 569*9a747e4fSDavid du Colombier 570*9a747e4fSDavid du Colombier return b; 571*9a747e4fSDavid du Colombier } 572*9a747e4fSDavid du Colombier 573*9a747e4fSDavid du Colombier ulong 574*9a747e4fSDavid du Colombier plan9mode(struct stat *st) 575*9a747e4fSDavid du Colombier { 576*9a747e4fSDavid du Colombier return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777); 577*9a747e4fSDavid du Colombier } 578*9a747e4fSDavid du Colombier 579*9a747e4fSDavid du Colombier /* 580*9a747e4fSDavid du Colombier * this is for chmod, so don't worry about S_IFDIR 581*9a747e4fSDavid du Colombier */ 582*9a747e4fSDavid du Colombier mode_t 583*9a747e4fSDavid du Colombier unixmode(Dir *d) 584*9a747e4fSDavid du Colombier { 585*9a747e4fSDavid du Colombier return (mode_t)(d->mode&0777); 586*9a747e4fSDavid du Colombier } 587*9a747e4fSDavid du Colombier 588*9a747e4fSDavid du Colombier Qid 589*9a747e4fSDavid du Colombier stat2qid(struct stat *st) 590*9a747e4fSDavid du Colombier { 591*9a747e4fSDavid du Colombier uchar *p, *ep, *q; 592*9a747e4fSDavid du Colombier Qid qid; 593*9a747e4fSDavid du Colombier 594*9a747e4fSDavid du Colombier /* 595*9a747e4fSDavid du Colombier * For now, ignore the device number. 596*9a747e4fSDavid du Colombier */ 597*9a747e4fSDavid du Colombier qid.path = 0; 598*9a747e4fSDavid du Colombier p = (uchar*)&qid.path; 599*9a747e4fSDavid du Colombier ep = p+sizeof(qid.path); 600*9a747e4fSDavid du Colombier q = p+sizeof(ino_t); 601*9a747e4fSDavid du Colombier if(q > ep){ 602*9a747e4fSDavid du Colombier fprint(2, "warning: inode number too big\n"); 603*9a747e4fSDavid du Colombier q = ep; 604*9a747e4fSDavid du Colombier } 605*9a747e4fSDavid du Colombier memmove(p, &st->st_ino, q-p); 606*9a747e4fSDavid du Colombier q = q+sizeof(dev_t); 607*9a747e4fSDavid du Colombier if(q > ep){ 608*9a747e4fSDavid du Colombier /* fprint(2, "warning: inode number + device number too big %d+%d\n", sizeof(ino_t), sizeof(dev_t)); */ 609*9a747e4fSDavid du Colombier q = ep - sizeof(dev_t); 610*9a747e4fSDavid du Colombier if(q < p) 611*9a747e4fSDavid du Colombier fprint(2, "warning: device number too big by itself\n"); 612*9a747e4fSDavid du Colombier else 613*9a747e4fSDavid du Colombier *(dev_t*)q ^= st->st_dev; 614*9a747e4fSDavid du Colombier } 615*9a747e4fSDavid du Colombier 616*9a747e4fSDavid du Colombier qid.vers = st->st_mtime ^ (st->st_size << 8); 617*9a747e4fSDavid du Colombier qid.type = modebyte(st); 618*9a747e4fSDavid du Colombier return qid; 619*9a747e4fSDavid du Colombier } 620*9a747e4fSDavid du Colombier 621*9a747e4fSDavid du Colombier void 622*9a747e4fSDavid du Colombier stat2dir(char *path, struct stat *st, Dir *d) 623*9a747e4fSDavid du Colombier { 624*9a747e4fSDavid du Colombier User *u; 625*9a747e4fSDavid du Colombier char *q; 626*9a747e4fSDavid du Colombier 627*9a747e4fSDavid du Colombier memset(d, 0, sizeof(*d)); 628*9a747e4fSDavid du Colombier d->qid = stat2qid(st); 629*9a747e4fSDavid du Colombier d->mode = plan9mode(st); 630*9a747e4fSDavid du Colombier d->atime = st->st_atime; 631*9a747e4fSDavid du Colombier d->mtime = st->st_mtime; 632*9a747e4fSDavid du Colombier d->length = st->st_size; 633*9a747e4fSDavid du Colombier 634*9a747e4fSDavid du Colombier d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; 635*9a747e4fSDavid du Colombier d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; 636*9a747e4fSDavid du Colombier d->muid = ""; 637*9a747e4fSDavid du Colombier 638*9a747e4fSDavid du Colombier if((q = strrchr(path, '/')) != nil) 639*9a747e4fSDavid du Colombier d->name = q+1; 640*9a747e4fSDavid du Colombier else 641*9a747e4fSDavid du Colombier d->name = path; 642*9a747e4fSDavid du Colombier } 643*9a747e4fSDavid du Colombier 644*9a747e4fSDavid du Colombier void 645*9a747e4fSDavid du Colombier rread(Fcall *rx, Fcall *tx) 646*9a747e4fSDavid du Colombier { 647*9a747e4fSDavid du Colombier char *e, *path; 648*9a747e4fSDavid du Colombier uchar *p, *ep; 649*9a747e4fSDavid du Colombier int n; 650*9a747e4fSDavid du Colombier Fid *fid; 6513e12c5d1SDavid du Colombier Dir d; 652*9a747e4fSDavid du Colombier struct stat st; 6533e12c5d1SDavid du Colombier 654*9a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 655*9a747e4fSDavid du Colombier seterror(tx, Etoolarge); 656*9a747e4fSDavid du Colombier return; 6573e12c5d1SDavid du Colombier } 658*9a747e4fSDavid du Colombier 659*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 660*9a747e4fSDavid du Colombier seterror(tx, e); 661*9a747e4fSDavid du Colombier return; 6623e12c5d1SDavid du Colombier } 663*9a747e4fSDavid du Colombier 664*9a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OWRITE){ 665*9a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 666*9a747e4fSDavid du Colombier return; 667*9a747e4fSDavid du Colombier } 668*9a747e4fSDavid du Colombier 669*9a747e4fSDavid du Colombier if(fid->dir){ 670*9a747e4fSDavid du Colombier if(rx->offset != fid->diroffset){ 671*9a747e4fSDavid du Colombier if(rx->offset != 0){ 672*9a747e4fSDavid du Colombier seterror(tx, Ebadoffset); 673*9a747e4fSDavid du Colombier return; 674*9a747e4fSDavid du Colombier } 675*9a747e4fSDavid du Colombier rewinddir(fid->dir); 676*9a747e4fSDavid du Colombier fid->diroffset = 0; 677*9a747e4fSDavid du Colombier } 678*9a747e4fSDavid du Colombier 679*9a747e4fSDavid du Colombier p = (uchar*)tx->data; 680*9a747e4fSDavid du Colombier ep = (uchar*)tx->data+rx->count; 681*9a747e4fSDavid du Colombier for(;;){ 682*9a747e4fSDavid du Colombier if(p+BIT16SZ >= ep) 6833e12c5d1SDavid du Colombier break; 684*9a747e4fSDavid du Colombier if(fid->dirent == nil) /* one entry cache for when convD2M fails */ 685*9a747e4fSDavid du Colombier if((fid->dirent = readdir(fid->dir)) == nil) 686*9a747e4fSDavid du Colombier break; 687*9a747e4fSDavid du Colombier if(strcmp(fid->dirent->d_name, ".") == 0 688*9a747e4fSDavid du Colombier || strcmp(fid->dirent->d_name, "..") == 0){ 689*9a747e4fSDavid du Colombier fid->dirent = nil; 6903e12c5d1SDavid du Colombier continue; 691*9a747e4fSDavid du Colombier } 692*9a747e4fSDavid du Colombier path = estrpath(fid->path, fid->dirent->d_name); 693*9a747e4fSDavid du Colombier memset(&st, 0, sizeof st); 694*9a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 695*9a747e4fSDavid du Colombier fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); 696*9a747e4fSDavid du Colombier fid->dirent = nil; 697*9a747e4fSDavid du Colombier free(path); 6983e12c5d1SDavid du Colombier continue; 6993e12c5d1SDavid du Colombier } 7003e12c5d1SDavid du Colombier free(path); 701*9a747e4fSDavid du Colombier stat2dir(fid->dirent->d_name, &st, &d); 702*9a747e4fSDavid du Colombier if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) 703*9a747e4fSDavid du Colombier break; 704*9a747e4fSDavid du Colombier p += n; 705*9a747e4fSDavid du Colombier fid->dirent = nil; 7063e12c5d1SDavid du Colombier } 707*9a747e4fSDavid du Colombier tx->count = p - (uchar*)tx->data; 708*9a747e4fSDavid du Colombier fid->diroffset += tx->count; 7093e12c5d1SDavid du Colombier }else{ 710*9a747e4fSDavid du Colombier if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ 711*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 712*9a747e4fSDavid du Colombier return; 713219b2ee8SDavid du Colombier } 714*9a747e4fSDavid du Colombier tx->count = n; 7153e12c5d1SDavid du Colombier } 7163e12c5d1SDavid du Colombier } 7173e12c5d1SDavid du Colombier 7183e12c5d1SDavid du Colombier void 719*9a747e4fSDavid du Colombier rwrite(Fcall *rx, Fcall *tx) 7203e12c5d1SDavid du Colombier { 721*9a747e4fSDavid du Colombier char *e; 722*9a747e4fSDavid du Colombier Fid *fid; 7233e12c5d1SDavid du Colombier int n; 7243e12c5d1SDavid du Colombier 725*9a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){ 726*9a747e4fSDavid du Colombier seterror(tx, Etoolarge); 7277dd7cddfSDavid du Colombier return; 7287dd7cddfSDavid du Colombier } 729*9a747e4fSDavid du Colombier 730*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 731*9a747e4fSDavid du Colombier seterror(tx, e); 732*9a747e4fSDavid du Colombier return; 7333e12c5d1SDavid du Colombier } 734*9a747e4fSDavid du Colombier 735*9a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ 736*9a747e4fSDavid du Colombier seterror(tx, Ebadusefid); 737*9a747e4fSDavid du Colombier return; 738*9a747e4fSDavid du Colombier } 739*9a747e4fSDavid du Colombier 740*9a747e4fSDavid du Colombier if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ 741*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 742*9a747e4fSDavid du Colombier return; 743*9a747e4fSDavid du Colombier } 744*9a747e4fSDavid du Colombier tx->count = n; 7453e12c5d1SDavid du Colombier } 7463e12c5d1SDavid du Colombier 7473e12c5d1SDavid du Colombier void 748*9a747e4fSDavid du Colombier rclunk(Fcall *rx, Fcall *tx) 7493e12c5d1SDavid du Colombier { 750*9a747e4fSDavid du Colombier char *e; 751*9a747e4fSDavid du Colombier Fid *fid; 7523e12c5d1SDavid du Colombier 753*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 754*9a747e4fSDavid du Colombier seterror(tx, e); 755*9a747e4fSDavid du Colombier return; 756*9a747e4fSDavid du Colombier } 757*9a747e4fSDavid du Colombier if(fid->omode != -1 && fid->omode&ORCLOSE) 758*9a747e4fSDavid du Colombier remove(fid->path); 759*9a747e4fSDavid du Colombier freefid(fid); 7603e12c5d1SDavid du Colombier } 761219b2ee8SDavid du Colombier 762*9a747e4fSDavid du Colombier void 763*9a747e4fSDavid du Colombier rremove(Fcall *rx, Fcall *tx) 7643e12c5d1SDavid du Colombier { 765*9a747e4fSDavid du Colombier char *e; 766*9a747e4fSDavid du Colombier Fid *fid; 7673e12c5d1SDavid du Colombier 768*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 769*9a747e4fSDavid du Colombier seterror(tx, e); 770*9a747e4fSDavid du Colombier return; 7713e12c5d1SDavid du Colombier } 772*9a747e4fSDavid du Colombier if(userremove(fid, &e) < 0) 773*9a747e4fSDavid du Colombier seterror(tx, e); 774*9a747e4fSDavid du Colombier freefid(fid); 775*9a747e4fSDavid du Colombier } 776*9a747e4fSDavid du Colombier 777*9a747e4fSDavid du Colombier void 778*9a747e4fSDavid du Colombier rstat(Fcall *rx, Fcall *tx) 779*9a747e4fSDavid du Colombier { 780*9a747e4fSDavid du Colombier char *e; 781*9a747e4fSDavid du Colombier Fid *fid; 782*9a747e4fSDavid du Colombier Dir d; 783*9a747e4fSDavid du Colombier 784*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 785*9a747e4fSDavid du Colombier seterror(tx, e); 786*9a747e4fSDavid du Colombier return; 787*9a747e4fSDavid du Colombier } 788*9a747e4fSDavid du Colombier 789*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 790*9a747e4fSDavid du Colombier seterror(tx, e); 791*9a747e4fSDavid du Colombier return; 792*9a747e4fSDavid du Colombier } 793*9a747e4fSDavid du Colombier 794*9a747e4fSDavid du Colombier stat2dir(fid->path, &fid->st, &d); 795*9a747e4fSDavid du Colombier if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) 796*9a747e4fSDavid du Colombier seterror(tx, "convD2M fails"); 797*9a747e4fSDavid du Colombier } 798*9a747e4fSDavid du Colombier 799*9a747e4fSDavid du Colombier void 800*9a747e4fSDavid du Colombier rwstat(Fcall *rx, Fcall *tx) 801*9a747e4fSDavid du Colombier { 802*9a747e4fSDavid du Colombier char *e; 803*9a747e4fSDavid du Colombier char *p, *old, *new, *dir; 804*9a747e4fSDavid du Colombier gid_t gid; 805*9a747e4fSDavid du Colombier Dir d; 806*9a747e4fSDavid du Colombier Fid *fid; 807*9a747e4fSDavid du Colombier 808*9a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){ 809*9a747e4fSDavid du Colombier seterror(tx, e); 810*9a747e4fSDavid du Colombier return; 811*9a747e4fSDavid du Colombier } 812*9a747e4fSDavid du Colombier 813*9a747e4fSDavid du Colombier /* 814*9a747e4fSDavid du Colombier * wstat is supposed to be atomic. 815*9a747e4fSDavid du Colombier * we check all the things we can before trying anything. 816*9a747e4fSDavid du Colombier * still, if we are told to truncate a file and rename it and only 817*9a747e4fSDavid du Colombier * one works, we're screwed. in such cases we leave things 818*9a747e4fSDavid du Colombier * half broken and return an error. it's hardly perfect. 819*9a747e4fSDavid du Colombier */ 820*9a747e4fSDavid du Colombier if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ 821*9a747e4fSDavid du Colombier seterror(tx, Ewstatbuffer); 822*9a747e4fSDavid du Colombier return; 823*9a747e4fSDavid du Colombier } 824*9a747e4fSDavid du Colombier 825*9a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){ 826*9a747e4fSDavid du Colombier seterror(tx, e); 827*9a747e4fSDavid du Colombier return; 828*9a747e4fSDavid du Colombier } 829*9a747e4fSDavid du Colombier 830*9a747e4fSDavid du Colombier /* 831*9a747e4fSDavid du Colombier * The casting is necessary because d.mode is ulong and might, 832*9a747e4fSDavid du Colombier * on some systems, be 64 bits. We only want to compare the 833*9a747e4fSDavid du Colombier * bottom 32 bits, since that's all that gets sent in the protocol. 834*9a747e4fSDavid du Colombier * 835*9a747e4fSDavid du Colombier * Same situation for d.mtime and d.length (although that last check 836*9a747e4fSDavid du Colombier * is admittedly superfluous, given the current lack of 128-bit machines). 837*9a747e4fSDavid du Colombier */ 838*9a747e4fSDavid du Colombier gid = (gid_t)-1; 839*9a747e4fSDavid du Colombier if(d.gid[0] != '\0'){ 840*9a747e4fSDavid du Colombier User *g; 841*9a747e4fSDavid du Colombier 842*9a747e4fSDavid du Colombier g = gname2user(d.gid); 843*9a747e4fSDavid du Colombier if(g == nil){ 844*9a747e4fSDavid du Colombier seterror(tx, Eunknowngroup); 845*9a747e4fSDavid du Colombier return; 846*9a747e4fSDavid du Colombier } 847*9a747e4fSDavid du Colombier gid = (gid_t)g->id; 848*9a747e4fSDavid du Colombier 849*9a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(gid), &e) < 0){ 850*9a747e4fSDavid du Colombier seterror(tx, e); 851*9a747e4fSDavid du Colombier return; 852*9a747e4fSDavid du Colombier } 853*9a747e4fSDavid du Colombier } 854*9a747e4fSDavid du Colombier 855*9a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ 856*9a747e4fSDavid du Colombier seterror(tx, Edirchange); 857*9a747e4fSDavid du Colombier return; 858*9a747e4fSDavid du Colombier } 859*9a747e4fSDavid du Colombier 860*9a747e4fSDavid du Colombier if(strcmp(fid->path, "/") == 0){ 861*9a747e4fSDavid du Colombier seterror(tx, "no wstat of root"); 862*9a747e4fSDavid du Colombier return; 863*9a747e4fSDavid du Colombier } 864*9a747e4fSDavid du Colombier 865*9a747e4fSDavid du Colombier /* 866*9a747e4fSDavid du Colombier * try things in increasing order of harm to the file. 867*9a747e4fSDavid du Colombier * mtime should come after truncate so that if you 868*9a747e4fSDavid du Colombier * do both the mtime actually takes effect, but i'd rather 869*9a747e4fSDavid du Colombier * leave truncate until last. 870*9a747e4fSDavid du Colombier * (see above comment about atomicity). 871*9a747e4fSDavid du Colombier */ 872*9a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ 873*9a747e4fSDavid du Colombier if(chatty9p) 874*9a747e4fSDavid du Colombier fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); 875*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 876*9a747e4fSDavid du Colombier return; 877*9a747e4fSDavid du Colombier } 878*9a747e4fSDavid du Colombier 879*9a747e4fSDavid du Colombier if((u32int)d.mtime != (u32int)~0){ 880*9a747e4fSDavid du Colombier struct utimbuf t; 881*9a747e4fSDavid du Colombier 882*9a747e4fSDavid du Colombier t.actime = 0; 883*9a747e4fSDavid du Colombier t.modtime = d.mtime; 884*9a747e4fSDavid du Colombier if(utime(fid->path, &t) < 0){ 885*9a747e4fSDavid du Colombier if(chatty9p) 886*9a747e4fSDavid du Colombier fprint(2, "utime(%s) failed\n", fid->path); 887*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 888*9a747e4fSDavid du Colombier return; 889*9a747e4fSDavid du Colombier } 890*9a747e4fSDavid du Colombier } 891*9a747e4fSDavid du Colombier 892*9a747e4fSDavid du Colombier if(gid != (gid_t)-1 && gid != fid->st.st_gid){ 893*9a747e4fSDavid du Colombier if(chown(fid->path, (uid_t)-1, gid) < 0){ 894*9a747e4fSDavid du Colombier if(chatty9p) 895*9a747e4fSDavid du Colombier fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); 896*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 897*9a747e4fSDavid du Colombier return; 898*9a747e4fSDavid du Colombier } 899*9a747e4fSDavid du Colombier } 900*9a747e4fSDavid du Colombier 901*9a747e4fSDavid du Colombier if(d.name[0]){ 902*9a747e4fSDavid du Colombier old = fid->path; 903*9a747e4fSDavid du Colombier dir = estrdup(fid->path); 904*9a747e4fSDavid du Colombier if((p = strrchr(dir, '/')) > dir) 905*9a747e4fSDavid du Colombier *p = '\0'; 9063e12c5d1SDavid du Colombier else{ 907*9a747e4fSDavid du Colombier seterror(tx, "whoops: can't happen in u9fs"); 908*9a747e4fSDavid du Colombier return; 9093e12c5d1SDavid du Colombier } 9103e12c5d1SDavid du Colombier 911*9a747e4fSDavid du Colombier new = estrpath(dir, d.name); 912*9a747e4fSDavid du Colombier if(strcmp(old, new) != 0 && rename(old, new) < 0){ 913*9a747e4fSDavid du Colombier if(chatty9p) 914*9a747e4fSDavid du Colombier fprint(2, "rename(%s, %s) failed\n", old, new); 915*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 916*9a747e4fSDavid du Colombier free(new); 917*9a747e4fSDavid du Colombier free(dir); 918*9a747e4fSDavid du Colombier return; 919*9a747e4fSDavid du Colombier } 920*9a747e4fSDavid du Colombier fid->path = new; 921*9a747e4fSDavid du Colombier free(old); 922*9a747e4fSDavid du Colombier free(dir); 923*9a747e4fSDavid du Colombier } 924*9a747e4fSDavid du Colombier 925*9a747e4fSDavid du Colombier if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ 926*9a747e4fSDavid du Colombier fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); 927*9a747e4fSDavid du Colombier seterror(tx, strerror(errno)); 928*9a747e4fSDavid du Colombier return; 929*9a747e4fSDavid du Colombier } 930*9a747e4fSDavid du Colombier } 931*9a747e4fSDavid du Colombier 932*9a747e4fSDavid du Colombier /* 933*9a747e4fSDavid du Colombier * we keep a table by numeric id. by name lookups happen infrequently 934*9a747e4fSDavid du Colombier * while by-number lookups happen once for every directory entry read 935*9a747e4fSDavid du Colombier * and every stat request. 936*9a747e4fSDavid du Colombier */ 937*9a747e4fSDavid du Colombier User *utab[64]; 938*9a747e4fSDavid du Colombier User *gtab[64]; 939*9a747e4fSDavid du Colombier 940*9a747e4fSDavid du Colombier User* 941*9a747e4fSDavid du Colombier adduser(struct passwd *p) 9423e12c5d1SDavid du Colombier { 943*9a747e4fSDavid du Colombier User *u; 9443e12c5d1SDavid du Colombier 945*9a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 946*9a747e4fSDavid du Colombier u->id = p->pw_uid; 947*9a747e4fSDavid du Colombier u->name = estrdup(p->pw_name); 948*9a747e4fSDavid du Colombier u->next = utab[p->pw_uid%nelem(utab)]; 949*9a747e4fSDavid du Colombier u->defaultgid = p->pw_gid; 950*9a747e4fSDavid du Colombier utab[p->pw_uid%nelem(utab)] = u; 951*9a747e4fSDavid du Colombier return u; 9523e12c5d1SDavid du Colombier } 9533e12c5d1SDavid du Colombier 9543e12c5d1SDavid du Colombier int 955*9a747e4fSDavid du Colombier useringroup(User *u, User *g) 9563e12c5d1SDavid du Colombier { 957*9a747e4fSDavid du Colombier int i; 958*9a747e4fSDavid du Colombier 959*9a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++) 960*9a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0) 9613e12c5d1SDavid du Colombier return 1; 962*9a747e4fSDavid du Colombier 963*9a747e4fSDavid du Colombier /* 964*9a747e4fSDavid du Colombier * Hack around common Unix problem that everyone has 965*9a747e4fSDavid du Colombier * default group "user" but /etc/group lists no members. 966*9a747e4fSDavid du Colombier */ 967*9a747e4fSDavid du Colombier if(u->defaultgid == g->id) 968*9a747e4fSDavid du Colombier return 1; 9693e12c5d1SDavid du Colombier return 0; 9703e12c5d1SDavid du Colombier } 9713e12c5d1SDavid du Colombier 972*9a747e4fSDavid du Colombier User* 973*9a747e4fSDavid du Colombier addgroup(struct group *g) 9743e12c5d1SDavid du Colombier { 975*9a747e4fSDavid du Colombier User *u; 976*9a747e4fSDavid du Colombier char **p; 9773e12c5d1SDavid du Colombier int n; 9783e12c5d1SDavid du Colombier 979*9a747e4fSDavid du Colombier u = emalloc(sizeof(*u)); 980*9a747e4fSDavid du Colombier n = 0; 981*9a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 982*9a747e4fSDavid du Colombier n++; 983*9a747e4fSDavid du Colombier u->mem = emalloc(sizeof(u->mem[0])*n); 984*9a747e4fSDavid du Colombier n = 0; 985*9a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++) 986*9a747e4fSDavid du Colombier u->mem[n++] = estrdup(*p); 987*9a747e4fSDavid du Colombier u->nmem = n; 988*9a747e4fSDavid du Colombier u->id = g->gr_gid; 989*9a747e4fSDavid du Colombier u->name = estrdup(g->gr_name); 990*9a747e4fSDavid du Colombier u->next = gtab[g->gr_gid%nelem(gtab)]; 991*9a747e4fSDavid du Colombier gtab[g->gr_gid%nelem(gtab)] = u; 992*9a747e4fSDavid du Colombier return u; 9933e12c5d1SDavid du Colombier } 9943e12c5d1SDavid du Colombier 995*9a747e4fSDavid du Colombier User* 996*9a747e4fSDavid du Colombier uname2user(char *name) 9977dd7cddfSDavid du Colombier { 9987dd7cddfSDavid du Colombier int i; 999*9a747e4fSDavid du Colombier User *u; 1000*9a747e4fSDavid du Colombier struct passwd *p; 10017dd7cddfSDavid du Colombier 1002*9a747e4fSDavid du Colombier for(i=0; i<nelem(utab); i++) 1003*9a747e4fSDavid du Colombier for(u=utab[i]; u; u=u->next) 1004*9a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 1005*9a747e4fSDavid du Colombier return u; 1006*9a747e4fSDavid du Colombier 1007*9a747e4fSDavid du Colombier if((p = getpwnam(name)) == nil) 1008*9a747e4fSDavid du Colombier return nil; 1009*9a747e4fSDavid du Colombier return adduser(p); 10107dd7cddfSDavid du Colombier } 10117dd7cddfSDavid du Colombier 1012*9a747e4fSDavid du Colombier User* 1013*9a747e4fSDavid du Colombier uid2user(int id) 1014*9a747e4fSDavid du Colombier { 1015*9a747e4fSDavid du Colombier User *u; 1016*9a747e4fSDavid du Colombier struct passwd *p; 1017*9a747e4fSDavid du Colombier 1018*9a747e4fSDavid du Colombier for(u=utab[id%nelem(utab)]; u; u=u->next) 1019*9a747e4fSDavid du Colombier if(u->id == id) 1020*9a747e4fSDavid du Colombier return u; 1021*9a747e4fSDavid du Colombier 1022*9a747e4fSDavid du Colombier if((p = getpwuid(id)) == nil) 1023*9a747e4fSDavid du Colombier return nil; 1024*9a747e4fSDavid du Colombier return adduser(p); 1025*9a747e4fSDavid du Colombier } 1026*9a747e4fSDavid du Colombier 1027*9a747e4fSDavid du Colombier User* 1028*9a747e4fSDavid du Colombier gname2user(char *name) 10293e12c5d1SDavid du Colombier { 10303e12c5d1SDavid du Colombier int i; 1031*9a747e4fSDavid du Colombier User *u; 1032*9a747e4fSDavid du Colombier struct group *g; 10333e12c5d1SDavid du Colombier 1034*9a747e4fSDavid du Colombier for(i=0; i<nelem(gtab); i++) 1035*9a747e4fSDavid du Colombier for(u=gtab[i]; u; u=u->next) 1036*9a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0) 1037*9a747e4fSDavid du Colombier return u; 1038*9a747e4fSDavid du Colombier 1039*9a747e4fSDavid du Colombier if((g = getgrnam(name)) == nil) 1040*9a747e4fSDavid du Colombier return nil; 1041*9a747e4fSDavid du Colombier return addgroup(g); 1042*9a747e4fSDavid du Colombier } 1043*9a747e4fSDavid du Colombier 1044*9a747e4fSDavid du Colombier User* 1045*9a747e4fSDavid du Colombier gid2user(int id) 1046*9a747e4fSDavid du Colombier { 1047*9a747e4fSDavid du Colombier User *u; 1048*9a747e4fSDavid du Colombier struct group *g; 1049*9a747e4fSDavid du Colombier 1050*9a747e4fSDavid du Colombier for(u=gtab[id%nelem(gtab)]; u; u=u->next) 1051*9a747e4fSDavid du Colombier if(u->id == id) 1052*9a747e4fSDavid du Colombier return u; 1053*9a747e4fSDavid du Colombier 1054*9a747e4fSDavid du Colombier if((g = getgrgid(id)) == nil) 1055*9a747e4fSDavid du Colombier return nil; 1056*9a747e4fSDavid du Colombier return addgroup(g); 10573e12c5d1SDavid du Colombier } 10583e12c5d1SDavid du Colombier 10593e12c5d1SDavid du Colombier void 1060*9a747e4fSDavid du Colombier sysfatal(char *fmt, ...) 10613e12c5d1SDavid du Colombier { 1062*9a747e4fSDavid du Colombier char buf[1024]; 1063*9a747e4fSDavid du Colombier va_list va; 10643e12c5d1SDavid du Colombier 1065*9a747e4fSDavid du Colombier va_start(va, fmt); 1066*9a747e4fSDavid du Colombier doprint(buf, buf+sizeof buf, fmt, va); 1067*9a747e4fSDavid du Colombier va_end(va); 1068*9a747e4fSDavid du Colombier fprint(2, "u9fs: %s\n", buf); 1069*9a747e4fSDavid du Colombier fprint(2, "last unix error: %s\n", strerror(errno)); 10703e12c5d1SDavid du Colombier exit(1); 10713e12c5d1SDavid du Colombier } 10723e12c5d1SDavid du Colombier 10733e12c5d1SDavid du Colombier void* 1074*9a747e4fSDavid du Colombier emalloc(size_t n) 1075*9a747e4fSDavid du Colombier { 1076*9a747e4fSDavid du Colombier void *p; 1077*9a747e4fSDavid du Colombier 1078*9a747e4fSDavid du Colombier p = malloc(n); 1079*9a747e4fSDavid du Colombier if(p == 0) 1080*9a747e4fSDavid du Colombier sysfatal("malloc(%ld) fails", (long)n); 1081*9a747e4fSDavid du Colombier memset(p, 0, n); 1082*9a747e4fSDavid du Colombier return p; 1083*9a747e4fSDavid du Colombier } 1084*9a747e4fSDavid du Colombier 1085*9a747e4fSDavid du Colombier void* 1086*9a747e4fSDavid du Colombier erealloc(void *p, size_t n) 10873e12c5d1SDavid du Colombier { 10883e12c5d1SDavid du Colombier if(p == 0) 10893e12c5d1SDavid du Colombier p = malloc(n); 10903e12c5d1SDavid du Colombier else 10913e12c5d1SDavid du Colombier p = realloc(p, n); 10923e12c5d1SDavid du Colombier if(p == 0) 1093*9a747e4fSDavid du Colombier sysfatal("realloc(..., %ld) fails", (long)n); 10943e12c5d1SDavid du Colombier return p; 10953e12c5d1SDavid du Colombier } 10963e12c5d1SDavid du Colombier 10973e12c5d1SDavid du Colombier char* 10983e12c5d1SDavid du Colombier estrdup(char *p) 10993e12c5d1SDavid du Colombier { 11003e12c5d1SDavid du Colombier p = strdup(p); 11013e12c5d1SDavid du Colombier if(p == 0) 1102*9a747e4fSDavid du Colombier sysfatal("strdup(%.20s) fails", p); 11033e12c5d1SDavid du Colombier return p; 11043e12c5d1SDavid du Colombier } 1105219b2ee8SDavid du Colombier 1106*9a747e4fSDavid du Colombier char* 1107*9a747e4fSDavid du Colombier estrpath(char *p, char *q) 1108219b2ee8SDavid du Colombier { 1109*9a747e4fSDavid du Colombier char *r, *s; 1110219b2ee8SDavid du Colombier 1111*9a747e4fSDavid du Colombier if(strcmp(q, "..") == 0){ 1112*9a747e4fSDavid du Colombier r = estrdup(p); 1113*9a747e4fSDavid du Colombier if((s = strrchr(r, '/')) && s > r) 1114*9a747e4fSDavid du Colombier *s = '\0'; 1115*9a747e4fSDavid du Colombier else if(s == r) 1116*9a747e4fSDavid du Colombier s[1] = '\0'; 1117*9a747e4fSDavid du Colombier return r; 1118219b2ee8SDavid du Colombier } 1119*9a747e4fSDavid du Colombier 1120*9a747e4fSDavid du Colombier r = emalloc(strlen(p)+1+strlen(q)+1); 1121*9a747e4fSDavid du Colombier strcpy(r, p); 1122*9a747e4fSDavid du Colombier if(r[0]=='\0' || r[strlen(r)-1] != '/') 1123*9a747e4fSDavid du Colombier strcat(r, "/"); 1124*9a747e4fSDavid du Colombier strcat(r, q); 1125*9a747e4fSDavid du Colombier return r; 1126*9a747e4fSDavid du Colombier } 1127*9a747e4fSDavid du Colombier 1128*9a747e4fSDavid du Colombier Fid *newfid(int, char**); 1129*9a747e4fSDavid du Colombier Fid *oldfid(int, char**); 1130*9a747e4fSDavid du Colombier int fidstat(Fid*, char**); 1131*9a747e4fSDavid du Colombier void freefid(Fid*); 1132*9a747e4fSDavid du Colombier 1133*9a747e4fSDavid du Colombier Fid *fidtab[1]; 1134*9a747e4fSDavid du Colombier 1135*9a747e4fSDavid du Colombier Fid* 1136*9a747e4fSDavid du Colombier lookupfid(int fid) 1137*9a747e4fSDavid du Colombier { 1138*9a747e4fSDavid du Colombier Fid *f; 1139*9a747e4fSDavid du Colombier 1140*9a747e4fSDavid du Colombier for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 1141*9a747e4fSDavid du Colombier if(f->fid == fid) 1142*9a747e4fSDavid du Colombier return f; 1143*9a747e4fSDavid du Colombier return nil; 1144*9a747e4fSDavid du Colombier } 1145*9a747e4fSDavid du Colombier 1146*9a747e4fSDavid du Colombier Fid* 1147*9a747e4fSDavid du Colombier newfid(int fid, char **ep) 1148*9a747e4fSDavid du Colombier { 1149*9a747e4fSDavid du Colombier Fid *f; 1150*9a747e4fSDavid du Colombier 1151*9a747e4fSDavid du Colombier if(lookupfid(fid) != nil){ 1152*9a747e4fSDavid du Colombier *ep = Efidactive; 1153*9a747e4fSDavid du Colombier return nil; 1154*9a747e4fSDavid du Colombier } 1155*9a747e4fSDavid du Colombier 1156*9a747e4fSDavid du Colombier f = emalloc(sizeof(*f)); 1157*9a747e4fSDavid du Colombier f->next = fidtab[fid%nelem(fidtab)]; 1158*9a747e4fSDavid du Colombier if(f->next) 1159*9a747e4fSDavid du Colombier f->next->prev = f; 1160*9a747e4fSDavid du Colombier fidtab[fid%nelem(fidtab)] = f; 1161*9a747e4fSDavid du Colombier f->fid = fid; 1162*9a747e4fSDavid du Colombier f->fd = -1; 1163*9a747e4fSDavid du Colombier f->omode = -1; 1164*9a747e4fSDavid du Colombier return f; 1165*9a747e4fSDavid du Colombier } 1166*9a747e4fSDavid du Colombier 1167*9a747e4fSDavid du Colombier Fid* 1168*9a747e4fSDavid du Colombier oldfid(int fid, char **ep) 1169*9a747e4fSDavid du Colombier { 1170*9a747e4fSDavid du Colombier Fid *f; 1171*9a747e4fSDavid du Colombier 1172*9a747e4fSDavid du Colombier if((f = lookupfid(fid)) == nil){ 1173*9a747e4fSDavid du Colombier *ep = Ebadfid; 1174*9a747e4fSDavid du Colombier return nil; 1175*9a747e4fSDavid du Colombier } 1176*9a747e4fSDavid du Colombier 1177*9a747e4fSDavid du Colombier if(userchange(f->u, ep) < 0) 1178*9a747e4fSDavid du Colombier return nil; 1179*9a747e4fSDavid du Colombier 1180*9a747e4fSDavid du Colombier return f; 1181*9a747e4fSDavid du Colombier } 1182*9a747e4fSDavid du Colombier 1183*9a747e4fSDavid du Colombier void 1184*9a747e4fSDavid du Colombier freefid(Fid *f) 1185*9a747e4fSDavid du Colombier { 1186*9a747e4fSDavid du Colombier if(f->prev) 1187*9a747e4fSDavid du Colombier f->prev->next = f->next; 1188*9a747e4fSDavid du Colombier else 1189*9a747e4fSDavid du Colombier fidtab[f->fid%nelem(fidtab)] = f->next; 1190*9a747e4fSDavid du Colombier if(f->next) 1191*9a747e4fSDavid du Colombier f->next->prev = f->prev; 1192*9a747e4fSDavid du Colombier if(f->dir) 1193*9a747e4fSDavid du Colombier closedir(f->dir); 1194*9a747e4fSDavid du Colombier if(f->fd) 1195*9a747e4fSDavid du Colombier close(f->fd); 1196*9a747e4fSDavid du Colombier free(f->path); 1197*9a747e4fSDavid du Colombier free(f); 1198*9a747e4fSDavid du Colombier } 1199*9a747e4fSDavid du Colombier 1200*9a747e4fSDavid du Colombier int 1201*9a747e4fSDavid du Colombier fidstat(Fid *fid, char **ep) 1202*9a747e4fSDavid du Colombier { 1203*9a747e4fSDavid du Colombier if(stat(fid->path, &fid->st) < 0){ 1204*9a747e4fSDavid du Colombier fprint(2, "fidstat(%s) failed\n", fid->path); 1205*9a747e4fSDavid du Colombier if(ep) 1206*9a747e4fSDavid du Colombier *ep = strerror(errno); 1207*9a747e4fSDavid du Colombier return -1; 1208*9a747e4fSDavid du Colombier } 1209*9a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)) 1210*9a747e4fSDavid du Colombier fid->st.st_size = 0; 1211*9a747e4fSDavid du Colombier return 0; 1212*9a747e4fSDavid du Colombier } 1213*9a747e4fSDavid du Colombier 1214*9a747e4fSDavid du Colombier int 1215*9a747e4fSDavid du Colombier userchange(User *u, char **ep) 1216*9a747e4fSDavid du Colombier { 1217*9a747e4fSDavid du Colombier if(!defaultuser && setreuid(0, 0) < 0){ 1218*9a747e4fSDavid du Colombier fprint(2, "setreuid(0, 0) failed\n"); 1219*9a747e4fSDavid du Colombier *ep = "cannot setuid back to root"; 1220*9a747e4fSDavid du Colombier return -1; 1221*9a747e4fSDavid du Colombier } 1222*9a747e4fSDavid du Colombier 1223*9a747e4fSDavid du Colombier /* 1224*9a747e4fSDavid du Colombier * Initgroups does not appear to be SUSV standard. 1225*9a747e4fSDavid du Colombier * But it exists on SGI and on Linux, which makes me 1226*9a747e4fSDavid du Colombier * think it's standard enough. We have to do something 1227*9a747e4fSDavid du Colombier * like this, and the closest other function I can find is 1228*9a747e4fSDavid du Colombier * setgroups (which initgroups eventually calls). 1229*9a747e4fSDavid du Colombier * Setgroups is the same as far as standardization though, 1230*9a747e4fSDavid du Colombier * so we're stuck using a non-SUSV call. Sigh. 1231*9a747e4fSDavid du Colombier */ 1232*9a747e4fSDavid du Colombier if(initgroups(u->name, u->defaultgid) < 0) 1233*9a747e4fSDavid du Colombier fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 1234*9a747e4fSDavid du Colombier 1235*9a747e4fSDavid du Colombier if(setreuid(-1, u->id) < 0){ 1236*9a747e4fSDavid du Colombier fprint(2, "setreuid(-1, %s) failed\n", u->name); 1237*9a747e4fSDavid du Colombier *ep = strerror(errno); 1238*9a747e4fSDavid du Colombier return -1; 1239*9a747e4fSDavid du Colombier } 1240*9a747e4fSDavid du Colombier 1241*9a747e4fSDavid du Colombier return 0; 1242*9a747e4fSDavid du Colombier } 1243*9a747e4fSDavid du Colombier 1244*9a747e4fSDavid du Colombier /* 1245*9a747e4fSDavid du Colombier * We do our own checking here, then switch to root temporarily 1246*9a747e4fSDavid du Colombier * to set our gid. In a perfect world, you'd be allowed to set your 1247*9a747e4fSDavid du Colombier * egid to any of the supplemental groups of your euid, but this 1248*9a747e4fSDavid du Colombier * is not the case on Linux 2.2.14 (and perhaps others). 1249*9a747e4fSDavid du Colombier * 1250*9a747e4fSDavid du Colombier * This is a race, of course, but it's a race against processes 1251*9a747e4fSDavid du Colombier * that can edit the group lists. If you can do that, you can 1252*9a747e4fSDavid du Colombier * change your own group without our help. 1253*9a747e4fSDavid du Colombier */ 1254*9a747e4fSDavid du Colombier int 1255*9a747e4fSDavid du Colombier groupchange(User *u, User *g, char **ep) 1256*9a747e4fSDavid du Colombier { 1257*9a747e4fSDavid du Colombier if(!useringroup(u, g)){ 1258*9a747e4fSDavid du Colombier if(chatty9p) 1259*9a747e4fSDavid du Colombier fprint(2, "%s not in group %s\n", u->name, g->name); 1260*9a747e4fSDavid du Colombier *ep = Enotingroup; 1261*9a747e4fSDavid du Colombier return -1; 1262*9a747e4fSDavid du Colombier } 1263*9a747e4fSDavid du Colombier 1264*9a747e4fSDavid du Colombier setreuid(0,0); 1265*9a747e4fSDavid du Colombier if(setregid(-1, g->id) < 0){ 1266*9a747e4fSDavid du Colombier fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 1267*9a747e4fSDavid du Colombier *ep = strerror(errno); 1268*9a747e4fSDavid du Colombier return -1; 1269*9a747e4fSDavid du Colombier } 1270*9a747e4fSDavid du Colombier if(userchange(u, ep) < 0) 1271*9a747e4fSDavid du Colombier return -1; 1272*9a747e4fSDavid du Colombier 1273*9a747e4fSDavid du Colombier return 0; 1274*9a747e4fSDavid du Colombier } 1275*9a747e4fSDavid du Colombier 1276*9a747e4fSDavid du Colombier 1277*9a747e4fSDavid du Colombier /* 1278*9a747e4fSDavid du Colombier * An attempt to enforce permissions by looking at the 1279*9a747e4fSDavid du Colombier * file system. Separation of checking permission and 1280*9a747e4fSDavid du Colombier * actually performing the action is a terrible idea, of 1281*9a747e4fSDavid du Colombier * course, so we use setreuid for most of the permission 1282*9a747e4fSDavid du Colombier * enforcement. This is here only so we can give errors 1283*9a747e4fSDavid du Colombier * on open(ORCLOSE) in some cases. 1284*9a747e4fSDavid du Colombier */ 1285*9a747e4fSDavid du Colombier int 1286*9a747e4fSDavid du Colombier userperm(User *u, char *path, int type, int need) 1287*9a747e4fSDavid du Colombier { 1288*9a747e4fSDavid du Colombier char *p, *q; 1289*9a747e4fSDavid du Colombier int i, have; 1290*9a747e4fSDavid du Colombier struct stat st; 1291*9a747e4fSDavid du Colombier User *g; 1292*9a747e4fSDavid du Colombier 1293*9a747e4fSDavid du Colombier switch(type){ 1294*9a747e4fSDavid du Colombier default: 1295*9a747e4fSDavid du Colombier fprint(2, "bad type %d in userperm\n", type); 1296*9a747e4fSDavid du Colombier return -1; 1297*9a747e4fSDavid du Colombier case Tdot: 1298*9a747e4fSDavid du Colombier if(stat(path, &st) < 0){ 1299*9a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) failed\n", path); 1300*9a747e4fSDavid du Colombier return -1; 1301*9a747e4fSDavid du Colombier } 1302*9a747e4fSDavid du Colombier break; 1303*9a747e4fSDavid du Colombier case Tdotdot: 1304*9a747e4fSDavid du Colombier p = estrdup(path); 1305*9a747e4fSDavid du Colombier if((q = strrchr(p, '/'))==nil){ 1306*9a747e4fSDavid du Colombier fprint(2, "userperm(%s, ..): bad path\n", p); 1307*9a747e4fSDavid du Colombier free(p); 1308*9a747e4fSDavid du Colombier return -1; 1309*9a747e4fSDavid du Colombier } 1310*9a747e4fSDavid du Colombier if(q > p) 1311*9a747e4fSDavid du Colombier *q = '\0'; 1312*9a747e4fSDavid du Colombier else 1313*9a747e4fSDavid du Colombier *(q+1) = '\0'; 1314*9a747e4fSDavid du Colombier if(stat(p, &st) < 0){ 1315*9a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 1316*9a747e4fSDavid du Colombier p, path); 1317*9a747e4fSDavid du Colombier free(p); 1318*9a747e4fSDavid du Colombier return -1; 1319*9a747e4fSDavid du Colombier } 1320*9a747e4fSDavid du Colombier free(p); 1321*9a747e4fSDavid du Colombier break; 1322*9a747e4fSDavid du Colombier } 1323*9a747e4fSDavid du Colombier 1324*9a747e4fSDavid du Colombier if(u == none){ 1325*9a747e4fSDavid du Colombier fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 1326*9a747e4fSDavid du Colombier have = st.st_mode&7; 1327*9a747e4fSDavid du Colombier if((have&need)==need) 1328*9a747e4fSDavid du Colombier return 0; 1329*9a747e4fSDavid du Colombier return -1; 1330*9a747e4fSDavid du Colombier } 1331*9a747e4fSDavid du Colombier have = st.st_mode&7; 1332*9a747e4fSDavid du Colombier if((uid_t)u->id == st.st_uid) 1333*9a747e4fSDavid du Colombier have |= (st.st_mode>>6)&7; 1334*9a747e4fSDavid du Colombier if((have&need)==need) 1335*9a747e4fSDavid du Colombier return 0; 1336*9a747e4fSDavid du Colombier if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 1337*9a747e4fSDavid du Colombier return -1; 1338*9a747e4fSDavid du Colombier g = gid2user(st.st_gid); 1339*9a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++){ 1340*9a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0){ 1341*9a747e4fSDavid du Colombier have |= (st.st_mode>>3)&7; 1342*9a747e4fSDavid du Colombier break; 1343*9a747e4fSDavid du Colombier } 1344*9a747e4fSDavid du Colombier } 1345*9a747e4fSDavid du Colombier if((have&need)==need) 1346*9a747e4fSDavid du Colombier return 0; 1347*9a747e4fSDavid du Colombier return -1; 1348*9a747e4fSDavid du Colombier } 1349*9a747e4fSDavid du Colombier 1350*9a747e4fSDavid du Colombier int 1351*9a747e4fSDavid du Colombier userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 1352*9a747e4fSDavid du Colombier { 1353*9a747e4fSDavid du Colombier char *npath; 1354*9a747e4fSDavid du Colombier struct stat st; 1355*9a747e4fSDavid du Colombier 1356*9a747e4fSDavid du Colombier npath = estrpath(*path, elem); 1357*9a747e4fSDavid du Colombier if(stat(npath, &st) < 0){ 1358*9a747e4fSDavid du Colombier free(npath); 1359*9a747e4fSDavid du Colombier *ep = strerror(errno); 1360*9a747e4fSDavid du Colombier return -1; 1361*9a747e4fSDavid du Colombier } 1362*9a747e4fSDavid du Colombier *qid = stat2qid(&st); 1363*9a747e4fSDavid du Colombier free(*path); 1364*9a747e4fSDavid du Colombier *path = npath; 1365*9a747e4fSDavid du Colombier return 0; 1366*9a747e4fSDavid du Colombier } 1367*9a747e4fSDavid du Colombier 1368*9a747e4fSDavid du Colombier int 1369*9a747e4fSDavid du Colombier useropen(Fid *fid, int omode, char **ep) 1370*9a747e4fSDavid du Colombier { 1371*9a747e4fSDavid du Colombier int a, o; 1372*9a747e4fSDavid du Colombier 1373*9a747e4fSDavid du Colombier /* 1374*9a747e4fSDavid du Colombier * Check this anyway, to try to head off problems later. 1375*9a747e4fSDavid du Colombier */ 1376*9a747e4fSDavid du Colombier if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 1377*9a747e4fSDavid du Colombier *ep = Eperm; 1378*9a747e4fSDavid du Colombier return -1; 1379*9a747e4fSDavid du Colombier } 1380*9a747e4fSDavid du Colombier 1381*9a747e4fSDavid du Colombier switch(omode&3){ 1382*9a747e4fSDavid du Colombier default: 1383*9a747e4fSDavid du Colombier *ep = "programmer error"; 1384*9a747e4fSDavid du Colombier return -1; 1385*9a747e4fSDavid du Colombier case OREAD: 1386*9a747e4fSDavid du Colombier a = R_OK; 1387*9a747e4fSDavid du Colombier o = O_RDONLY; 1388*9a747e4fSDavid du Colombier break; 1389*9a747e4fSDavid du Colombier case ORDWR: 1390*9a747e4fSDavid du Colombier a = R_OK|W_OK; 1391*9a747e4fSDavid du Colombier o = O_RDWR; 1392*9a747e4fSDavid du Colombier break; 1393*9a747e4fSDavid du Colombier case OWRITE: 1394*9a747e4fSDavid du Colombier a = R_OK; 1395*9a747e4fSDavid du Colombier o = O_WRONLY; 1396*9a747e4fSDavid du Colombier break; 1397*9a747e4fSDavid du Colombier case OEXEC: 1398*9a747e4fSDavid du Colombier a = X_OK; 1399*9a747e4fSDavid du Colombier o = O_RDONLY; 1400*9a747e4fSDavid du Colombier break; 1401*9a747e4fSDavid du Colombier } 1402*9a747e4fSDavid du Colombier if(omode & OTRUNC){ 1403*9a747e4fSDavid du Colombier a |= W_OK; 1404*9a747e4fSDavid du Colombier o |= O_TRUNC; 1405*9a747e4fSDavid du Colombier } 1406*9a747e4fSDavid du Colombier 1407*9a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)){ 1408*9a747e4fSDavid du Colombier if(a != R_OK){ 1409*9a747e4fSDavid du Colombier fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 1410*9a747e4fSDavid du Colombier *ep = Eperm; 1411*9a747e4fSDavid du Colombier return -1; 1412*9a747e4fSDavid du Colombier } 1413*9a747e4fSDavid du Colombier if((fid->dir = opendir(fid->path)) == nil){ 1414*9a747e4fSDavid du Colombier *ep = strerror(errno); 1415*9a747e4fSDavid du Colombier return -1; 1416*9a747e4fSDavid du Colombier } 1417*9a747e4fSDavid du Colombier }else{ 1418*9a747e4fSDavid du Colombier if(access(fid->path, a) < 0){ 1419*9a747e4fSDavid du Colombier *ep = strerror(errno); 1420*9a747e4fSDavid du Colombier return -1; 1421*9a747e4fSDavid du Colombier } 1422*9a747e4fSDavid du Colombier if((fid->fd = open(fid->path, o)) < 0){ 1423*9a747e4fSDavid du Colombier *ep = strerror(errno); 1424*9a747e4fSDavid du Colombier return -1; 1425*9a747e4fSDavid du Colombier } 1426*9a747e4fSDavid du Colombier } 1427*9a747e4fSDavid du Colombier fid->omode = omode; 1428*9a747e4fSDavid du Colombier return 0; 1429*9a747e4fSDavid du Colombier } 1430*9a747e4fSDavid du Colombier 1431*9a747e4fSDavid du Colombier int 1432*9a747e4fSDavid du Colombier usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 1433*9a747e4fSDavid du Colombier { 1434*9a747e4fSDavid du Colombier int o, m; 1435*9a747e4fSDavid du Colombier char *opath, *npath; 1436*9a747e4fSDavid du Colombier struct stat st, parent; 1437*9a747e4fSDavid du Colombier 1438*9a747e4fSDavid du Colombier if(stat(fid->path, &parent) < 0){ 1439*9a747e4fSDavid du Colombier *ep = strerror(errno); 1440*9a747e4fSDavid du Colombier return -1; 1441*9a747e4fSDavid du Colombier } 1442*9a747e4fSDavid du Colombier 1443*9a747e4fSDavid du Colombier /* 1444*9a747e4fSDavid du Colombier * Change group so that created file has expected group 1445*9a747e4fSDavid du Colombier * by Plan 9 semantics. If that fails, might as well go 1446*9a747e4fSDavid du Colombier * with the user's default group. 1447*9a747e4fSDavid du Colombier */ 1448*9a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 1449*9a747e4fSDavid du Colombier && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 1450*9a747e4fSDavid du Colombier return -1; 1451*9a747e4fSDavid du Colombier 1452*9a747e4fSDavid du Colombier m = (perm & DMDIR) ? 0777 : 0666; 1453*9a747e4fSDavid du Colombier perm = perm & (~m | (fid->st.st_mode & m)); 1454*9a747e4fSDavid du Colombier 1455*9a747e4fSDavid du Colombier npath = estrpath(fid->path, elem); 1456*9a747e4fSDavid du Colombier if(perm & DMDIR){ 1457*9a747e4fSDavid du Colombier if((omode&~ORCLOSE) != OREAD){ 1458*9a747e4fSDavid du Colombier *ep = Eperm; 1459*9a747e4fSDavid du Colombier free(npath); 1460*9a747e4fSDavid du Colombier return -1; 1461*9a747e4fSDavid du Colombier } 1462*9a747e4fSDavid du Colombier if(stat(npath, &st) >= 0 || errno != ENOENT){ 1463*9a747e4fSDavid du Colombier *ep = Eexist; 1464*9a747e4fSDavid du Colombier free(npath); 1465*9a747e4fSDavid du Colombier return -1; 1466*9a747e4fSDavid du Colombier } 1467*9a747e4fSDavid du Colombier /* race */ 1468*9a747e4fSDavid du Colombier if(mkdir(npath, perm&0777) < 0){ 1469*9a747e4fSDavid du Colombier *ep = strerror(errno); 1470*9a747e4fSDavid du Colombier free(npath); 1471*9a747e4fSDavid du Colombier return -1; 1472*9a747e4fSDavid du Colombier } 1473*9a747e4fSDavid du Colombier if((fid->dir = opendir(npath)) == nil){ 1474*9a747e4fSDavid du Colombier *ep = strerror(errno); 1475*9a747e4fSDavid du Colombier remove(npath); /* race */ 1476*9a747e4fSDavid du Colombier free(npath); 1477*9a747e4fSDavid du Colombier return -1; 1478*9a747e4fSDavid du Colombier } 1479*9a747e4fSDavid du Colombier }else{ 1480*9a747e4fSDavid du Colombier o = O_CREAT|O_EXCL; 1481*9a747e4fSDavid du Colombier switch(omode&3){ 1482*9a747e4fSDavid du Colombier default: 1483*9a747e4fSDavid du Colombier *ep = "programmer error"; 1484*9a747e4fSDavid du Colombier return -1; 1485*9a747e4fSDavid du Colombier case OREAD: 1486*9a747e4fSDavid du Colombier case OEXEC: 1487*9a747e4fSDavid du Colombier o |= O_RDONLY; 1488*9a747e4fSDavid du Colombier break; 1489*9a747e4fSDavid du Colombier case ORDWR: 1490*9a747e4fSDavid du Colombier o |= O_RDWR; 1491*9a747e4fSDavid du Colombier break; 1492*9a747e4fSDavid du Colombier case OWRITE: 1493*9a747e4fSDavid du Colombier o |= O_WRONLY; 1494*9a747e4fSDavid du Colombier break; 1495*9a747e4fSDavid du Colombier } 1496*9a747e4fSDavid du Colombier if(omode & OTRUNC) 1497*9a747e4fSDavid du Colombier o |= O_TRUNC; 1498*9a747e4fSDavid du Colombier if((fid->fd = open(npath, o, perm&0777)) < 0){ 1499*9a747e4fSDavid du Colombier if(chatty9p) 1500*9a747e4fSDavid du Colombier fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 1501*9a747e4fSDavid du Colombier *ep = strerror(errno); 1502*9a747e4fSDavid du Colombier free(npath); 1503*9a747e4fSDavid du Colombier return -1; 1504*9a747e4fSDavid du Colombier } 1505*9a747e4fSDavid du Colombier } 1506*9a747e4fSDavid du Colombier 1507*9a747e4fSDavid du Colombier opath = fid->path; 1508*9a747e4fSDavid du Colombier fid->path = npath; 1509*9a747e4fSDavid du Colombier if(fidstat(fid, ep) < 0){ 1510*9a747e4fSDavid du Colombier fprint(2, "stat after create on %s failed\n", npath); 1511*9a747e4fSDavid du Colombier remove(npath); /* race */ 1512*9a747e4fSDavid du Colombier free(npath); 1513*9a747e4fSDavid du Colombier fid->path = opath; 1514*9a747e4fSDavid du Colombier if(fid->fd >= 0){ 1515*9a747e4fSDavid du Colombier close(fid->fd); 1516*9a747e4fSDavid du Colombier fid->fd = -1; 1517*9a747e4fSDavid du Colombier }else{ 1518*9a747e4fSDavid du Colombier closedir(fid->dir); 1519*9a747e4fSDavid du Colombier fid->dir = nil; 1520*9a747e4fSDavid du Colombier } 1521*9a747e4fSDavid du Colombier return -1; 1522*9a747e4fSDavid du Colombier } 1523*9a747e4fSDavid du Colombier fid->omode = omode; 1524*9a747e4fSDavid du Colombier free(opath); 1525*9a747e4fSDavid du Colombier return 0; 1526*9a747e4fSDavid du Colombier } 1527*9a747e4fSDavid du Colombier 1528*9a747e4fSDavid du Colombier int 1529*9a747e4fSDavid du Colombier userremove(Fid *fid, char **ep) 1530*9a747e4fSDavid du Colombier { 1531*9a747e4fSDavid du Colombier if(remove(fid->path) < 0){ 1532*9a747e4fSDavid du Colombier *ep = strerror(errno); 1533*9a747e4fSDavid du Colombier return -1; 1534*9a747e4fSDavid du Colombier } 1535*9a747e4fSDavid du Colombier return 0; 1536*9a747e4fSDavid du Colombier } 1537*9a747e4fSDavid du Colombier 1538*9a747e4fSDavid du Colombier void 1539*9a747e4fSDavid du Colombier usage(void) 1540*9a747e4fSDavid du Colombier { 1541*9a747e4fSDavid du Colombier fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 1542*9a747e4fSDavid du Colombier exit(1); 1543*9a747e4fSDavid du Colombier } 1544*9a747e4fSDavid du Colombier 1545*9a747e4fSDavid du Colombier int 1546*9a747e4fSDavid du Colombier main(int argc, char **argv) 1547*9a747e4fSDavid du Colombier { 1548*9a747e4fSDavid du Colombier char *authtype; 1549*9a747e4fSDavid du Colombier int i; 1550*9a747e4fSDavid du Colombier int fd; 1551*9a747e4fSDavid du Colombier int logflag; 1552*9a747e4fSDavid du Colombier 1553*9a747e4fSDavid du Colombier auth = authmethods[0]; 1554*9a747e4fSDavid du Colombier logflag = O_WRONLY|O_APPEND|O_CREAT; 1555*9a747e4fSDavid du Colombier ARGBEGIN{ 1556*9a747e4fSDavid du Colombier case 'D': 1557*9a747e4fSDavid du Colombier chatty9p = 1; 1558*9a747e4fSDavid du Colombier break; 1559*9a747e4fSDavid du Colombier case 'a': 1560*9a747e4fSDavid du Colombier authtype = EARGF(usage()); 1561*9a747e4fSDavid du Colombier auth = nil; 1562*9a747e4fSDavid du Colombier for(i=0; i<nelem(authmethods); i++) 1563*9a747e4fSDavid du Colombier if(strcmp(authmethods[i]->name, authtype)==0) 1564*9a747e4fSDavid du Colombier auth = authmethods[i]; 1565*9a747e4fSDavid du Colombier if(auth == nil) 1566*9a747e4fSDavid du Colombier sysfatal("unknown auth type '%s'", authtype); 1567*9a747e4fSDavid du Colombier break; 1568*9a747e4fSDavid du Colombier case 'A': 1569*9a747e4fSDavid du Colombier autharg = EARGF(usage()); 1570*9a747e4fSDavid du Colombier break; 1571*9a747e4fSDavid du Colombier case 'l': 1572*9a747e4fSDavid du Colombier logfile = EARGF(usage()); 1573*9a747e4fSDavid du Colombier break; 1574*9a747e4fSDavid du Colombier case 'm': 1575*9a747e4fSDavid du Colombier msize = strtol(EARGF(usage()), 0, 0); 1576*9a747e4fSDavid du Colombier break; 1577*9a747e4fSDavid du Colombier case 'n': 1578*9a747e4fSDavid du Colombier network = 0; 1579*9a747e4fSDavid du Colombier break; 1580*9a747e4fSDavid du Colombier case 'u': 1581*9a747e4fSDavid du Colombier defaultuser = EARGF(usage()); 1582*9a747e4fSDavid du Colombier break; 1583*9a747e4fSDavid du Colombier case 'z': 1584*9a747e4fSDavid du Colombier logflag |= O_TRUNC; 1585*9a747e4fSDavid du Colombier }ARGEND 1586*9a747e4fSDavid du Colombier 1587*9a747e4fSDavid du Colombier if(argc > 1) 1588*9a747e4fSDavid du Colombier usage(); 1589*9a747e4fSDavid du Colombier 1590*9a747e4fSDavid du Colombier fd = open(logfile, logflag, 0666); 1591*9a747e4fSDavid du Colombier if(fd < 0) 1592*9a747e4fSDavid du Colombier sysfatal("cannot open log '%s'", logfile); 1593*9a747e4fSDavid du Colombier 1594*9a747e4fSDavid du Colombier if(dup2(fd, 2) < 0) 1595*9a747e4fSDavid du Colombier sysfatal("cannot dup fd onto stderr"); 1596*9a747e4fSDavid du Colombier fprint(2, "u9fs\nkill %d\n", (int)getpid()); 1597*9a747e4fSDavid du Colombier 1598*9a747e4fSDavid du Colombier fmtinstall('F', fcallconv); 1599*9a747e4fSDavid du Colombier fmtinstall('D', dirconv); 1600*9a747e4fSDavid du Colombier fmtinstall('M', dirmodeconv); 1601*9a747e4fSDavid du Colombier 1602*9a747e4fSDavid du Colombier rxbuf = emalloc(msize); 1603*9a747e4fSDavid du Colombier txbuf = emalloc(msize); 1604*9a747e4fSDavid du Colombier databuf = emalloc(msize); 1605*9a747e4fSDavid du Colombier 1606*9a747e4fSDavid du Colombier if(auth->init) 1607*9a747e4fSDavid du Colombier auth->init(); 1608*9a747e4fSDavid du Colombier 1609*9a747e4fSDavid du Colombier if(network) 1610*9a747e4fSDavid du Colombier getremotehostname(remotehostname, sizeof remotehostname); 1611*9a747e4fSDavid du Colombier 1612*9a747e4fSDavid du Colombier if(gethostname(hostname, sizeof hostname) < 0) 1613*9a747e4fSDavid du Colombier strcpy(hostname, "gnot"); 1614*9a747e4fSDavid du Colombier 1615*9a747e4fSDavid du Colombier umask(0); 1616*9a747e4fSDavid du Colombier 1617*9a747e4fSDavid du Colombier if(argc == 1) 1618*9a747e4fSDavid du Colombier if(chroot(argv[0]) < 0) 1619*9a747e4fSDavid du Colombier sysfatal("chroot '%s' failed", argv[0]); 1620*9a747e4fSDavid du Colombier 1621*9a747e4fSDavid du Colombier none = uname2user("none"); 1622*9a747e4fSDavid du Colombier serve(0, 1); 1623*9a747e4fSDavid du Colombier return 0; 1624*9a747e4fSDavid du Colombier } 1625