13e12c5d1SDavid du Colombier #include "u.h" 23e12c5d1SDavid du Colombier #include <sys/types.h> 33e12c5d1SDavid du Colombier #include <sys/stat.h> 43e12c5d1SDavid du Colombier #include "libc.h" 53e12c5d1SDavid du Colombier #include "9p.h" 63e12c5d1SDavid du Colombier #include "stdio.h" 73e12c5d1SDavid du Colombier #include "setjmp.h" 83e12c5d1SDavid du Colombier #include "pwd.h" 93e12c5d1SDavid du Colombier #include "grp.h" 103e12c5d1SDavid du Colombier 113e12c5d1SDavid du Colombier #define DBG(f) 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier struct group *getgrent(void); 143e12c5d1SDavid du Colombier struct passwd *getpwent(void); 153e12c5d1SDavid du Colombier 163e12c5d1SDavid du Colombier #ifdef SYSV 173e12c5d1SDavid du Colombier # include <dirent.h> 183e12c5d1SDavid du Colombier # define DTYPE struct dirent 19*219b2ee8SDavid du Colombier # define SOCKETS 203e12c5d1SDavid du Colombier #endif 213e12c5d1SDavid du Colombier #ifdef V10 223e12c5d1SDavid du Colombier # include <ndir.h> 233e12c5d1SDavid du Colombier # define DTYPE struct direct 243e12c5d1SDavid du Colombier #endif 253e12c5d1SDavid du Colombier #ifdef BSD 263e12c5d1SDavid du Colombier # include <sys/dir.h> 273e12c5d1SDavid du Colombier # define DTYPE struct direct 28*219b2ee8SDavid du Colombier # define SOCKETS 29*219b2ee8SDavid du Colombier #endif 30*219b2ee8SDavid du Colombier #ifdef SOCKETS 31*219b2ee8SDavid du Colombier # define sendmsg __sendmsg 32*219b2ee8SDavid du Colombier # include <sys/socket.h> 33*219b2ee8SDavid du Colombier # include <netinet/in.h> 34*219b2ee8SDavid du Colombier # include <netdb.h> 35*219b2ee8SDavid du Colombier # undef sendmsg 36*219b2ee8SDavid du Colombier char bsdhost[256]; 37*219b2ee8SDavid du Colombier void remotehostname(void); 383e12c5d1SDavid du Colombier #endif 393e12c5d1SDavid du Colombier 403e12c5d1SDavid du Colombier typedef struct File File; 413e12c5d1SDavid du Colombier typedef struct Rfile Rfile; 423e12c5d1SDavid du Colombier typedef struct Fd Fd; 433e12c5d1SDavid du Colombier typedef struct Pass Pass; 443e12c5d1SDavid du Colombier 453e12c5d1SDavid du Colombier struct Fd{ 463e12c5d1SDavid du Colombier int ref; 473e12c5d1SDavid du Colombier Ulong offset; 483e12c5d1SDavid du Colombier int fd; 493e12c5d1SDavid du Colombier DIR *dir; 503e12c5d1SDavid du Colombier }; 513e12c5d1SDavid du Colombier 523e12c5d1SDavid du Colombier struct Rfile{ 533e12c5d1SDavid du Colombier int busy; 543e12c5d1SDavid du Colombier int uid; 553e12c5d1SDavid du Colombier int gid; 56*219b2ee8SDavid du Colombier int rclose; 573e12c5d1SDavid du Colombier File *file; 583e12c5d1SDavid du Colombier Fd *fd; 593e12c5d1SDavid du Colombier }; 603e12c5d1SDavid du Colombier 613e12c5d1SDavid du Colombier struct File{ 623e12c5d1SDavid du Colombier int ref; 633e12c5d1SDavid du Colombier char *path; 643e12c5d1SDavid du Colombier char *name; 653e12c5d1SDavid du Colombier Qid qid; 663e12c5d1SDavid du Colombier struct stat stbuf; 673e12c5d1SDavid du Colombier }; 683e12c5d1SDavid du Colombier 693e12c5d1SDavid du Colombier struct Pass{ 703e12c5d1SDavid du Colombier int id; 713e12c5d1SDavid du Colombier int gid; 723e12c5d1SDavid du Colombier char *name; 733e12c5d1SDavid du Colombier Pass *next; 743e12c5d1SDavid du Colombier }; 753e12c5d1SDavid du Colombier 763e12c5d1SDavid du Colombier char data[2][MAXMSG+MAXFDATA]; 773e12c5d1SDavid du Colombier char tdata[MAXMSG+MAXFDATA]; 783e12c5d1SDavid du Colombier char rdata[MAXFDATA]; 793e12c5d1SDavid du Colombier Fcall rhdr; 803e12c5d1SDavid du Colombier Fcall thdr; 813e12c5d1SDavid du Colombier Rfile *rfile; 823e12c5d1SDavid du Colombier File *file0; 833e12c5d1SDavid du Colombier int nrfilealloc; 843e12c5d1SDavid du Colombier jmp_buf loopjmp; 853e12c5d1SDavid du Colombier Pass* uid[256]; 863e12c5d1SDavid du Colombier Pass* gid[256]; 873e12c5d1SDavid du Colombier int devallowed; 883e12c5d1SDavid du Colombier int connected; 893e12c5d1SDavid du Colombier 903e12c5d1SDavid du Colombier void io(void); 913e12c5d1SDavid du Colombier void error(char*); 923e12c5d1SDavid du Colombier char *mfmt(Fcall*); 933e12c5d1SDavid du Colombier void sendmsg(char*); 943e12c5d1SDavid du Colombier int okfid(int); 953e12c5d1SDavid du Colombier Rfile* rfilefid(void); 963e12c5d1SDavid du Colombier File* newfile(void); 973e12c5d1SDavid du Colombier void* erealloc(void*, unsigned); 983e12c5d1SDavid du Colombier char* estrdup(char*); 993e12c5d1SDavid du Colombier char* dostat(File*, char*); 1003e12c5d1SDavid du Colombier char* bldpath(char*, char*, char*); 1013e12c5d1SDavid du Colombier Ulong qid(struct stat*); 102*219b2ee8SDavid du Colombier Ulong vers(struct stat*); 1033e12c5d1SDavid du Colombier void errjmp(char*); 1043e12c5d1SDavid du Colombier int omode(int); 1053e12c5d1SDavid du Colombier char* id2name(Pass**, int); 1063e12c5d1SDavid du Colombier Pass* name2pass(Pass**, char*); 1073e12c5d1SDavid du Colombier void getpwdf(void); 1083e12c5d1SDavid du Colombier void getgrpf(void); 1093e12c5d1SDavid du Colombier void perm(Rfile*, int, struct stat*); 1103e12c5d1SDavid du Colombier void parentwrperm(Rfile*); 1113e12c5d1SDavid du Colombier 112*219b2ee8SDavid du Colombier void rsession(void); 1133e12c5d1SDavid du Colombier void rattach(void); 1143e12c5d1SDavid du Colombier void rflush(void); 1153e12c5d1SDavid du Colombier void rclone(void); 1163e12c5d1SDavid du Colombier void rwalk(void); 1173e12c5d1SDavid du Colombier void ropen(void); 1183e12c5d1SDavid du Colombier void rcreate(void); 1193e12c5d1SDavid du Colombier void rread(void); 1203e12c5d1SDavid du Colombier void rwrite(void); 1213e12c5d1SDavid du Colombier void rclunk(int); 1223e12c5d1SDavid du Colombier void rstat(void); 1233e12c5d1SDavid du Colombier void rwstat(void); 1243e12c5d1SDavid du Colombier void rclwalk(void); 1253e12c5d1SDavid du Colombier 1263e12c5d1SDavid du Colombier char Eauth[] = "authentication failed"; 1273e12c5d1SDavid du Colombier char Eperm[] = "permission denied"; 1283e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range"; 1293e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use"; 1303e12c5d1SDavid du Colombier char Eopen[] = "file is open"; 1313e12c5d1SDavid du Colombier char Emode[] = "invalid open mode"; 1323e12c5d1SDavid du Colombier char Especial[] = "no access to special file"; 1333e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files"; 1343e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files"; 1353e12c5d1SDavid du Colombier char Enotopen[] = "file is not open"; 1363e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large"; 1373e12c5d1SDavid du Colombier char Ebaddir[] = "i/o error on directory"; 1383e12c5d1SDavid du Colombier char Eunknown[] = "unknown user or group"; 1393e12c5d1SDavid du Colombier char Euid[] = "can't set uid"; 1403e12c5d1SDavid du Colombier char Egid[] = "can't set gid"; 1413e12c5d1SDavid du Colombier char Eowner[] = "not owner"; 1423e12c5d1SDavid du Colombier 1433e12c5d1SDavid du Colombier int 1443e12c5d1SDavid du Colombier main(int argc, char *argv[]) 1453e12c5d1SDavid du Colombier { 1463e12c5d1SDavid du Colombier freopen(LOG, "a", stderr); 1473e12c5d1SDavid du Colombier setbuf(stderr, (void*)0); 1483e12c5d1SDavid du Colombier DBG(fprintf(stderr, "u9fs\nkill %d\n", getpid())); 1493e12c5d1SDavid du Colombier if(argc > 1) 1503e12c5d1SDavid du Colombier if(chroot(argv[1]) == -1) 1513e12c5d1SDavid du Colombier error("chroot failed"); 152*219b2ee8SDavid du Colombier 153*219b2ee8SDavid du Colombier # ifdef SOCKETS 154*219b2ee8SDavid du Colombier remotehostname(); 155*219b2ee8SDavid du Colombier # endif 156*219b2ee8SDavid du Colombier 1573e12c5d1SDavid du Colombier io(); 1583e12c5d1SDavid du Colombier return 0; 1593e12c5d1SDavid du Colombier } 1603e12c5d1SDavid du Colombier 1613e12c5d1SDavid du Colombier void 1623e12c5d1SDavid du Colombier io(void) 1633e12c5d1SDavid du Colombier { 1643e12c5d1SDavid du Colombier int m; 1653e12c5d1SDavid du Colombier static int toggle, ndata; 1663e12c5d1SDavid du Colombier char *datap; 1673e12c5d1SDavid du Colombier 1683e12c5d1SDavid du Colombier /* 1693e12c5d1SDavid du Colombier * TCP does not preserve record boundaries; this dance works around 1703e12c5d1SDavid du Colombier * the problem. 1713e12c5d1SDavid du Colombier */ 1723e12c5d1SDavid du Colombier setjmp(loopjmp); 1733e12c5d1SDavid du Colombier 1743e12c5d1SDavid du Colombier /* 1753e12c5d1SDavid du Colombier * Invariant: data[toggle] has ndata bytes already 1763e12c5d1SDavid du Colombier */ 1773e12c5d1SDavid du Colombier loop: 1783e12c5d1SDavid du Colombier datap = data[toggle]; 1793e12c5d1SDavid du Colombier toggle ^= 1; 1803e12c5d1SDavid du Colombier for(;;){ 1813e12c5d1SDavid du Colombier if(ndata){ 1823e12c5d1SDavid du Colombier m = convM2S(datap, &rhdr, ndata); 1833e12c5d1SDavid du Colombier /* m is number of bytes more than a full message */ 1843e12c5d1SDavid du Colombier if(m >= 0){ 1853e12c5d1SDavid du Colombier memmove(data[toggle], datap+(ndata-m), m); 1863e12c5d1SDavid du Colombier ndata = m; 1873e12c5d1SDavid du Colombier break; 1883e12c5d1SDavid du Colombier } 1893e12c5d1SDavid du Colombier } 1903e12c5d1SDavid du Colombier m = read(0, datap+ndata, (MAXMSG+MAXFDATA)-ndata); 1913e12c5d1SDavid du Colombier if(m <= 0) 1923e12c5d1SDavid du Colombier error("read"); 1933e12c5d1SDavid du Colombier ndata += m; 1943e12c5d1SDavid du Colombier } 1953e12c5d1SDavid du Colombier 1963e12c5d1SDavid du Colombier thdr.type = rhdr.type+1; 1973e12c5d1SDavid du Colombier thdr.tag = rhdr.tag; 1983e12c5d1SDavid du Colombier thdr.fid = rhdr.fid; 1993e12c5d1SDavid du Colombier DBG(fprintf(stderr, ">> %s\n", mfmt(&rhdr))); 2003e12c5d1SDavid du Colombier switch(rhdr.type){ 2013e12c5d1SDavid du Colombier case Tnop: 2023e12c5d1SDavid du Colombier case Tflush: /* this is a synchronous fs; easy */ 2033e12c5d1SDavid du Colombier break; 204*219b2ee8SDavid du Colombier case Tsession: 205*219b2ee8SDavid du Colombier rsession(); 2063e12c5d1SDavid du Colombier break; 2073e12c5d1SDavid du Colombier case Tattach: 2083e12c5d1SDavid du Colombier rattach(); 2093e12c5d1SDavid du Colombier break; 2103e12c5d1SDavid du Colombier case Tclone: 2113e12c5d1SDavid du Colombier rclone(); 2123e12c5d1SDavid du Colombier break; 2133e12c5d1SDavid du Colombier case Twalk: 2143e12c5d1SDavid du Colombier rwalk(); 2153e12c5d1SDavid du Colombier break; 2163e12c5d1SDavid du Colombier case Tstat: 2173e12c5d1SDavid du Colombier rstat(); 2183e12c5d1SDavid du Colombier break; 2193e12c5d1SDavid du Colombier case Twstat: 2203e12c5d1SDavid du Colombier rwstat(); 2213e12c5d1SDavid du Colombier break; 2223e12c5d1SDavid du Colombier case Topen: 2233e12c5d1SDavid du Colombier ropen(); 2243e12c5d1SDavid du Colombier break; 2253e12c5d1SDavid du Colombier case Tcreate: 2263e12c5d1SDavid du Colombier rcreate(); 2273e12c5d1SDavid du Colombier break; 2283e12c5d1SDavid du Colombier case Tread: 2293e12c5d1SDavid du Colombier rread(); 2303e12c5d1SDavid du Colombier break; 2313e12c5d1SDavid du Colombier case Twrite: 2323e12c5d1SDavid du Colombier rwrite(); 2333e12c5d1SDavid du Colombier break; 2343e12c5d1SDavid du Colombier case Tclunk: 2353e12c5d1SDavid du Colombier rclunk(0); 2363e12c5d1SDavid du Colombier break; 2373e12c5d1SDavid du Colombier case Tremove: 2383e12c5d1SDavid du Colombier rclunk(1); 2393e12c5d1SDavid du Colombier break; 2403e12c5d1SDavid du Colombier default: 2413e12c5d1SDavid du Colombier fprintf(stderr, "unknown message %s\n", mfmt(&rhdr)); 2423e12c5d1SDavid du Colombier error("bad message"); 2433e12c5d1SDavid du Colombier } 2443e12c5d1SDavid du Colombier sendmsg(0); 2453e12c5d1SDavid du Colombier goto loop; 2463e12c5d1SDavid du Colombier } 2473e12c5d1SDavid du Colombier 2483e12c5d1SDavid du Colombier void 249*219b2ee8SDavid du Colombier rsession(void) 2503e12c5d1SDavid du Colombier { 251*219b2ee8SDavid du Colombier memset(thdr.authid, 0, sizeof(thdr.authid)); 252*219b2ee8SDavid du Colombier memset(thdr.authdom, 0, sizeof(thdr.authdom)); 253*219b2ee8SDavid du Colombier memset(thdr.chal, 0, sizeof(thdr.chal)); 2543e12c5d1SDavid du Colombier } 2553e12c5d1SDavid du Colombier 2563e12c5d1SDavid du Colombier void 2573e12c5d1SDavid du Colombier rattach(void) 2583e12c5d1SDavid du Colombier { 2593e12c5d1SDavid du Colombier Rfile *rf; 2603e12c5d1SDavid du Colombier char *err; 2613e12c5d1SDavid du Colombier Pass *p; 2623e12c5d1SDavid du Colombier 2633e12c5d1SDavid du Colombier err = 0; 2643e12c5d1SDavid du Colombier if(file0 == 0){ 2653e12c5d1SDavid du Colombier file0 = newfile(); 2663e12c5d1SDavid du Colombier file0->ref++; /* one extra to hold it up */ 2673e12c5d1SDavid du Colombier file0->path = estrdup("/"); 2683e12c5d1SDavid du Colombier file0->name = estrdup("/"); 2693e12c5d1SDavid du Colombier errjmp(dostat(file0, 0)); 2703e12c5d1SDavid du Colombier } 2713e12c5d1SDavid du Colombier if(!okfid(rhdr.fid)) 2723e12c5d1SDavid du Colombier errjmp(Ebadfid); 2733e12c5d1SDavid du Colombier if(strncmp(rhdr.aname, "device", 6) == 0){ 2743e12c5d1SDavid du Colombier if(connected && !devallowed) 2753e12c5d1SDavid du Colombier errjmp(Especial0); 2763e12c5d1SDavid du Colombier devallowed = 1; 2773e12c5d1SDavid du Colombier }else{ 2783e12c5d1SDavid du Colombier if(connected && devallowed) 2793e12c5d1SDavid du Colombier errjmp(Especial1); 2803e12c5d1SDavid du Colombier } 2813e12c5d1SDavid du Colombier getpwdf(); 2823e12c5d1SDavid du Colombier getgrpf(); 2833e12c5d1SDavid du Colombier rf = &rfile[rhdr.fid]; 2843e12c5d1SDavid du Colombier if(rf->busy) 2853e12c5d1SDavid du Colombier errjmp(Efidactive); 2863e12c5d1SDavid du Colombier p = name2pass(uid, rhdr.uname); 2873e12c5d1SDavid du Colombier if(p == 0) 2883e12c5d1SDavid du Colombier errjmp(Eunknown); 289*219b2ee8SDavid du Colombier if(p->id == 0) 290*219b2ee8SDavid du Colombier errjmp(Eperm); 291*219b2ee8SDavid du Colombier # ifdef SOCKETS 292*219b2ee8SDavid du Colombier if(ruserok(bsdhost, 0, rhdr.uname, rhdr.uname) < 0) 293*219b2ee8SDavid du Colombier errjmp(Eperm); 294*219b2ee8SDavid du Colombier # endif 295*219b2ee8SDavid du Colombier /* mark busy & inc ref cnt only after committed to succeed */ 296*219b2ee8SDavid du Colombier rf->busy = 1; 297*219b2ee8SDavid du Colombier rf->file = file0; 298*219b2ee8SDavid du Colombier file0->ref++; 299*219b2ee8SDavid du Colombier rf->rclose = 0; 3003e12c5d1SDavid du Colombier rf->uid = p->id; 3013e12c5d1SDavid du Colombier rf->gid = p->gid; 3023e12c5d1SDavid du Colombier thdr.qid = file0->qid; 3033e12c5d1SDavid du Colombier connected = 1; 3043e12c5d1SDavid du Colombier } 3053e12c5d1SDavid du Colombier 3063e12c5d1SDavid du Colombier void 3073e12c5d1SDavid du Colombier rclone(void) 3083e12c5d1SDavid du Colombier { 3093e12c5d1SDavid du Colombier Rfile *rf, *nrf; 3103e12c5d1SDavid du Colombier File *f; 3113e12c5d1SDavid du Colombier 3123e12c5d1SDavid du Colombier rfilefid(); 3133e12c5d1SDavid du Colombier if(!okfid(rhdr.newfid)) 3143e12c5d1SDavid du Colombier errjmp(Ebadfid); 3153e12c5d1SDavid du Colombier rf = &rfile[rhdr.fid]; 3163e12c5d1SDavid du Colombier nrf = &rfile[rhdr.newfid]; 3173e12c5d1SDavid du Colombier f = rf->file; 3183e12c5d1SDavid du Colombier if(nrf->busy) 3193e12c5d1SDavid du Colombier errjmp(Efidactive); 3203e12c5d1SDavid du Colombier nrf->busy = 1; 3213e12c5d1SDavid du Colombier nrf->file = f; 3223e12c5d1SDavid du Colombier f->ref++; 3233e12c5d1SDavid du Colombier nrf->fd = rf->fd; 3243e12c5d1SDavid du Colombier nrf->uid = rf->uid; 3253e12c5d1SDavid du Colombier nrf->gid = rf->gid; 326*219b2ee8SDavid du Colombier nrf->rclose = rf->rclose; 3273e12c5d1SDavid du Colombier if(nrf->fd){ 3283e12c5d1SDavid du Colombier if(nrf->fd->ref == 0) 3293e12c5d1SDavid du Colombier error("clone fd count"); 3303e12c5d1SDavid du Colombier nrf->fd->ref++; 3313e12c5d1SDavid du Colombier } 3323e12c5d1SDavid du Colombier } 3333e12c5d1SDavid du Colombier 3343e12c5d1SDavid du Colombier void 3353e12c5d1SDavid du Colombier rwalk(void) 3363e12c5d1SDavid du Colombier { 3373e12c5d1SDavid du Colombier char *err; 3383e12c5d1SDavid du Colombier Rfile *rf; 3393e12c5d1SDavid du Colombier File *of, *f; 3403e12c5d1SDavid du Colombier 3413e12c5d1SDavid du Colombier rf = rfilefid(); 3423e12c5d1SDavid du Colombier if(rf->fd) 3433e12c5d1SDavid du Colombier errjmp(Eopen); 3443e12c5d1SDavid du Colombier of = rf->file; 3453e12c5d1SDavid du Colombier perm(rf, 1, 0); 3463e12c5d1SDavid du Colombier f = newfile(); 3473e12c5d1SDavid du Colombier f->path = estrdup(of->path); 3483e12c5d1SDavid du Colombier err = dostat(f, rhdr.name); 3493e12c5d1SDavid du Colombier if(err){ 3503e12c5d1SDavid du Colombier f->ref = 0; 3513e12c5d1SDavid du Colombier free(f->path); 3523e12c5d1SDavid du Colombier errjmp(err); 3533e12c5d1SDavid du Colombier } 3543e12c5d1SDavid du Colombier if(of->ref <= 0) 3553e12c5d1SDavid du Colombier error("walk ref count"); 3563e12c5d1SDavid du Colombier if(--of->ref == 0){ 3573e12c5d1SDavid du Colombier free(of->path); 3583e12c5d1SDavid du Colombier free(of->name); 3593e12c5d1SDavid du Colombier free(of); 3603e12c5d1SDavid du Colombier } 3613e12c5d1SDavid du Colombier rf->file = f; 3623e12c5d1SDavid du Colombier thdr.qid = f->qid; 3633e12c5d1SDavid du Colombier } 3643e12c5d1SDavid du Colombier 3653e12c5d1SDavid du Colombier void 3663e12c5d1SDavid du Colombier ropen(void) 3673e12c5d1SDavid du Colombier { 3683e12c5d1SDavid du Colombier Rfile *rf; 3693e12c5d1SDavid du Colombier File *f; 3703e12c5d1SDavid du Colombier int fd; 3713e12c5d1SDavid du Colombier DIR *dir; 3723e12c5d1SDavid du Colombier int m, trunc; 3733e12c5d1SDavid du Colombier 3743e12c5d1SDavid du Colombier rf = rfilefid(); 3753e12c5d1SDavid du Colombier f = rf->file; 3763e12c5d1SDavid du Colombier if(rf->fd) 3773e12c5d1SDavid du Colombier error("open already open"); 3783e12c5d1SDavid du Colombier if(!devallowed && (f->stbuf.st_mode & S_IFCHR)) 3793e12c5d1SDavid du Colombier errjmp(Especial); 3803e12c5d1SDavid du Colombier m = rhdr.mode & (16|3); 3813e12c5d1SDavid du Colombier trunc = m & 16; /* OTRUNC */ 3823e12c5d1SDavid du Colombier switch(m){ 3833e12c5d1SDavid du Colombier case 0: 3843e12c5d1SDavid du Colombier perm(rf, 4, 0); 3853e12c5d1SDavid du Colombier break; 3863e12c5d1SDavid du Colombier case 1: 3873e12c5d1SDavid du Colombier case 1|16: 3883e12c5d1SDavid du Colombier perm(rf, 2, 0); 3893e12c5d1SDavid du Colombier break; 3903e12c5d1SDavid du Colombier case 2: 3913e12c5d1SDavid du Colombier case 0|16: 3923e12c5d1SDavid du Colombier case 2|16: 3933e12c5d1SDavid du Colombier perm(rf, 4, 0); 3943e12c5d1SDavid du Colombier perm(rf, 2, 0); 3953e12c5d1SDavid du Colombier break; 3963e12c5d1SDavid du Colombier case 3: 3973e12c5d1SDavid du Colombier perm(rf, 1, 0); 3983e12c5d1SDavid du Colombier break; 3993e12c5d1SDavid du Colombier default: 4003e12c5d1SDavid du Colombier errjmp(Emode); 4013e12c5d1SDavid du Colombier } 4023e12c5d1SDavid du Colombier 403bd389b36SDavid du Colombier m = omode(m & 3); 4043e12c5d1SDavid du Colombier errno = 0; 4053e12c5d1SDavid du Colombier if(f->qid.path & CHDIR){ 4063e12c5d1SDavid du Colombier if(rhdr.mode != 0) /* OREAD */ 4073e12c5d1SDavid du Colombier errjmp(Eperm); 4083e12c5d1SDavid du Colombier dir = opendir(f->path); 4093e12c5d1SDavid du Colombier if(dir == 0) 4103e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 4113e12c5d1SDavid du Colombier fd = 0; 4123e12c5d1SDavid du Colombier }else{ 4133e12c5d1SDavid du Colombier if(trunc){ 4143e12c5d1SDavid du Colombier fd = creat(f->path, 0666); 4153e12c5d1SDavid du Colombier if(fd >= 0) 4163e12c5d1SDavid du Colombier if(m != 1){ 4173e12c5d1SDavid du Colombier close(fd); 4183e12c5d1SDavid du Colombier fd = open(f->path, m); 4193e12c5d1SDavid du Colombier } 4203e12c5d1SDavid du Colombier }else 4213e12c5d1SDavid du Colombier fd = open(f->path, m); 4223e12c5d1SDavid du Colombier if(fd < 0) 4233e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 4243e12c5d1SDavid du Colombier dir = 0; 4253e12c5d1SDavid du Colombier } 426*219b2ee8SDavid du Colombier rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 4273e12c5d1SDavid du Colombier rf->fd = erealloc(0, sizeof(Fd)); 4283e12c5d1SDavid du Colombier rf->fd->ref = 1; 4293e12c5d1SDavid du Colombier rf->fd->fd = fd; 4303e12c5d1SDavid du Colombier rf->fd->dir = dir; 4313e12c5d1SDavid du Colombier rf->fd->offset = 0; 4323e12c5d1SDavid du Colombier thdr.qid = f->qid; 4333e12c5d1SDavid du Colombier } 4343e12c5d1SDavid du Colombier 4353e12c5d1SDavid du Colombier void 4363e12c5d1SDavid du Colombier rcreate(void) 4373e12c5d1SDavid du Colombier { 4383e12c5d1SDavid du Colombier Rfile *rf; 4393e12c5d1SDavid du Colombier File *f, *of; 4403e12c5d1SDavid du Colombier char *path, *err; 4413e12c5d1SDavid du Colombier int fd; 4423e12c5d1SDavid du Colombier int m; 4433e12c5d1SDavid du Colombier char name[NAMELEN]; 4443e12c5d1SDavid du Colombier 4453e12c5d1SDavid du Colombier rf = rfilefid(); 4463e12c5d1SDavid du Colombier if(rf->fd) 4473e12c5d1SDavid du Colombier errjmp(Eopen); 4483e12c5d1SDavid du Colombier perm(rf, 2, 0); 4493e12c5d1SDavid du Colombier path = bldpath(rf->file->path, rhdr.name, name); 450bd389b36SDavid du Colombier m = omode(rhdr.mode&3); 4513e12c5d1SDavid du Colombier errno = 0; 4523e12c5d1SDavid du Colombier if(rhdr.perm & CHDIR){ 4533e12c5d1SDavid du Colombier if(m){ 4543e12c5d1SDavid du Colombier free(path); 4553e12c5d1SDavid du Colombier errjmp(Eperm); 4563e12c5d1SDavid du Colombier } 4573e12c5d1SDavid du Colombier fd = mkdir(path, 0777); 4583e12c5d1SDavid du Colombier if(fd < 0){ 4593e12c5d1SDavid du Colombier free(path); 4603e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 4613e12c5d1SDavid du Colombier } 4623e12c5d1SDavid du Colombier fd = open(path, 0); 4633e12c5d1SDavid du Colombier free(path); 4643e12c5d1SDavid du Colombier if(fd >= 0){ 4653e12c5d1SDavid du Colombier fchmod(fd, rhdr.perm&0777); 4663e12c5d1SDavid du Colombier fchown(fd, rf->uid, rf->gid); 4673e12c5d1SDavid du Colombier } 4683e12c5d1SDavid du Colombier }else{ 4693e12c5d1SDavid du Colombier fd = creat(path, 0666); 4703e12c5d1SDavid du Colombier if(fd >= 0){ 4713e12c5d1SDavid du Colombier if(m != 1){ 4723e12c5d1SDavid du Colombier close(fd); 4733e12c5d1SDavid du Colombier fd = open(path, m); 4743e12c5d1SDavid du Colombier } 4753e12c5d1SDavid du Colombier fchmod(fd, rhdr.perm&0777); 4763e12c5d1SDavid du Colombier fchown(fd, rf->uid, rf->gid); 4773e12c5d1SDavid du Colombier } 4783e12c5d1SDavid du Colombier free(path); 4793e12c5d1SDavid du Colombier if(fd < 0) 4803e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 4813e12c5d1SDavid du Colombier } 4823e12c5d1SDavid du Colombier f = newfile(); 4833e12c5d1SDavid du Colombier of = rf->file; 4843e12c5d1SDavid du Colombier f->path = estrdup(of->path); 4853e12c5d1SDavid du Colombier err = dostat(f, rhdr.name); 4863e12c5d1SDavid du Colombier if(err){ 4873e12c5d1SDavid du Colombier free(f->path); 4883e12c5d1SDavid du Colombier free(f->name); 4893e12c5d1SDavid du Colombier free(f); 4903e12c5d1SDavid du Colombier errjmp(err); 4913e12c5d1SDavid du Colombier } 4923e12c5d1SDavid du Colombier if(!devallowed && (f->stbuf.st_mode & S_IFCHR)){ 4933e12c5d1SDavid du Colombier free(f->path); 4943e12c5d1SDavid du Colombier free(f->name); 4953e12c5d1SDavid du Colombier free(f); 4963e12c5d1SDavid du Colombier errjmp(Especial); 4973e12c5d1SDavid du Colombier } 4983e12c5d1SDavid du Colombier if(--of->ref == 0){ 4993e12c5d1SDavid du Colombier free(of->path); 5003e12c5d1SDavid du Colombier free(of->name); 5013e12c5d1SDavid du Colombier free(of); 5023e12c5d1SDavid du Colombier } 5033e12c5d1SDavid du Colombier rf->file = f; 504*219b2ee8SDavid du Colombier rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 5053e12c5d1SDavid du Colombier rf->fd = erealloc(0, sizeof(Fd)); 5063e12c5d1SDavid du Colombier rf->fd->ref = 1; 5073e12c5d1SDavid du Colombier rf->fd->fd = fd; 5083e12c5d1SDavid du Colombier rf->fd->dir = 0; 5093e12c5d1SDavid du Colombier rf->fd->offset = 0; 5103e12c5d1SDavid du Colombier thdr.qid = f->qid; 5113e12c5d1SDavid du Colombier } 5123e12c5d1SDavid du Colombier 5133e12c5d1SDavid du Colombier void 5143e12c5d1SDavid du Colombier rread(void) 5153e12c5d1SDavid du Colombier { 5163e12c5d1SDavid du Colombier Rfile *rf; 5173e12c5d1SDavid du Colombier File *f; 5183e12c5d1SDavid du Colombier long n; 5193e12c5d1SDavid du Colombier DTYPE *de; 5203e12c5d1SDavid du Colombier Dir d; 5213e12c5d1SDavid du Colombier struct stat stbuf; 5223e12c5d1SDavid du Colombier char *path; 5233e12c5d1SDavid du Colombier 5243e12c5d1SDavid du Colombier rf = rfilefid(); 5253e12c5d1SDavid du Colombier if(rf->fd == 0) 5263e12c5d1SDavid du Colombier errjmp(Enotopen); 5273e12c5d1SDavid du Colombier if(rhdr.count > sizeof rdata) 5283e12c5d1SDavid du Colombier errjmp(Etoolarge); 5293e12c5d1SDavid du Colombier f = rf->file; 5303e12c5d1SDavid du Colombier if(rf->fd->dir){ 5313e12c5d1SDavid du Colombier errno = 0; 532*219b2ee8SDavid du Colombier rhdr.count = (rhdr.count/DIRLEN)*DIRLEN; 5333e12c5d1SDavid du Colombier if(rf->fd->offset != rhdr.offset){ 534*219b2ee8SDavid du Colombier rf->fd->offset = rhdr.offset; /* sync offset */ 5353e12c5d1SDavid du Colombier seekdir(rf->fd->dir, 0); 5363e12c5d1SDavid du Colombier for(n=0; n<rhdr.offset; ){ 5373e12c5d1SDavid du Colombier de = readdir(rf->fd->dir); 5383e12c5d1SDavid du Colombier if(de == 0) 5393e12c5d1SDavid du Colombier break; 5403e12c5d1SDavid du Colombier if(de->d_ino==0 || de->d_name[0]==0) 5413e12c5d1SDavid du Colombier continue; 5423e12c5d1SDavid du Colombier if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 5433e12c5d1SDavid du Colombier continue; 5443e12c5d1SDavid du Colombier n += DIRLEN; 5453e12c5d1SDavid du Colombier } 5463e12c5d1SDavid du Colombier } 5473e12c5d1SDavid du Colombier for(n=0; n<rhdr.count; ){ 5483e12c5d1SDavid du Colombier de = readdir(rf->fd->dir); 5493e12c5d1SDavid du Colombier if(de == 0) 5503e12c5d1SDavid du Colombier break; 5513e12c5d1SDavid du Colombier if(de->d_ino==0 || de->d_name[0]==0) 5523e12c5d1SDavid du Colombier continue; 5533e12c5d1SDavid du Colombier if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 5543e12c5d1SDavid du Colombier continue; 5553e12c5d1SDavid du Colombier strncpy(d.name, de->d_name, NAMELEN-1); 5563e12c5d1SDavid du Colombier d.name[NAMELEN-1] = 0; 5573e12c5d1SDavid du Colombier path = erealloc(0, strlen(f->path)+1+strlen(de->d_name)+1); 5583e12c5d1SDavid du Colombier sprintf(path, "%s/%s", f->path, de->d_name); 5593e12c5d1SDavid du Colombier memset(&stbuf, 0, sizeof stbuf); 5603e12c5d1SDavid du Colombier if(stat(path, &stbuf) < 0){ 5613e12c5d1SDavid du Colombier fprintf(stderr, "dir: bad path %s\n", path); 5623e12c5d1SDavid du Colombier /* but continue... probably a bad symlink */ 5633e12c5d1SDavid du Colombier } 5643e12c5d1SDavid du Colombier free(path); 5653e12c5d1SDavid du Colombier strncpy(d.uid, id2name(uid, stbuf.st_uid), NAMELEN); 5663e12c5d1SDavid du Colombier strncpy(d.gid, id2name(gid, stbuf.st_gid), NAMELEN); 5673e12c5d1SDavid du Colombier d.qid.path = qid(&stbuf); 568*219b2ee8SDavid du Colombier d.qid.vers = vers(&stbuf); 5693e12c5d1SDavid du Colombier d.mode = (d.qid.path&CHDIR)|(stbuf.st_mode&0777); 5703e12c5d1SDavid du Colombier d.atime = stbuf.st_atime; 5713e12c5d1SDavid du Colombier d.mtime = stbuf.st_mtime; 5723e12c5d1SDavid du Colombier d.len.l.hlength = 0; 5733e12c5d1SDavid du Colombier d.len.l.length = stbuf.st_size; 5743e12c5d1SDavid du Colombier convD2M(&d, rdata+n); 5753e12c5d1SDavid du Colombier n += DIRLEN; 5763e12c5d1SDavid du Colombier } 5773e12c5d1SDavid du Colombier }else{ 5783e12c5d1SDavid du Colombier errno = 0; 579*219b2ee8SDavid du Colombier if(rf->fd->offset != rhdr.offset){ 580*219b2ee8SDavid du Colombier rf->fd->offset = rhdr.offset; 5813e12c5d1SDavid du Colombier if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 5823e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 583*219b2ee8SDavid du Colombier } 5843e12c5d1SDavid du Colombier n = read(rf->fd->fd, rdata, rhdr.count); 5853e12c5d1SDavid du Colombier if(n < 0) 5863e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 5873e12c5d1SDavid du Colombier } 5883e12c5d1SDavid du Colombier rf->fd->offset += n; 5893e12c5d1SDavid du Colombier thdr.count = n; 5903e12c5d1SDavid du Colombier thdr.data = rdata; 5913e12c5d1SDavid du Colombier } 5923e12c5d1SDavid du Colombier 5933e12c5d1SDavid du Colombier void 5943e12c5d1SDavid du Colombier rwrite(void) 5953e12c5d1SDavid du Colombier { 5963e12c5d1SDavid du Colombier Rfile *rf; 5973e12c5d1SDavid du Colombier int n; 5983e12c5d1SDavid du Colombier 5993e12c5d1SDavid du Colombier rf = rfilefid(); 6003e12c5d1SDavid du Colombier if(rf->fd == 0) 6013e12c5d1SDavid du Colombier errjmp(Enotopen); 6023e12c5d1SDavid du Colombier if(rhdr.count > sizeof rdata) 6033e12c5d1SDavid du Colombier errjmp(Etoolarge); 6043e12c5d1SDavid du Colombier errno = 0; 605*219b2ee8SDavid du Colombier if(rf->fd->offset != rhdr.offset){ 606*219b2ee8SDavid du Colombier rf->fd->offset = rhdr.offset; 6073e12c5d1SDavid du Colombier if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 6083e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 609*219b2ee8SDavid du Colombier } 6103e12c5d1SDavid du Colombier n = write(rf->fd->fd, rhdr.data, rhdr.count); 6113e12c5d1SDavid du Colombier if(n < 0) 6123e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 6133e12c5d1SDavid du Colombier rf->fd->offset += n; 6143e12c5d1SDavid du Colombier thdr.count = n; 6153e12c5d1SDavid du Colombier } 6163e12c5d1SDavid du Colombier 6173e12c5d1SDavid du Colombier void 6183e12c5d1SDavid du Colombier rstat(void) 6193e12c5d1SDavid du Colombier { 6203e12c5d1SDavid du Colombier Rfile *rf; 6213e12c5d1SDavid du Colombier File *f; 6223e12c5d1SDavid du Colombier Dir d; 6233e12c5d1SDavid du Colombier 6243e12c5d1SDavid du Colombier rf = rfilefid(); 6253e12c5d1SDavid du Colombier f = rf->file; 6263e12c5d1SDavid du Colombier errjmp(dostat(f, 0)); 6273e12c5d1SDavid du Colombier strncpy(d.name, f->name, NAMELEN); 6283e12c5d1SDavid du Colombier strncpy(d.uid, id2name(uid, f->stbuf.st_uid), NAMELEN); 6293e12c5d1SDavid du Colombier strncpy(d.gid, id2name(gid, f->stbuf.st_gid), NAMELEN); 6303e12c5d1SDavid du Colombier d.qid = f->qid; 6313e12c5d1SDavid du Colombier d.mode = (f->qid.path&CHDIR)|(f->stbuf.st_mode&0777); 6323e12c5d1SDavid du Colombier d.atime = f->stbuf.st_atime; 6333e12c5d1SDavid du Colombier d.mtime = f->stbuf.st_mtime; 6343e12c5d1SDavid du Colombier d.len.l.hlength = 0; 6353e12c5d1SDavid du Colombier d.len.l.length = f->stbuf.st_size; 6363e12c5d1SDavid du Colombier convD2M(&d, thdr.stat); 6373e12c5d1SDavid du Colombier } 6383e12c5d1SDavid du Colombier 6393e12c5d1SDavid du Colombier void 6403e12c5d1SDavid du Colombier rwstat(void) 6413e12c5d1SDavid du Colombier { 6423e12c5d1SDavid du Colombier Rfile *rf; 6433e12c5d1SDavid du Colombier File *f; 6443e12c5d1SDavid du Colombier Dir d; 6453e12c5d1SDavid du Colombier Pass *p; 6463e12c5d1SDavid du Colombier char *path, *dir, name[NAMELEN]; 6473e12c5d1SDavid du Colombier 6483e12c5d1SDavid du Colombier rf = rfilefid(); 6493e12c5d1SDavid du Colombier f = rf->file; 6503e12c5d1SDavid du Colombier errjmp(dostat(f, 0)); 6513e12c5d1SDavid du Colombier convM2D(rhdr.stat, &d); 6523e12c5d1SDavid du Colombier errno = 0; 6533e12c5d1SDavid du Colombier if(rf->uid != f->stbuf.st_uid) 6543e12c5d1SDavid du Colombier errjmp(Eowner); 6553e12c5d1SDavid du Colombier if(strcmp(d.name, f->name) != 0){ 6563e12c5d1SDavid du Colombier parentwrperm(rf); 6573e12c5d1SDavid du Colombier dir = bldpath(f->path, "..", name); 6583e12c5d1SDavid du Colombier path = erealloc(0, strlen(dir)+1+strlen(d.name)+1); 6593e12c5d1SDavid du Colombier sprintf(path, "%s/%s", dir, d.name); 6603e12c5d1SDavid du Colombier if(link(f->path, path) < 0){ 6613e12c5d1SDavid du Colombier free(path); 6623e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 6633e12c5d1SDavid du Colombier } 6643e12c5d1SDavid du Colombier if(unlink(f->path) < 0){ 6653e12c5d1SDavid du Colombier free(path); 6663e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 6673e12c5d1SDavid du Colombier } 6683e12c5d1SDavid du Colombier free(f->path); 6693e12c5d1SDavid du Colombier free(f->name); 6703e12c5d1SDavid du Colombier f->path = path; 6713e12c5d1SDavid du Colombier f->name = estrdup(d.name); 6723e12c5d1SDavid du Colombier } 6733e12c5d1SDavid du Colombier if((d.mode&0777) != (f->stbuf.st_mode&0777)){ 6743e12c5d1SDavid du Colombier if(chmod(f->path, d.mode&0777) < 0) 6753e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 6763e12c5d1SDavid du Colombier f->stbuf.st_mode &= ~0777; 6773e12c5d1SDavid du Colombier f->stbuf.st_mode |= d.mode&0777; 6783e12c5d1SDavid du Colombier } 6793e12c5d1SDavid du Colombier p = name2pass(gid, d.gid); 6803e12c5d1SDavid du Colombier if(p == 0) 6813e12c5d1SDavid du Colombier errjmp(Eunknown); 6823e12c5d1SDavid du Colombier if(p->id != f->stbuf.st_gid){ 6833e12c5d1SDavid du Colombier if(chown(f->path, f->stbuf.st_uid, p->id) < 0) 6843e12c5d1SDavid du Colombier errjmp(sys_errlist[errno]); 6853e12c5d1SDavid du Colombier f->stbuf.st_gid = p->id; 6863e12c5d1SDavid du Colombier } 6873e12c5d1SDavid du Colombier } 6883e12c5d1SDavid du Colombier 6893e12c5d1SDavid du Colombier void 6903e12c5d1SDavid du Colombier rclunk(int rm) 6913e12c5d1SDavid du Colombier { 6923e12c5d1SDavid du Colombier int ret; 6933e12c5d1SDavid du Colombier char *err; 6943e12c5d1SDavid du Colombier Rfile *rf; 6953e12c5d1SDavid du Colombier File *f; 6963e12c5d1SDavid du Colombier Fd *fd; 6973e12c5d1SDavid du Colombier 6983e12c5d1SDavid du Colombier err = 0; 6993e12c5d1SDavid du Colombier rf = rfilefid(); 7003e12c5d1SDavid du Colombier f = rf->file; 7013e12c5d1SDavid du Colombier if(rm){ 7023e12c5d1SDavid du Colombier parentwrperm(rf); 7033e12c5d1SDavid du Colombier if(f->qid.path & CHDIR) 7043e12c5d1SDavid du Colombier ret = rmdir(f->path); 7053e12c5d1SDavid du Colombier else 7063e12c5d1SDavid du Colombier ret = unlink(f->path); 7073e12c5d1SDavid du Colombier if(ret) 7083e12c5d1SDavid du Colombier err = sys_errlist[errno]; 709*219b2ee8SDavid du Colombier }else if(rf->rclose){ /* ignore errors */ 710*219b2ee8SDavid du Colombier if(f->qid.path & CHDIR) 711*219b2ee8SDavid du Colombier rmdir(f->path); 712*219b2ee8SDavid du Colombier else 713*219b2ee8SDavid du Colombier unlink(f->path); 7143e12c5d1SDavid du Colombier } 715*219b2ee8SDavid du Colombier 7163e12c5d1SDavid du Colombier rf->busy = 0; 7173e12c5d1SDavid du Colombier if(--f->ref == 0){ 7183e12c5d1SDavid du Colombier free(f->path); 7193e12c5d1SDavid du Colombier free(f->name); 7203e12c5d1SDavid du Colombier free(f); 7213e12c5d1SDavid du Colombier } 7223e12c5d1SDavid du Colombier fd = rf->fd; 7233e12c5d1SDavid du Colombier if(fd){ 7243e12c5d1SDavid du Colombier if(fd->ref <= 0) 7253e12c5d1SDavid du Colombier error("clunk fd count"); 7263e12c5d1SDavid du Colombier if(--fd->ref == 0){ 7273e12c5d1SDavid du Colombier if(fd->fd) 7283e12c5d1SDavid du Colombier close(fd->fd); 7293e12c5d1SDavid du Colombier if(fd->dir) 7303e12c5d1SDavid du Colombier closedir(fd->dir); 7313e12c5d1SDavid du Colombier free(fd); 7323e12c5d1SDavid du Colombier } 7333e12c5d1SDavid du Colombier rf->fd = 0; 7343e12c5d1SDavid du Colombier } 7353e12c5d1SDavid du Colombier if(err) 7363e12c5d1SDavid du Colombier errjmp(err); 7373e12c5d1SDavid du Colombier } 7383e12c5d1SDavid du Colombier 7393e12c5d1SDavid du Colombier char* 7403e12c5d1SDavid du Colombier bldpath(char *a, char *elem, char *name) 7413e12c5d1SDavid du Colombier { 7423e12c5d1SDavid du Colombier char *path, *p; 7433e12c5d1SDavid du Colombier 7443e12c5d1SDavid du Colombier if(strcmp(elem, "..") == 0){ 7453e12c5d1SDavid du Colombier if(strcmp(a, "/") == 0){ 7463e12c5d1SDavid du Colombier path = estrdup(a); 7473e12c5d1SDavid du Colombier strcpy(name, a); 7483e12c5d1SDavid du Colombier }else{ 7493e12c5d1SDavid du Colombier p = strrchr(a, '/'); 7503e12c5d1SDavid du Colombier if(p == 0){ 7513e12c5d1SDavid du Colombier fprintf(stderr, "path: '%s'\n", path); 7523e12c5d1SDavid du Colombier error("malformed path 1"); 7533e12c5d1SDavid du Colombier } 7543e12c5d1SDavid du Colombier if(p == a) /* reduced to "/" */ 7553e12c5d1SDavid du Colombier p++; 7563e12c5d1SDavid du Colombier path = erealloc(0, (p-a)+1); 7573e12c5d1SDavid du Colombier memmove(path, a, (p-a)); 7583e12c5d1SDavid du Colombier path[(p-a)] = 0; 7593e12c5d1SDavid du Colombier if(strcmp(path, "/") == 0) 7603e12c5d1SDavid du Colombier p = path; 7613e12c5d1SDavid du Colombier else{ 7623e12c5d1SDavid du Colombier p = strrchr(path, '/'); 7633e12c5d1SDavid du Colombier if(p == 0){ 7643e12c5d1SDavid du Colombier fprintf(stderr, "path: '%s'\n", path); 7653e12c5d1SDavid du Colombier error("malformed path 2"); 7663e12c5d1SDavid du Colombier } 7673e12c5d1SDavid du Colombier p++; 7683e12c5d1SDavid du Colombier } 7693e12c5d1SDavid du Colombier strcpy(name, p); 7703e12c5d1SDavid du Colombier } 7713e12c5d1SDavid du Colombier }else{ 7723e12c5d1SDavid du Colombier if(strcmp(a, "/") == 0) 7733e12c5d1SDavid du Colombier a = ""; 7743e12c5d1SDavid du Colombier path = erealloc(0, strlen(a)+1+strlen(elem)+1); 7753e12c5d1SDavid du Colombier sprintf(path, "%s/%s", a, elem); 7763e12c5d1SDavid du Colombier strcpy(name, elem); 7773e12c5d1SDavid du Colombier } 7783e12c5d1SDavid du Colombier if(strlen(name) >= NAMELEN) 7793e12c5d1SDavid du Colombier error("bldpath: name too long"); 7803e12c5d1SDavid du Colombier return path; 7813e12c5d1SDavid du Colombier } 7823e12c5d1SDavid du Colombier 7833e12c5d1SDavid du Colombier char* 7843e12c5d1SDavid du Colombier dostat(File *f, char *elem) 7853e12c5d1SDavid du Colombier { 7863e12c5d1SDavid du Colombier char *path; 7873e12c5d1SDavid du Colombier struct stat stbuf; 7883e12c5d1SDavid du Colombier char name[NAMELEN]; 7893e12c5d1SDavid du Colombier 7903e12c5d1SDavid du Colombier if(elem) 7913e12c5d1SDavid du Colombier path = bldpath(f->path, elem, name); 7923e12c5d1SDavid du Colombier else 7933e12c5d1SDavid du Colombier path = f->path; 7943e12c5d1SDavid du Colombier errno = 0; 7953e12c5d1SDavid du Colombier if(stat(path, &stbuf) < 0) 7963e12c5d1SDavid du Colombier return sys_errlist[errno]; 7973e12c5d1SDavid du Colombier if(elem){ 7983e12c5d1SDavid du Colombier free(f->path); 7993e12c5d1SDavid du Colombier f->path = path; 8003e12c5d1SDavid du Colombier f->name = estrdup(name); 8013e12c5d1SDavid du Colombier } 8023e12c5d1SDavid du Colombier f->qid.path = qid(&stbuf); 803*219b2ee8SDavid du Colombier f->qid.vers = vers(&stbuf); 8043e12c5d1SDavid du Colombier f->stbuf = stbuf; 8053e12c5d1SDavid du Colombier return 0; 8063e12c5d1SDavid du Colombier } 8073e12c5d1SDavid du Colombier 8083e12c5d1SDavid du Colombier int 8093e12c5d1SDavid du Colombier omode(int m) 8103e12c5d1SDavid du Colombier { 8113e12c5d1SDavid du Colombier switch(m){ 8123e12c5d1SDavid du Colombier case 0: /* OREAD */ 8133e12c5d1SDavid du Colombier case 3: /* OEXEC */ 8143e12c5d1SDavid du Colombier return 0; 8153e12c5d1SDavid du Colombier case 1: /* OWRITE */ 8163e12c5d1SDavid du Colombier return 1; 8173e12c5d1SDavid du Colombier case 2: /* ORDWR */ 8183e12c5d1SDavid du Colombier return 2; 8193e12c5d1SDavid du Colombier } 8203e12c5d1SDavid du Colombier errjmp(Emode); 8213e12c5d1SDavid du Colombier return 0; 8223e12c5d1SDavid du Colombier } 8233e12c5d1SDavid du Colombier 8243e12c5d1SDavid du Colombier void 8253e12c5d1SDavid du Colombier sendmsg(char *err) 8263e12c5d1SDavid du Colombier { 8273e12c5d1SDavid du Colombier int n; 8283e12c5d1SDavid du Colombier 8293e12c5d1SDavid du Colombier if(err){ 8303e12c5d1SDavid du Colombier thdr.type = Rerror; 8313e12c5d1SDavid du Colombier strncpy(thdr.ename, err, ERRLEN); 8323e12c5d1SDavid du Colombier } 8333e12c5d1SDavid du Colombier DBG(fprintf(stderr, "<< %s\n", mfmt(&thdr))); 8343e12c5d1SDavid du Colombier n = convS2M(&thdr, tdata); 8353e12c5d1SDavid du Colombier if(n == 0) 8363e12c5d1SDavid du Colombier error("bad sendmsg format"); 8373e12c5d1SDavid du Colombier if(write(1, tdata, n) != n) 8383e12c5d1SDavid du Colombier error("write error"); 8393e12c5d1SDavid du Colombier } 8403e12c5d1SDavid du Colombier 8413e12c5d1SDavid du Colombier 8423e12c5d1SDavid du Colombier int 8433e12c5d1SDavid du Colombier okfid(int fid) 8443e12c5d1SDavid du Colombier { 8453e12c5d1SDavid du Colombier enum{ Delta=10 }; 8463e12c5d1SDavid du Colombier 8473e12c5d1SDavid du Colombier if(fid < 0){ 8483e12c5d1SDavid du Colombier fprintf(stderr, "u9fs: negative fid %d\n", fid); 8493e12c5d1SDavid du Colombier return 0; 8503e12c5d1SDavid du Colombier } 8513e12c5d1SDavid du Colombier if(fid >= nrfilealloc){ 8523e12c5d1SDavid du Colombier fid += Delta; 8533e12c5d1SDavid du Colombier rfile = erealloc(rfile, fid*sizeof(Rfile)); 8543e12c5d1SDavid du Colombier memset(rfile+nrfilealloc, 0, (fid-nrfilealloc)*sizeof(Rfile)); 8553e12c5d1SDavid du Colombier nrfilealloc = fid; 8563e12c5d1SDavid du Colombier } 8573e12c5d1SDavid du Colombier return 1; 8583e12c5d1SDavid du Colombier } 8593e12c5d1SDavid du Colombier 8603e12c5d1SDavid du Colombier Rfile* 8613e12c5d1SDavid du Colombier rfilefid(void) 8623e12c5d1SDavid du Colombier { 8633e12c5d1SDavid du Colombier Rfile *rf; 8643e12c5d1SDavid du Colombier 8653e12c5d1SDavid du Colombier if(!okfid(rhdr.fid)) 8663e12c5d1SDavid du Colombier errjmp(Ebadfid); 8673e12c5d1SDavid du Colombier rf = &rfile[rhdr.fid]; 8683e12c5d1SDavid du Colombier if(rf->busy == 0) 8693e12c5d1SDavid du Colombier errjmp(Ebadfid); 8703e12c5d1SDavid du Colombier if(rf->file->ref <= 0) 8713e12c5d1SDavid du Colombier error("ref count"); 8723e12c5d1SDavid du Colombier return rf; 8733e12c5d1SDavid du Colombier } 8743e12c5d1SDavid du Colombier 8753e12c5d1SDavid du Colombier void 8763e12c5d1SDavid du Colombier perm(Rfile *rf, int mask, struct stat *st) 8773e12c5d1SDavid du Colombier { 8783e12c5d1SDavid du Colombier if(st == 0) 8793e12c5d1SDavid du Colombier st = &rf->file->stbuf; 8803e12c5d1SDavid du Colombier /* plan 9 access semantics; simpler and more sensible */ 8813e12c5d1SDavid du Colombier if(rf->uid == st->st_uid) 8823e12c5d1SDavid du Colombier if((st->st_mode>>6) & mask) 8833e12c5d1SDavid du Colombier return; 8843e12c5d1SDavid du Colombier if(rf->gid == st->st_gid) 8853e12c5d1SDavid du Colombier if((st->st_mode>>3) & mask) 8863e12c5d1SDavid du Colombier return; 8873e12c5d1SDavid du Colombier if((st->st_mode>>0) & mask) 8883e12c5d1SDavid du Colombier return; 8893e12c5d1SDavid du Colombier errjmp(Eperm); 8903e12c5d1SDavid du Colombier } 8913e12c5d1SDavid du Colombier 8923e12c5d1SDavid du Colombier void 8933e12c5d1SDavid du Colombier parentwrperm(Rfile *rf) 8943e12c5d1SDavid du Colombier { 8953e12c5d1SDavid du Colombier Rfile trf; 8963e12c5d1SDavid du Colombier struct stat st; 8973e12c5d1SDavid du Colombier char *dirp, dir[512]; 8983e12c5d1SDavid du Colombier 8993e12c5d1SDavid du Colombier dirp = bldpath(rf->file->path, "..", dir); 9003e12c5d1SDavid du Colombier if(strlen(dirp) < sizeof dir){ /* ugly: avoid leaving dirp allocated */ 9013e12c5d1SDavid du Colombier strcpy(dir, dirp); 9023e12c5d1SDavid du Colombier free(dirp); 9033e12c5d1SDavid du Colombier dirp = dir; 9043e12c5d1SDavid du Colombier } 9053e12c5d1SDavid du Colombier if(stat(dirp, &st) < 0) 9063e12c5d1SDavid du Colombier errjmp(Eperm); 9073e12c5d1SDavid du Colombier trf.uid = rf->uid; 9083e12c5d1SDavid du Colombier trf.gid = rf->gid; 9093e12c5d1SDavid du Colombier perm(&trf, 2, &st); 9103e12c5d1SDavid du Colombier } 9113e12c5d1SDavid du Colombier 9123e12c5d1SDavid du Colombier File* 9133e12c5d1SDavid du Colombier newfile(void) 9143e12c5d1SDavid du Colombier { 9153e12c5d1SDavid du Colombier File *f; 9163e12c5d1SDavid du Colombier 9173e12c5d1SDavid du Colombier f = erealloc(0, sizeof(File)); 9183e12c5d1SDavid du Colombier memset(f, 0, sizeof(File)); 9193e12c5d1SDavid du Colombier f->ref = 1; 9203e12c5d1SDavid du Colombier return f; 9213e12c5d1SDavid du Colombier } 9223e12c5d1SDavid du Colombier 9233e12c5d1SDavid du Colombier /* 9243e12c5d1SDavid du Colombier * qids: directory bit, seven bits of device, 24 bits of inode 9253e12c5d1SDavid du Colombier */ 9263e12c5d1SDavid du Colombier Ulong 927*219b2ee8SDavid du Colombier vers(struct stat *st) 928*219b2ee8SDavid du Colombier { 929*219b2ee8SDavid du Colombier return st->st_mtime; 930*219b2ee8SDavid du Colombier } 931*219b2ee8SDavid du Colombier 932*219b2ee8SDavid du Colombier Ulong 9333e12c5d1SDavid du Colombier qid(struct stat *st) 9343e12c5d1SDavid du Colombier { 9353e12c5d1SDavid du Colombier static int nqdev; 9363e12c5d1SDavid du Colombier static Uchar *qdev; 9373e12c5d1SDavid du Colombier Ulong q; 9383e12c5d1SDavid du Colombier int dev; 9393e12c5d1SDavid du Colombier 940*219b2ee8SDavid du Colombier if(qdev == 0){ 9413e12c5d1SDavid du Colombier qdev = erealloc(0, 65536U); 942*219b2ee8SDavid du Colombier memset(qdev, 0, 65536U); 943*219b2ee8SDavid du Colombier } 9443e12c5d1SDavid du Colombier q = 0; 945*219b2ee8SDavid du Colombier if((st->st_mode&S_IFMT) == S_IFDIR) 9463e12c5d1SDavid du Colombier q = CHDIR; 9473e12c5d1SDavid du Colombier dev = st->st_dev & 0xFFFFUL; 9483e12c5d1SDavid du Colombier if(qdev[dev] == 0){ 9493e12c5d1SDavid du Colombier if(++nqdev >= 128) 9503e12c5d1SDavid du Colombier error("too many devices"); 9513e12c5d1SDavid du Colombier qdev[dev] = nqdev; 9523e12c5d1SDavid du Colombier } 9533e12c5d1SDavid du Colombier q |= qdev[dev]<<24; 9543e12c5d1SDavid du Colombier q |= st->st_ino & 0x00FFFFFFUL; 9553e12c5d1SDavid du Colombier return q; 9563e12c5d1SDavid du Colombier } 9573e12c5d1SDavid du Colombier 9583e12c5d1SDavid du Colombier Pass* 9593e12c5d1SDavid du Colombier name2pass(Pass **pw, char *name) 9603e12c5d1SDavid du Colombier { 9613e12c5d1SDavid du Colombier int i; 9623e12c5d1SDavid du Colombier Pass *p; 9633e12c5d1SDavid du Colombier 9643e12c5d1SDavid du Colombier for(i=0; i<256; i++) 9653e12c5d1SDavid du Colombier for(p = pw[i]; p; p = p->next) 9663e12c5d1SDavid du Colombier if(strcmp(name, p->name) == 0) 9673e12c5d1SDavid du Colombier return p; 9683e12c5d1SDavid du Colombier return 0; 9693e12c5d1SDavid du Colombier } 9703e12c5d1SDavid du Colombier 9713e12c5d1SDavid du Colombier char* 9723e12c5d1SDavid du Colombier id2name(Pass **pw, int id) 9733e12c5d1SDavid du Colombier { 9743e12c5d1SDavid du Colombier int i; 9753e12c5d1SDavid du Colombier Pass *p; 9763e12c5d1SDavid du Colombier char *s; 9773e12c5d1SDavid du Colombier static char buf[8]; 9783e12c5d1SDavid du Colombier 9793e12c5d1SDavid du Colombier s = 0; 9803e12c5d1SDavid du Colombier /* use last on list == first in file */ 9813e12c5d1SDavid du Colombier i = (id&0xFF) ^ ((id>>8)&0xFF); 9823e12c5d1SDavid du Colombier for(p = pw[i]; p; p = p->next) 9833e12c5d1SDavid du Colombier if(p->id == id) 9843e12c5d1SDavid du Colombier s = p->name; 9853e12c5d1SDavid du Colombier if(s) 9863e12c5d1SDavid du Colombier return s; 9873e12c5d1SDavid du Colombier sprintf(buf, "%d", id); 9883e12c5d1SDavid du Colombier return buf; 9893e12c5d1SDavid du Colombier } 9903e12c5d1SDavid du Colombier 9913e12c5d1SDavid du Colombier void 9923e12c5d1SDavid du Colombier freepass(Pass **pass) 9933e12c5d1SDavid du Colombier { 9943e12c5d1SDavid du Colombier int i; 9953e12c5d1SDavid du Colombier Pass *p, *np; 9963e12c5d1SDavid du Colombier 9973e12c5d1SDavid du Colombier for(i=0; i<256; i++){ 9983e12c5d1SDavid du Colombier for(p = pass[i]; p; p = np){ 9993e12c5d1SDavid du Colombier np = p->next; 10003e12c5d1SDavid du Colombier free(p); 10013e12c5d1SDavid du Colombier } 10023e12c5d1SDavid du Colombier pass[i] = 0; 10033e12c5d1SDavid du Colombier } 10043e12c5d1SDavid du Colombier } 10053e12c5d1SDavid du Colombier 10063e12c5d1SDavid du Colombier void 10073e12c5d1SDavid du Colombier getpwdf(void) 10083e12c5d1SDavid du Colombier { 10093e12c5d1SDavid du Colombier static mtime; 10103e12c5d1SDavid du Colombier struct stat stbuf; 10113e12c5d1SDavid du Colombier struct passwd *pw; 10123e12c5d1SDavid du Colombier int i; 10133e12c5d1SDavid du Colombier Pass *p; 10143e12c5d1SDavid du Colombier 10153e12c5d1SDavid du Colombier if(stat("/etc/passwd", &stbuf) < 0) 10163e12c5d1SDavid du Colombier error("can't read /etc/passwd"); 10173e12c5d1SDavid du Colombier if(stbuf.st_mtime <= mtime) 10183e12c5d1SDavid du Colombier return; 10193e12c5d1SDavid du Colombier freepass(uid); 10203e12c5d1SDavid du Colombier while(pw = getpwent()){ 10213e12c5d1SDavid du Colombier i = pw->pw_uid; 10223e12c5d1SDavid du Colombier i = (i&0xFF) ^ ((i>>8)&0xFF); 10233e12c5d1SDavid du Colombier p = erealloc(0, sizeof(Pass)); 10243e12c5d1SDavid du Colombier p->next = uid[i]; 10253e12c5d1SDavid du Colombier uid[i] = p; 10263e12c5d1SDavid du Colombier p->id = pw->pw_uid; 10273e12c5d1SDavid du Colombier p->gid = pw->pw_gid; 10283e12c5d1SDavid du Colombier p->name = estrdup(pw->pw_name); 10293e12c5d1SDavid du Colombier } 10303e12c5d1SDavid du Colombier setpwent(); 10313e12c5d1SDavid du Colombier endpwent(); 10323e12c5d1SDavid du Colombier } 10333e12c5d1SDavid du Colombier 10343e12c5d1SDavid du Colombier void 10353e12c5d1SDavid du Colombier getgrpf(void) 10363e12c5d1SDavid du Colombier { 10373e12c5d1SDavid du Colombier static mtime; 10383e12c5d1SDavid du Colombier struct stat stbuf; 10393e12c5d1SDavid du Colombier struct group *pw; 10403e12c5d1SDavid du Colombier int i; 10413e12c5d1SDavid du Colombier Pass *p; 10423e12c5d1SDavid du Colombier 10433e12c5d1SDavid du Colombier if(stat("/etc/group", &stbuf) < 0) 10443e12c5d1SDavid du Colombier error("can't read /etc/group"); 10453e12c5d1SDavid du Colombier if(stbuf.st_mtime <= mtime) 10463e12c5d1SDavid du Colombier return; 10473e12c5d1SDavid du Colombier freepass(gid); 10483e12c5d1SDavid du Colombier while(pw = getgrent()){ 10493e12c5d1SDavid du Colombier i = pw->gr_gid; 10503e12c5d1SDavid du Colombier i = (i&0xFF) ^ ((i>>8)&0xFF); 10513e12c5d1SDavid du Colombier p = erealloc(0, sizeof(Pass)); 10523e12c5d1SDavid du Colombier p->next = gid[i]; 10533e12c5d1SDavid du Colombier gid[i] = p; 10543e12c5d1SDavid du Colombier p->id = pw->gr_gid; 10553e12c5d1SDavid du Colombier p->gid = 0; 10563e12c5d1SDavid du Colombier p->name = estrdup(pw->gr_name); 10573e12c5d1SDavid du Colombier } 10583e12c5d1SDavid du Colombier setgrent(); 10593e12c5d1SDavid du Colombier endgrent(); 10603e12c5d1SDavid du Colombier } 10613e12c5d1SDavid du Colombier 10623e12c5d1SDavid du Colombier void 10633e12c5d1SDavid du Colombier error(char *s) 10643e12c5d1SDavid du Colombier { 10653e12c5d1SDavid du Colombier fprintf(stderr, "u9fs: %s\n", s); 10663e12c5d1SDavid du Colombier perror("unix error"); 10673e12c5d1SDavid du Colombier exit(1); 10683e12c5d1SDavid du Colombier } 10693e12c5d1SDavid du Colombier 10703e12c5d1SDavid du Colombier void 10713e12c5d1SDavid du Colombier errjmp(char *s) 10723e12c5d1SDavid du Colombier { 10733e12c5d1SDavid du Colombier if(s == 0) 10743e12c5d1SDavid du Colombier return; 10753e12c5d1SDavid du Colombier sendmsg(s); 10763e12c5d1SDavid du Colombier longjmp(loopjmp, 1); 10773e12c5d1SDavid du Colombier } 10783e12c5d1SDavid du Colombier 10793e12c5d1SDavid du Colombier void* 10803e12c5d1SDavid du Colombier erealloc(void *p, unsigned n) 10813e12c5d1SDavid du Colombier { 10823e12c5d1SDavid du Colombier if(p == 0) 10833e12c5d1SDavid du Colombier p = malloc(n); 10843e12c5d1SDavid du Colombier else 10853e12c5d1SDavid du Colombier p = realloc(p, n); 10863e12c5d1SDavid du Colombier if(p == 0) 10873e12c5d1SDavid du Colombier error("realloc fail"); 10883e12c5d1SDavid du Colombier return p; 10893e12c5d1SDavid du Colombier } 10903e12c5d1SDavid du Colombier 10913e12c5d1SDavid du Colombier char* 10923e12c5d1SDavid du Colombier estrdup(char *p) 10933e12c5d1SDavid du Colombier { 10943e12c5d1SDavid du Colombier p = strdup(p); 10953e12c5d1SDavid du Colombier if(p == 0) 10963e12c5d1SDavid du Colombier error("strdup fail"); 10973e12c5d1SDavid du Colombier return p; 10983e12c5d1SDavid du Colombier } 1099*219b2ee8SDavid du Colombier 1100*219b2ee8SDavid du Colombier #ifdef SOCKETS 1101*219b2ee8SDavid du Colombier void 1102*219b2ee8SDavid du Colombier remotehostname(void) 1103*219b2ee8SDavid du Colombier { 1104*219b2ee8SDavid du Colombier struct sockaddr_in sock; 1105*219b2ee8SDavid du Colombier struct hostent *hp; 1106*219b2ee8SDavid du Colombier int len; 1107*219b2ee8SDavid du Colombier int on = 1; 1108*219b2ee8SDavid du Colombier 1109*219b2ee8SDavid du Colombier len = sizeof sock; 1110*219b2ee8SDavid du Colombier if(getpeername(0, &sock, &len) < 0) 1111*219b2ee8SDavid du Colombier error("getpeername"); 1112*219b2ee8SDavid du Colombier hp = gethostbyaddr((char *)&sock.sin_addr, sizeof (struct in_addr), 1113*219b2ee8SDavid du Colombier sock.sin_family); 1114*219b2ee8SDavid du Colombier if(hp == 0) 1115*219b2ee8SDavid du Colombier error("gethostbyaddr"); 1116*219b2ee8SDavid du Colombier strcpy(bsdhost, hp->h_name); 1117*219b2ee8SDavid du Colombier fprintf(stderr, "bsdhost %s on %d\n", bsdhost, getpid()); 1118*219b2ee8SDavid du Colombier 1119*219b2ee8SDavid du Colombier setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); 1120*219b2ee8SDavid du Colombier } 1121*219b2ee8SDavid du Colombier #endif 1122