19a747e4fSDavid du Colombier /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */
2f5736e95SDavid du Colombier /* plan9.h is first to get the large file support definitions as early as possible */
3f5736e95SDavid du Colombier #include <plan9.h>
49a747e4fSDavid du Colombier #include <sys/stat.h> /* for stat, umask */
59a747e4fSDavid du Colombier #include <stdlib.h> /* for malloc */
69a747e4fSDavid du Colombier #include <string.h> /* for strcpy, memmove */
79a747e4fSDavid du Colombier #include <pwd.h> /* for getpwnam, getpwuid */
89a747e4fSDavid du Colombier #include <grp.h> /* for getgrnam, getgrgid */
99a747e4fSDavid du Colombier #include <unistd.h> /* for gethostname, pread, pwrite, read, write */
109a747e4fSDavid du Colombier #include <utime.h> /* for utime */
119a747e4fSDavid du Colombier #include <dirent.h> /* for readdir */
129a747e4fSDavid du Colombier #include <errno.h> /* for errno */
139a747e4fSDavid du Colombier #include <stdio.h> /* for remove [sic] */
149a747e4fSDavid du Colombier #include <fcntl.h> /* for O_RDONLY, etc. */
153e12c5d1SDavid du Colombier
169a747e4fSDavid du Colombier #include <sys/socket.h> /* various networking crud */
17219b2ee8SDavid du Colombier #include <netinet/in.h>
18219b2ee8SDavid du Colombier #include <netdb.h>
199a747e4fSDavid du Colombier
209a747e4fSDavid du Colombier #include <fcall.h>
219a747e4fSDavid du Colombier #include <oldfcall.h>
229a747e4fSDavid du Colombier #include <u9fs.h>
239a747e4fSDavid du Colombier
249a747e4fSDavid du Colombier /* #ifndef because can be given in makefile */
259a747e4fSDavid du Colombier #ifndef DEFAULTLOG
269a747e4fSDavid du Colombier #define DEFAULTLOG "/tmp/u9fs.log"
273e12c5d1SDavid du Colombier #endif
283e12c5d1SDavid du Colombier
299a747e4fSDavid du Colombier char *logfile = DEFAULTLOG;
303e12c5d1SDavid du Colombier
319a747e4fSDavid du Colombier #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m))
329a747e4fSDavid du Colombier
339a747e4fSDavid du Colombier enum {
349a747e4fSDavid du Colombier Tdot = 1,
359a747e4fSDavid du Colombier Tdotdot
363e12c5d1SDavid du Colombier };
373e12c5d1SDavid du Colombier
389a747e4fSDavid du Colombier enum {
399a747e4fSDavid du Colombier P9P1,
409a747e4fSDavid du Colombier P9P2000
413e12c5d1SDavid du Colombier };
423e12c5d1SDavid du Colombier
439a747e4fSDavid du Colombier typedef struct User User;
449a747e4fSDavid du Colombier struct User {
453e12c5d1SDavid du Colombier int id;
469a747e4fSDavid du Colombier gid_t defaultgid;
473e12c5d1SDavid du Colombier char *name;
489a747e4fSDavid du Colombier char **mem; /* group members */
497dd7cddfSDavid du Colombier int nmem;
509a747e4fSDavid du Colombier User *next;
513e12c5d1SDavid du Colombier };
523e12c5d1SDavid du Colombier
539a747e4fSDavid du Colombier struct Fid {
549a747e4fSDavid du Colombier int fid;
559a747e4fSDavid du Colombier char *path;
569a747e4fSDavid du Colombier struct stat st;
579a747e4fSDavid du Colombier User *u;
589a747e4fSDavid du Colombier int omode;
599a747e4fSDavid du Colombier DIR *dir;
609a747e4fSDavid du Colombier int diroffset;
619a747e4fSDavid du Colombier int fd;
629a747e4fSDavid du Colombier struct dirent *dirent;
63bd8a67bbSDavid du Colombier int direof;
649a747e4fSDavid du Colombier Fid *next;
659a747e4fSDavid du Colombier Fid *prev;
6650a9bdd4SDavid du Colombier int auth;
6750a9bdd4SDavid du Colombier void *authmagic;
689a747e4fSDavid du Colombier };
693e12c5d1SDavid du Colombier
709a747e4fSDavid du Colombier void* emalloc(size_t);
719a747e4fSDavid du Colombier void* erealloc(void*, size_t);
723e12c5d1SDavid du Colombier char* estrdup(char*);
73dfda52d8SDavid du Colombier char* estrpath(char*, char*, int);
749a747e4fSDavid du Colombier void sysfatal(char*, ...);
759a747e4fSDavid du Colombier int okuser(char*);
763e12c5d1SDavid du Colombier
779a747e4fSDavid du Colombier void rversion(Fcall*, Fcall*);
789a747e4fSDavid du Colombier void rauth(Fcall*, Fcall*);
799a747e4fSDavid du Colombier void rattach(Fcall*, Fcall*);
809a747e4fSDavid du Colombier void rflush(Fcall*, Fcall*);
819a747e4fSDavid du Colombier void rclone(Fcall*, Fcall*);
829a747e4fSDavid du Colombier void rwalk(Fcall*, Fcall*);
839a747e4fSDavid du Colombier void ropen(Fcall*, Fcall*);
849a747e4fSDavid du Colombier void rcreate(Fcall*, Fcall*);
859a747e4fSDavid du Colombier void rread(Fcall*, Fcall*);
869a747e4fSDavid du Colombier void rwrite(Fcall*, Fcall*);
879a747e4fSDavid du Colombier void rclunk(Fcall*, Fcall*);
889a747e4fSDavid du Colombier void rstat(Fcall*, Fcall*);
899a747e4fSDavid du Colombier void rwstat(Fcall*, Fcall*);
909a747e4fSDavid du Colombier void rclwalk(Fcall*, Fcall*);
919a747e4fSDavid du Colombier void rremove(Fcall*, Fcall*);
929a747e4fSDavid du Colombier
939a747e4fSDavid du Colombier User* uname2user(char*);
949a747e4fSDavid du Colombier User* gname2user(char*);
959a747e4fSDavid du Colombier User* uid2user(int);
969a747e4fSDavid du Colombier User* gid2user(int);
979a747e4fSDavid du Colombier
989a747e4fSDavid du Colombier Fid* newfid(int, char**);
9950a9bdd4SDavid du Colombier Fid* oldfidex(int, int, char**);
1009a747e4fSDavid du Colombier Fid* oldfid(int, char**);
1019a747e4fSDavid du Colombier int fidstat(Fid*, char**);
1029a747e4fSDavid du Colombier void freefid(Fid*);
1039a747e4fSDavid du Colombier
1049a747e4fSDavid du Colombier int userchange(User*, char**);
1059a747e4fSDavid du Colombier int userwalk(User*, char**, char*, Qid*, char**);
1069a747e4fSDavid du Colombier int useropen(Fid*, int, char**);
1079a747e4fSDavid du Colombier int usercreate(Fid*, char*, int, long, char**);
1089a747e4fSDavid du Colombier int userremove(Fid*, char**);
1099a747e4fSDavid du Colombier int userperm(User*, char*, int, int);
1109a747e4fSDavid du Colombier int useringroup(User*, User*);
1119a747e4fSDavid du Colombier
1129a747e4fSDavid du Colombier Qid stat2qid(struct stat*);
1139a747e4fSDavid du Colombier
1149a747e4fSDavid du Colombier void getfcallold(int, Fcall*, int);
1159a747e4fSDavid du Colombier void putfcallold(int, Fcall*);
1163e12c5d1SDavid du Colombier
1173e12c5d1SDavid du Colombier char Eauth[] = "authentication failed";
1183e12c5d1SDavid du Colombier char Ebadfid[] = "fid unknown or out of range";
1199a747e4fSDavid du Colombier char Ebadoffset[] = "bad offset in directory read";
1209a747e4fSDavid du Colombier char Ebadusefid[] = "bad use of fid";
1219a747e4fSDavid du Colombier char Edirchange[] = "wstat can't convert between files and directories";
1229a747e4fSDavid du Colombier char Eexist[] = "file or directory already exists";
1233e12c5d1SDavid du Colombier char Efidactive[] = "fid already in use";
1249a747e4fSDavid du Colombier char Enotdir[] = "not a directory";
1259a747e4fSDavid du Colombier char Enotingroup[] = "not a member of proposed group";
1269a747e4fSDavid du Colombier char Enotowner[] = "only owner can change group in wstat";
1279a747e4fSDavid du Colombier char Eperm[] = "permission denied";
1283e12c5d1SDavid du Colombier char Especial0[] = "already attached without access to special files";
1293e12c5d1SDavid du Colombier char Especial1[] = "already attached with access to special files";
1309a747e4fSDavid du Colombier char Especial[] = "no access to special file";
1313e12c5d1SDavid du Colombier char Etoolarge[] = "i/o count too large";
1329a747e4fSDavid du Colombier char Eunknowngroup[] = "unknown group";
1339a747e4fSDavid du Colombier char Eunknownuser[] = "unknown user";
1349a747e4fSDavid du Colombier char Ewstatbuffer[] = "bogus wstat buffer";
1359a747e4fSDavid du Colombier
1369a747e4fSDavid du Colombier ulong msize = IOHDRSZ+8192;
1379a747e4fSDavid du Colombier uchar* rxbuf;
1389a747e4fSDavid du Colombier uchar* txbuf;
1399a747e4fSDavid du Colombier void* databuf;
1409a747e4fSDavid du Colombier int connected;
1419a747e4fSDavid du Colombier int devallowed;
1429a747e4fSDavid du Colombier char* autharg;
1439a747e4fSDavid du Colombier char* defaultuser;
1449a747e4fSDavid du Colombier char hostname[256];
1459a747e4fSDavid du Colombier char remotehostname[256];
1469a747e4fSDavid du Colombier int chatty9p = 0;
1479a747e4fSDavid du Colombier int network = 1;
1489a747e4fSDavid du Colombier int old9p = -1;
1499a747e4fSDavid du Colombier int authed;
1509a747e4fSDavid du Colombier User* none;
1519a747e4fSDavid du Colombier
1529a747e4fSDavid du Colombier Auth *authmethods[] = { /* first is default */
1539a747e4fSDavid du Colombier &authrhosts,
15450a9bdd4SDavid du Colombier &authp9any,
1559a747e4fSDavid du Colombier &authnone,
1569a747e4fSDavid du Colombier };
1579a747e4fSDavid du Colombier
1589a747e4fSDavid du Colombier Auth *auth;
1593e12c5d1SDavid du Colombier
160dfda52d8SDavid du Colombier /*
161dfda52d8SDavid du Colombier * frogs: characters not valid in plan9
162dfda52d8SDavid du Colombier * filenames, keep this list in sync with
163dfda52d8SDavid du Colombier * /sys/src/9/port/chan.c:1656
164dfda52d8SDavid du Colombier */
165dfda52d8SDavid du Colombier char isfrog[256]={
166dfda52d8SDavid du Colombier /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
167dfda52d8SDavid du Colombier /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
168dfda52d8SDavid du Colombier /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
169dfda52d8SDavid du Colombier /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
170dfda52d8SDavid du Colombier ['/'] 1,
171dfda52d8SDavid du Colombier [0x7f] 1,
172dfda52d8SDavid du Colombier };
173dfda52d8SDavid du Colombier
1747dd7cddfSDavid du Colombier void
getfcallnew(int fd,Fcall * fc,int have)1759a747e4fSDavid du Colombier getfcallnew(int fd, Fcall *fc, int have)
1767dd7cddfSDavid du Colombier {
1779a747e4fSDavid du Colombier int len;
1789a747e4fSDavid du Colombier
1799a747e4fSDavid du Colombier if(have > BIT32SZ)
1809a747e4fSDavid du Colombier sysfatal("cannot happen");
1819a747e4fSDavid du Colombier
1829a747e4fSDavid du Colombier if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have)
1839a747e4fSDavid du Colombier sysfatal("couldn't read message");
1849a747e4fSDavid du Colombier
1859a747e4fSDavid du Colombier len = GBIT32(rxbuf);
1869a747e4fSDavid du Colombier if(len <= BIT32SZ)
1879a747e4fSDavid du Colombier sysfatal("bogus message");
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier len -= BIT32SZ;
1909a747e4fSDavid du Colombier if(readn(fd, rxbuf+BIT32SZ, len) != len)
1919a747e4fSDavid du Colombier sysfatal("short message");
1929a747e4fSDavid du Colombier
1939a747e4fSDavid du Colombier if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ)
1949a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]);
1959a747e4fSDavid du Colombier }
1969a747e4fSDavid du Colombier
1979a747e4fSDavid du Colombier void
getfcallold(int fd,Fcall * fc,int have)1989a747e4fSDavid du Colombier getfcallold(int fd, Fcall *fc, int have)
1999a747e4fSDavid du Colombier {
2009a747e4fSDavid du Colombier int len, n;
2019a747e4fSDavid du Colombier
2029a747e4fSDavid du Colombier if(have > 3)
2039a747e4fSDavid du Colombier sysfatal("cannot happen");
2049a747e4fSDavid du Colombier
2059a747e4fSDavid du Colombier if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have)
2069a747e4fSDavid du Colombier sysfatal("couldn't read message");
2079a747e4fSDavid du Colombier
2089a747e4fSDavid du Colombier len = oldhdrsize(rxbuf[0]);
2099a747e4fSDavid du Colombier if(len < 3)
2109a747e4fSDavid du Colombier sysfatal("bad message %d", rxbuf[0]);
2119a747e4fSDavid du Colombier if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3)
2129a747e4fSDavid du Colombier sysfatal("couldn't read message");
2139a747e4fSDavid du Colombier
2149a747e4fSDavid du Colombier n = iosize(rxbuf);
2159a747e4fSDavid du Colombier if(readn(fd, rxbuf+len, n) != n)
2169a747e4fSDavid du Colombier sysfatal("couldn't read message");
2179a747e4fSDavid du Colombier len += n;
2189a747e4fSDavid du Colombier
2199a747e4fSDavid du Colombier if(convM2Sold(rxbuf, len, fc) != len)
2209a747e4fSDavid du Colombier sysfatal("badly sized message type %d", rxbuf[0]);
2219a747e4fSDavid du Colombier }
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier void
putfcallnew(int wfd,Fcall * tx)2249a747e4fSDavid du Colombier putfcallnew(int wfd, Fcall *tx)
2259a747e4fSDavid du Colombier {
2269a747e4fSDavid du Colombier uint n;
2279a747e4fSDavid du Colombier
2289a747e4fSDavid du Colombier if((n = convS2M(tx, txbuf, msize)) == 0)
2299a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type);
2309a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n)
2319a747e4fSDavid du Colombier sysfatal("couldn't send message");
2329a747e4fSDavid du Colombier }
2339a747e4fSDavid du Colombier
2349a747e4fSDavid du Colombier void
putfcallold(int wfd,Fcall * tx)2359a747e4fSDavid du Colombier putfcallold(int wfd, Fcall *tx)
2369a747e4fSDavid du Colombier {
2379a747e4fSDavid du Colombier uint n;
2389a747e4fSDavid du Colombier
2399a747e4fSDavid du Colombier if((n = convS2Mold(tx, txbuf, msize)) == 0)
2409a747e4fSDavid du Colombier sysfatal("couldn't format message type %d", tx->type);
2419a747e4fSDavid du Colombier if(write(wfd, txbuf, n) != n)
2429a747e4fSDavid du Colombier sysfatal("couldn't send message");
2439a747e4fSDavid du Colombier }
2449a747e4fSDavid du Colombier
2459a747e4fSDavid du Colombier void
getfcall(int fd,Fcall * fc)2469a747e4fSDavid du Colombier getfcall(int fd, Fcall *fc)
2479a747e4fSDavid du Colombier {
2489a747e4fSDavid du Colombier if(old9p == 1){
2499a747e4fSDavid du Colombier getfcallold(fd, fc, 0);
2509a747e4fSDavid du Colombier return;
2519a747e4fSDavid du Colombier }
2529a747e4fSDavid du Colombier if(old9p == 0){
2539a747e4fSDavid du Colombier getfcallnew(fd, fc, 0);
2549a747e4fSDavid du Colombier return;
2559a747e4fSDavid du Colombier }
2569a747e4fSDavid du Colombier
2579a747e4fSDavid du Colombier /* auto-detect */
2589a747e4fSDavid du Colombier if(readn(fd, rxbuf, 3) != 3)
2599a747e4fSDavid du Colombier sysfatal("couldn't read message");
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier /* is it an old (9P1) message? */
2629a747e4fSDavid du Colombier if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){
2639a747e4fSDavid du Colombier old9p = 1;
2649a747e4fSDavid du Colombier getfcallold(fd, fc, 3);
2659a747e4fSDavid du Colombier return;
2669a747e4fSDavid du Colombier }
2679a747e4fSDavid du Colombier
2689a747e4fSDavid du Colombier getfcallnew(fd, fc, 3);
2699a747e4fSDavid du Colombier old9p = 0;
2709a747e4fSDavid du Colombier }
2719a747e4fSDavid du Colombier
2729a747e4fSDavid du Colombier void
seterror(Fcall * f,char * error)2739a747e4fSDavid du Colombier seterror(Fcall *f, char *error)
2749a747e4fSDavid du Colombier {
2759a747e4fSDavid du Colombier f->type = Rerror;
2769a747e4fSDavid du Colombier f->ename = error ? error : "programmer error";
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier
2793e12c5d1SDavid du Colombier int
isowner(User * u,Fid * f)2809a747e4fSDavid du Colombier isowner(User *u, Fid *f)
2813e12c5d1SDavid du Colombier {
2829a747e4fSDavid du Colombier return u->id == f->st.st_uid;
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier
2859df35464SDavid du Colombier
2869df35464SDavid du Colombier
2873e12c5d1SDavid du Colombier void
serve(int rfd,int wfd)2889a747e4fSDavid du Colombier serve(int rfd, int wfd)
2893e12c5d1SDavid du Colombier {
2909a747e4fSDavid du Colombier Fcall rx, tx;
2913e12c5d1SDavid du Colombier
2923e12c5d1SDavid du Colombier for(;;){
2939a747e4fSDavid du Colombier getfcall(rfd, &rx);
2943e12c5d1SDavid du Colombier
2959a747e4fSDavid du Colombier if(chatty9p)
2969a747e4fSDavid du Colombier fprint(2, "<- %F\n", &rx);
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier memset(&tx, 0, sizeof tx);
2999a747e4fSDavid du Colombier tx.type = rx.type+1;
3009a747e4fSDavid du Colombier tx.tag = rx.tag;
3019a747e4fSDavid du Colombier switch(rx.type){
3029a747e4fSDavid du Colombier case Tflush:
3033e12c5d1SDavid du Colombier break;
3049a747e4fSDavid du Colombier case Tversion:
3059a747e4fSDavid du Colombier rversion(&rx, &tx);
3069a747e4fSDavid du Colombier break;
3079a747e4fSDavid du Colombier case Tauth:
3089a747e4fSDavid du Colombier rauth(&rx, &tx);
3093e12c5d1SDavid du Colombier break;
3103e12c5d1SDavid du Colombier case Tattach:
3119a747e4fSDavid du Colombier rattach(&rx, &tx);
3123e12c5d1SDavid du Colombier break;
3133e12c5d1SDavid du Colombier case Twalk:
3149a747e4fSDavid du Colombier rwalk(&rx, &tx);
3153e12c5d1SDavid du Colombier break;
3163e12c5d1SDavid du Colombier case Tstat:
3179a747e4fSDavid du Colombier tx.stat = databuf;
3189a747e4fSDavid du Colombier rstat(&rx, &tx);
3193e12c5d1SDavid du Colombier break;
3203e12c5d1SDavid du Colombier case Twstat:
3219a747e4fSDavid du Colombier rwstat(&rx, &tx);
3223e12c5d1SDavid du Colombier break;
3233e12c5d1SDavid du Colombier case Topen:
3249a747e4fSDavid du Colombier ropen(&rx, &tx);
3253e12c5d1SDavid du Colombier break;
3263e12c5d1SDavid du Colombier case Tcreate:
3279a747e4fSDavid du Colombier rcreate(&rx, &tx);
3283e12c5d1SDavid du Colombier break;
3293e12c5d1SDavid du Colombier case Tread:
3309a747e4fSDavid du Colombier tx.data = databuf;
3319a747e4fSDavid du Colombier rread(&rx, &tx);
3323e12c5d1SDavid du Colombier break;
3333e12c5d1SDavid du Colombier case Twrite:
3349a747e4fSDavid du Colombier rwrite(&rx, &tx);
3353e12c5d1SDavid du Colombier break;
3363e12c5d1SDavid du Colombier case Tclunk:
3379a747e4fSDavid du Colombier rclunk(&rx, &tx);
3383e12c5d1SDavid du Colombier break;
3393e12c5d1SDavid du Colombier case Tremove:
3409a747e4fSDavid du Colombier rremove(&rx, &tx);
3413e12c5d1SDavid du Colombier break;
3423e12c5d1SDavid du Colombier default:
3439a747e4fSDavid du Colombier fprint(2, "unknown message %F\n", &rx);
3449a747e4fSDavid du Colombier seterror(&tx, "bad message");
3459a747e4fSDavid du Colombier break;
3463e12c5d1SDavid du Colombier }
3479a747e4fSDavid du Colombier
3489a747e4fSDavid du Colombier if(chatty9p)
3499a747e4fSDavid du Colombier fprint(2, "-> %F\n", &tx);
3509a747e4fSDavid du Colombier
3519a747e4fSDavid du Colombier (old9p ? putfcallold : putfcallnew)(wfd, &tx);
3529a747e4fSDavid du Colombier }
3533e12c5d1SDavid du Colombier }
3543e12c5d1SDavid du Colombier
3553e12c5d1SDavid du Colombier void
rversion(Fcall * rx,Fcall * tx)3569a747e4fSDavid du Colombier rversion(Fcall *rx, Fcall *tx)
3573e12c5d1SDavid du Colombier {
3589a747e4fSDavid du Colombier if(msize > rx->msize)
3599a747e4fSDavid du Colombier msize = rx->msize;
3609a747e4fSDavid du Colombier tx->msize = msize;
3619a747e4fSDavid du Colombier if(strncmp(rx->version, "9P", 2) != 0)
3629a747e4fSDavid du Colombier tx->version = "unknown";
3639a747e4fSDavid du Colombier else
3649a747e4fSDavid du Colombier tx->version = "9P2000";
3653e12c5d1SDavid du Colombier }
3663e12c5d1SDavid du Colombier
3673e12c5d1SDavid du Colombier void
rauth(Fcall * rx,Fcall * tx)3689a747e4fSDavid du Colombier rauth(Fcall *rx, Fcall *tx)
3693e12c5d1SDavid du Colombier {
3709a747e4fSDavid du Colombier char *e;
3713e12c5d1SDavid du Colombier
3729a747e4fSDavid du Colombier if((e = auth->auth(rx, tx)) != nil)
3739a747e4fSDavid du Colombier seterror(tx, e);
3743e12c5d1SDavid du Colombier }
3759a747e4fSDavid du Colombier
3769a747e4fSDavid du Colombier void
rattach(Fcall * rx,Fcall * tx)3779a747e4fSDavid du Colombier rattach(Fcall *rx, Fcall *tx)
3789a747e4fSDavid du Colombier {
3799a747e4fSDavid du Colombier char *e;
3809a747e4fSDavid du Colombier Fid *fid;
3819a747e4fSDavid du Colombier User *u;
3829a747e4fSDavid du Colombier
3839a747e4fSDavid du Colombier if(rx->aname == nil)
3849a747e4fSDavid du Colombier rx->aname = "";
3859a747e4fSDavid du Colombier
3869a747e4fSDavid du Colombier if(strcmp(rx->aname, "device") == 0){
3879a747e4fSDavid du Colombier if(connected && !devallowed){
3889a747e4fSDavid du Colombier seterror(tx, Especial0);
3899a747e4fSDavid du Colombier return;
3909a747e4fSDavid du Colombier }
3913e12c5d1SDavid du Colombier devallowed = 1;
3923e12c5d1SDavid du Colombier }else{
3939a747e4fSDavid du Colombier if(connected && devallowed){
3949a747e4fSDavid du Colombier seterror(tx, Especial1);
3959a747e4fSDavid du Colombier return;
3963e12c5d1SDavid du Colombier }
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier
3999a747e4fSDavid du Colombier if(strcmp(rx->uname, "none") == 0){
4009a747e4fSDavid du Colombier if(authed == 0){
4019a747e4fSDavid du Colombier seterror(tx, Eauth);
4029a747e4fSDavid du Colombier return;
4039a747e4fSDavid du Colombier }
404*ad6ca847SDavid du Colombier if (none != nil)
405*ad6ca847SDavid du Colombier rx->uname = none->name;
4069a747e4fSDavid du Colombier } else {
4079a747e4fSDavid du Colombier if((e = auth->attach(rx, tx)) != nil){
4089a747e4fSDavid du Colombier seterror(tx, e);
4099a747e4fSDavid du Colombier return;
4109a747e4fSDavid du Colombier }
4119a747e4fSDavid du Colombier authed++;
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier
4149a747e4fSDavid du Colombier if((fid = newfid(rx->fid, &e)) == nil){
4159a747e4fSDavid du Colombier seterror(tx, e);
4169a747e4fSDavid du Colombier return;
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier fid->path = estrdup("/");
4199a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
4209a747e4fSDavid du Colombier seterror(tx, e);
4219a747e4fSDavid du Colombier freefid(fid);
4229a747e4fSDavid du Colombier return;
4239a747e4fSDavid du Colombier }
4249a747e4fSDavid du Colombier
4259a747e4fSDavid du Colombier if(defaultuser)
4269a747e4fSDavid du Colombier rx->uname = defaultuser;
4279a747e4fSDavid du Colombier
428fa1160edSDavid du Colombier if((u = uname2user(rx->uname)) == nil
429fa1160edSDavid du Colombier || (!defaultuser && u->id == 0)){
4309a747e4fSDavid du Colombier /* we don't know anyone named root... */
4319a747e4fSDavid du Colombier seterror(tx, Eunknownuser);
4329a747e4fSDavid du Colombier freefid(fid);
4339a747e4fSDavid du Colombier return;
4349a747e4fSDavid du Colombier }
4359a747e4fSDavid du Colombier
4369a747e4fSDavid du Colombier fid->u = u;
4379a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st);
4389a747e4fSDavid du Colombier return;
4393e12c5d1SDavid du Colombier }
4403e12c5d1SDavid du Colombier
4413e12c5d1SDavid du Colombier void
rwalk(Fcall * rx,Fcall * tx)4429a747e4fSDavid du Colombier rwalk(Fcall *rx, Fcall *tx)
4433e12c5d1SDavid du Colombier {
4449a747e4fSDavid du Colombier int i;
4459a747e4fSDavid du Colombier char *path, *e;
4469a747e4fSDavid du Colombier Fid *fid, *nfid;
4473e12c5d1SDavid du Colombier
4489a747e4fSDavid du Colombier e = nil;
4499a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
4509a747e4fSDavid du Colombier seterror(tx, e);
4519a747e4fSDavid du Colombier return;
4523e12c5d1SDavid du Colombier }
4533e12c5d1SDavid du Colombier
4549a747e4fSDavid du Colombier if(fid->omode != -1){
4559a747e4fSDavid du Colombier seterror(tx, Ebadusefid);
4569a747e4fSDavid du Colombier return;
4573e12c5d1SDavid du Colombier }
4583e12c5d1SDavid du Colombier
4599a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
4609a747e4fSDavid du Colombier seterror(tx, e);
4619a747e4fSDavid du Colombier return;
4629a747e4fSDavid du Colombier }
4633e12c5d1SDavid du Colombier
4649a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode) && rx->nwname){
4659a747e4fSDavid du Colombier seterror(tx, Enotdir);
4669a747e4fSDavid du Colombier return;
4679a747e4fSDavid du Colombier }
4689a747e4fSDavid du Colombier
4699a747e4fSDavid du Colombier nfid = nil;
4709a747e4fSDavid du Colombier if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){
4719a747e4fSDavid du Colombier seterror(tx, e);
4729a747e4fSDavid du Colombier return;
4739a747e4fSDavid du Colombier }
4749a747e4fSDavid du Colombier
4759a747e4fSDavid du Colombier path = estrdup(fid->path);
4769a747e4fSDavid du Colombier e = nil;
4779a747e4fSDavid du Colombier for(i=0; i<rx->nwname; i++)
4789a747e4fSDavid du Colombier if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0)
4793e12c5d1SDavid du Colombier break;
4803e12c5d1SDavid du Colombier
4819a747e4fSDavid du Colombier if(i == rx->nwname){ /* successful clone or walk */
4829a747e4fSDavid du Colombier tx->nwqid = i;
4839a747e4fSDavid du Colombier if(nfid){
4849a747e4fSDavid du Colombier nfid->path = path;
4859a747e4fSDavid du Colombier nfid->u = fid->u;
4863e12c5d1SDavid du Colombier }else{
4879a747e4fSDavid du Colombier free(fid->path);
4889a747e4fSDavid du Colombier fid->path = path;
4893e12c5d1SDavid du Colombier }
4909a747e4fSDavid du Colombier }else{
4919a747e4fSDavid du Colombier if(i > 0) /* partial walk? */
4929a747e4fSDavid du Colombier tx->nwqid = i;
4939a747e4fSDavid du Colombier else
4949a747e4fSDavid du Colombier seterror(tx, e);
4959a747e4fSDavid du Colombier
4969a747e4fSDavid du Colombier if(nfid) /* clone implicit new fid */
4979a747e4fSDavid du Colombier freefid(nfid);
4989a747e4fSDavid du Colombier free(path);
4993e12c5d1SDavid du Colombier }
5009a747e4fSDavid du Colombier return;
5013e12c5d1SDavid du Colombier }
5023e12c5d1SDavid du Colombier
5033e12c5d1SDavid du Colombier void
ropen(Fcall * rx,Fcall * tx)5049a747e4fSDavid du Colombier ropen(Fcall *rx, Fcall *tx)
5053e12c5d1SDavid du Colombier {
5069a747e4fSDavid du Colombier char *e;
5079a747e4fSDavid du Colombier Fid *fid;
5083e12c5d1SDavid du Colombier
5099a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
5109a747e4fSDavid du Colombier seterror(tx, e);
5119a747e4fSDavid du Colombier return;
5123e12c5d1SDavid du Colombier }
5139a747e4fSDavid du Colombier
5149a747e4fSDavid du Colombier if(fid->omode != -1){
5159a747e4fSDavid du Colombier seterror(tx, Ebadusefid);
5169a747e4fSDavid du Colombier return;
5173e12c5d1SDavid du Colombier }
5189a747e4fSDavid du Colombier
5199a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
5209a747e4fSDavid du Colombier seterror(tx, e);
5219a747e4fSDavid du Colombier return;
5223e12c5d1SDavid du Colombier }
5239a747e4fSDavid du Colombier
5249a747e4fSDavid du Colombier if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){
5259a747e4fSDavid du Colombier seterror(tx, Especial);
5269a747e4fSDavid du Colombier return;
5273e12c5d1SDavid du Colombier }
5289a747e4fSDavid du Colombier
5299a747e4fSDavid du Colombier if(useropen(fid, rx->mode, &e) < 0){
5309a747e4fSDavid du Colombier seterror(tx, e);
5319a747e4fSDavid du Colombier return;
5323e12c5d1SDavid du Colombier }
5339a747e4fSDavid du Colombier
5349a747e4fSDavid du Colombier tx->iounit = 0;
5359a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st);
5363e12c5d1SDavid du Colombier }
5373e12c5d1SDavid du Colombier
5383e12c5d1SDavid du Colombier void
rcreate(Fcall * rx,Fcall * tx)5399a747e4fSDavid du Colombier rcreate(Fcall *rx, Fcall *tx)
5403e12c5d1SDavid du Colombier {
5419a747e4fSDavid du Colombier char *e;
5429a747e4fSDavid du Colombier Fid *fid;
5439a747e4fSDavid du Colombier
5449a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
5459a747e4fSDavid du Colombier seterror(tx, e);
5469a747e4fSDavid du Colombier return;
5479a747e4fSDavid du Colombier }
5489a747e4fSDavid du Colombier
5499a747e4fSDavid du Colombier if(fid->omode != -1){
5509a747e4fSDavid du Colombier seterror(tx, Ebadusefid);
5519a747e4fSDavid du Colombier return;
5529a747e4fSDavid du Colombier }
5539a747e4fSDavid du Colombier
5549a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
5559a747e4fSDavid du Colombier seterror(tx, e);
5569a747e4fSDavid du Colombier return;
5579a747e4fSDavid du Colombier }
5589a747e4fSDavid du Colombier
5599a747e4fSDavid du Colombier if(!S_ISDIR(fid->st.st_mode)){
5609a747e4fSDavid du Colombier seterror(tx, Enotdir);
5619a747e4fSDavid du Colombier return;
5629a747e4fSDavid du Colombier }
5639a747e4fSDavid du Colombier
5649a747e4fSDavid du Colombier if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){
5659a747e4fSDavid du Colombier seterror(tx, e);
5669a747e4fSDavid du Colombier return;
5679a747e4fSDavid du Colombier }
5689a747e4fSDavid du Colombier
5699a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
5709a747e4fSDavid du Colombier seterror(tx, e);
5719a747e4fSDavid du Colombier return;
5729a747e4fSDavid du Colombier }
5739a747e4fSDavid du Colombier
5749a747e4fSDavid du Colombier tx->iounit = 0;
5759a747e4fSDavid du Colombier tx->qid = stat2qid(&fid->st);
5769a747e4fSDavid du Colombier }
5779a747e4fSDavid du Colombier
5789a747e4fSDavid du Colombier uchar
modebyte(struct stat * st)5799a747e4fSDavid du Colombier modebyte(struct stat *st)
5809a747e4fSDavid du Colombier {
5819a747e4fSDavid du Colombier uchar b;
5829a747e4fSDavid du Colombier
5839a747e4fSDavid du Colombier b = 0;
5849a747e4fSDavid du Colombier
5859a747e4fSDavid du Colombier if(S_ISDIR(st->st_mode))
5869a747e4fSDavid du Colombier b |= QTDIR;
5879a747e4fSDavid du Colombier
5889a747e4fSDavid du Colombier /* no way to test append-only */
5899a747e4fSDavid du Colombier /* no real way to test exclusive use, but mark devices as such */
5909a747e4fSDavid du Colombier if(S_ISSPECIAL(st->st_mode))
5919a747e4fSDavid du Colombier b |= QTEXCL;
5929a747e4fSDavid du Colombier
5939a747e4fSDavid du Colombier return b;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier
5969a747e4fSDavid du Colombier ulong
plan9mode(struct stat * st)5979a747e4fSDavid du Colombier plan9mode(struct stat *st)
5989a747e4fSDavid du Colombier {
5999a747e4fSDavid du Colombier return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777);
6009a747e4fSDavid du Colombier }
6019a747e4fSDavid du Colombier
6029a747e4fSDavid du Colombier /*
6039a747e4fSDavid du Colombier * this is for chmod, so don't worry about S_IFDIR
6049a747e4fSDavid du Colombier */
6059a747e4fSDavid du Colombier mode_t
unixmode(Dir * d)6069a747e4fSDavid du Colombier unixmode(Dir *d)
6079a747e4fSDavid du Colombier {
6089a747e4fSDavid du Colombier return (mode_t)(d->mode&0777);
6099a747e4fSDavid du Colombier }
6109a747e4fSDavid du Colombier
6119a747e4fSDavid du Colombier Qid
stat2qid(struct stat * st)6129a747e4fSDavid du Colombier stat2qid(struct stat *st)
6139a747e4fSDavid du Colombier {
6149a747e4fSDavid du Colombier uchar *p, *ep, *q;
6159a747e4fSDavid du Colombier Qid qid;
6169a747e4fSDavid du Colombier
6179a747e4fSDavid du Colombier /*
6189a747e4fSDavid du Colombier * For now, ignore the device number.
6199a747e4fSDavid du Colombier */
6209a747e4fSDavid du Colombier qid.path = 0;
6219a747e4fSDavid du Colombier p = (uchar*)&qid.path;
6229a747e4fSDavid du Colombier ep = p+sizeof(qid.path);
6239a747e4fSDavid du Colombier q = p+sizeof(ino_t);
6249a747e4fSDavid du Colombier if(q > ep){
6259a747e4fSDavid du Colombier fprint(2, "warning: inode number too big\n");
6269a747e4fSDavid du Colombier q = ep;
6279a747e4fSDavid du Colombier }
6289a747e4fSDavid du Colombier memmove(p, &st->st_ino, q-p);
6299a747e4fSDavid du Colombier q = q+sizeof(dev_t);
6309a747e4fSDavid du Colombier if(q > ep){
631dfda52d8SDavid du Colombier /*
632dfda52d8SDavid du Colombier * fprint(2, "warning: inode number + device number too big %d+%d\n",
633dfda52d8SDavid du Colombier * sizeof(ino_t), sizeof(dev_t));
634dfda52d8SDavid du Colombier */
6359a747e4fSDavid du Colombier q = ep - sizeof(dev_t);
6369a747e4fSDavid du Colombier if(q < p)
6379a747e4fSDavid du Colombier fprint(2, "warning: device number too big by itself\n");
6389a747e4fSDavid du Colombier else
6399a747e4fSDavid du Colombier *(dev_t*)q ^= st->st_dev;
6409a747e4fSDavid du Colombier }
6419a747e4fSDavid du Colombier
6429a747e4fSDavid du Colombier qid.vers = st->st_mtime ^ (st->st_size << 8);
6439a747e4fSDavid du Colombier qid.type = modebyte(st);
6449a747e4fSDavid du Colombier return qid;
6459a747e4fSDavid du Colombier }
6469a747e4fSDavid du Colombier
647dfda52d8SDavid du Colombier char *
enfrog(char * src)648dfda52d8SDavid du Colombier enfrog(char *src)
649dfda52d8SDavid du Colombier {
650dfda52d8SDavid du Colombier char *d, *dst;
651dfda52d8SDavid du Colombier uchar *s;
652dfda52d8SDavid du Colombier
653dfda52d8SDavid du Colombier d = dst = emalloc(strlen(src)*3 + 1);
654dfda52d8SDavid du Colombier for (s = (uchar *)src; *s; s++)
655dfda52d8SDavid du Colombier if(isfrog[*s] || *s == '\\')
656dfda52d8SDavid du Colombier d += sprintf(d, "\\%02x", *s);
657dfda52d8SDavid du Colombier else
658dfda52d8SDavid du Colombier *d++ = *s;
659dfda52d8SDavid du Colombier *d = 0;
660dfda52d8SDavid du Colombier return dst;
661dfda52d8SDavid du Colombier }
662dfda52d8SDavid du Colombier
663dfda52d8SDavid du Colombier char *
defrog(char * s)664dfda52d8SDavid du Colombier defrog(char *s)
665dfda52d8SDavid du Colombier {
666dfda52d8SDavid du Colombier char *d, *dst, buf[3];
667dfda52d8SDavid du Colombier
668dfda52d8SDavid du Colombier d = dst = emalloc(strlen(s) + 1);
669dfda52d8SDavid du Colombier for(; *s; s++)
670dfda52d8SDavid du Colombier if(*s == '\\' && strlen(s) >= 3){
671dfda52d8SDavid du Colombier buf[0] = *++s; /* skip \ */
672dfda52d8SDavid du Colombier buf[1] = *++s;
673dfda52d8SDavid du Colombier buf[2] = 0;
674dfda52d8SDavid du Colombier *d++ = strtoul(buf, NULL, 16);
675dfda52d8SDavid du Colombier } else
676dfda52d8SDavid du Colombier *d++ = *s;
677dfda52d8SDavid du Colombier *d = 0;
678dfda52d8SDavid du Colombier return dst;
679dfda52d8SDavid du Colombier }
680dfda52d8SDavid du Colombier
6819a747e4fSDavid du Colombier void
stat2dir(char * path,struct stat * st,Dir * d)6829a747e4fSDavid du Colombier stat2dir(char *path, struct stat *st, Dir *d)
6839a747e4fSDavid du Colombier {
6849a747e4fSDavid du Colombier User *u;
685dfda52d8SDavid du Colombier char *q, *p, *npath;
6869a747e4fSDavid du Colombier
6879a747e4fSDavid du Colombier memset(d, 0, sizeof(*d));
6889a747e4fSDavid du Colombier d->qid = stat2qid(st);
6899a747e4fSDavid du Colombier d->mode = plan9mode(st);
6909a747e4fSDavid du Colombier d->atime = st->st_atime;
6919a747e4fSDavid du Colombier d->mtime = st->st_mtime;
6929a747e4fSDavid du Colombier d->length = st->st_size;
6939a747e4fSDavid du Colombier
6949a747e4fSDavid du Colombier d->uid = (u = uid2user(st->st_uid)) ? u->name : "???";
6959a747e4fSDavid du Colombier d->gid = (u = gid2user(st->st_gid)) ? u->name : "???";
6969a747e4fSDavid du Colombier d->muid = "";
6979a747e4fSDavid du Colombier
6989a747e4fSDavid du Colombier if((q = strrchr(path, '/')) != nil)
699dfda52d8SDavid du Colombier d->name = enfrog(q+1);
7009a747e4fSDavid du Colombier else
701dfda52d8SDavid du Colombier d->name = enfrog(path);
7029a747e4fSDavid du Colombier }
7039a747e4fSDavid du Colombier
7049a747e4fSDavid du Colombier void
rread(Fcall * rx,Fcall * tx)7059a747e4fSDavid du Colombier rread(Fcall *rx, Fcall *tx)
7069a747e4fSDavid du Colombier {
7079a747e4fSDavid du Colombier char *e, *path;
7089a747e4fSDavid du Colombier uchar *p, *ep;
7099a747e4fSDavid du Colombier int n;
7109a747e4fSDavid du Colombier Fid *fid;
7113e12c5d1SDavid du Colombier Dir d;
7129a747e4fSDavid du Colombier struct stat st;
7133e12c5d1SDavid du Colombier
7149a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){
7159a747e4fSDavid du Colombier seterror(tx, Etoolarge);
7169a747e4fSDavid du Colombier return;
7173e12c5d1SDavid du Colombier }
7189a747e4fSDavid du Colombier
71950a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){
72050a9bdd4SDavid du Colombier seterror(tx, e);
72150a9bdd4SDavid du Colombier return;
72250a9bdd4SDavid du Colombier }
72350a9bdd4SDavid du Colombier
72450a9bdd4SDavid du Colombier if (fid->auth) {
72550a9bdd4SDavid du Colombier char *e;
72650a9bdd4SDavid du Colombier e = auth->read(rx, tx);
72750a9bdd4SDavid du Colombier if (e)
7289a747e4fSDavid du Colombier seterror(tx, e);
7299a747e4fSDavid du Colombier return;
7303e12c5d1SDavid du Colombier }
7319a747e4fSDavid du Colombier
7329a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OWRITE){
7339a747e4fSDavid du Colombier seterror(tx, Ebadusefid);
7349a747e4fSDavid du Colombier return;
7359a747e4fSDavid du Colombier }
7369a747e4fSDavid du Colombier
7379a747e4fSDavid du Colombier if(fid->dir){
7389a747e4fSDavid du Colombier if(rx->offset != fid->diroffset){
7399a747e4fSDavid du Colombier if(rx->offset != 0){
7409a747e4fSDavid du Colombier seterror(tx, Ebadoffset);
7419a747e4fSDavid du Colombier return;
7429a747e4fSDavid du Colombier }
7439a747e4fSDavid du Colombier rewinddir(fid->dir);
7449a747e4fSDavid du Colombier fid->diroffset = 0;
745bd8a67bbSDavid du Colombier fid->direof = 0;
746bd8a67bbSDavid du Colombier }
747bd8a67bbSDavid du Colombier if(fid->direof){
748bd8a67bbSDavid du Colombier tx->count = 0;
749bd8a67bbSDavid du Colombier return;
7509a747e4fSDavid du Colombier }
7519a747e4fSDavid du Colombier
7529a747e4fSDavid du Colombier p = (uchar*)tx->data;
7539a747e4fSDavid du Colombier ep = (uchar*)tx->data+rx->count;
7549a747e4fSDavid du Colombier for(;;){
7559a747e4fSDavid du Colombier if(p+BIT16SZ >= ep)
7563e12c5d1SDavid du Colombier break;
7579a747e4fSDavid du Colombier if(fid->dirent == nil) /* one entry cache for when convD2M fails */
758bd8a67bbSDavid du Colombier if((fid->dirent = readdir(fid->dir)) == nil){
759bd8a67bbSDavid du Colombier fid->direof = 1;
7609a747e4fSDavid du Colombier break;
761bd8a67bbSDavid du Colombier }
7629a747e4fSDavid du Colombier if(strcmp(fid->dirent->d_name, ".") == 0
7639a747e4fSDavid du Colombier || strcmp(fid->dirent->d_name, "..") == 0){
7649a747e4fSDavid du Colombier fid->dirent = nil;
7653e12c5d1SDavid du Colombier continue;
7669a747e4fSDavid du Colombier }
767dfda52d8SDavid du Colombier path = estrpath(fid->path, fid->dirent->d_name, 0);
7689a747e4fSDavid du Colombier memset(&st, 0, sizeof st);
7699a747e4fSDavid du Colombier if(stat(path, &st) < 0){
7709a747e4fSDavid du Colombier fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno));
7719a747e4fSDavid du Colombier fid->dirent = nil;
7729a747e4fSDavid du Colombier free(path);
7733e12c5d1SDavid du Colombier continue;
7743e12c5d1SDavid du Colombier }
7753e12c5d1SDavid du Colombier free(path);
7769a747e4fSDavid du Colombier stat2dir(fid->dirent->d_name, &st, &d);
7779a747e4fSDavid du Colombier if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ)
7789a747e4fSDavid du Colombier break;
7799a747e4fSDavid du Colombier p += n;
7809a747e4fSDavid du Colombier fid->dirent = nil;
7813e12c5d1SDavid du Colombier }
7829a747e4fSDavid du Colombier tx->count = p - (uchar*)tx->data;
7839a747e4fSDavid du Colombier fid->diroffset += tx->count;
7843e12c5d1SDavid du Colombier }else{
7859a747e4fSDavid du Colombier if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){
7869a747e4fSDavid du Colombier seterror(tx, strerror(errno));
7879a747e4fSDavid du Colombier return;
788219b2ee8SDavid du Colombier }
7899a747e4fSDavid du Colombier tx->count = n;
7903e12c5d1SDavid du Colombier }
7913e12c5d1SDavid du Colombier }
7923e12c5d1SDavid du Colombier
7933e12c5d1SDavid du Colombier void
rwrite(Fcall * rx,Fcall * tx)7949a747e4fSDavid du Colombier rwrite(Fcall *rx, Fcall *tx)
7953e12c5d1SDavid du Colombier {
7969a747e4fSDavid du Colombier char *e;
7979a747e4fSDavid du Colombier Fid *fid;
7983e12c5d1SDavid du Colombier int n;
7993e12c5d1SDavid du Colombier
8009a747e4fSDavid du Colombier if(rx->count > msize-IOHDRSZ){
8019a747e4fSDavid du Colombier seterror(tx, Etoolarge);
8027dd7cddfSDavid du Colombier return;
8037dd7cddfSDavid du Colombier }
8049a747e4fSDavid du Colombier
80550a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){
80650a9bdd4SDavid du Colombier seterror(tx, e);
80750a9bdd4SDavid du Colombier return;
80850a9bdd4SDavid du Colombier }
80950a9bdd4SDavid du Colombier
81050a9bdd4SDavid du Colombier if (fid->auth) {
81150a9bdd4SDavid du Colombier char *e;
81250a9bdd4SDavid du Colombier e = auth->write(rx, tx);
81350a9bdd4SDavid du Colombier if (e)
8149a747e4fSDavid du Colombier seterror(tx, e);
8159a747e4fSDavid du Colombier return;
8163e12c5d1SDavid du Colombier }
8179a747e4fSDavid du Colombier
8189a747e4fSDavid du Colombier if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){
8199a747e4fSDavid du Colombier seterror(tx, Ebadusefid);
8209a747e4fSDavid du Colombier return;
8219a747e4fSDavid du Colombier }
8229a747e4fSDavid du Colombier
8239a747e4fSDavid du Colombier if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){
8249a747e4fSDavid du Colombier seterror(tx, strerror(errno));
8259a747e4fSDavid du Colombier return;
8269a747e4fSDavid du Colombier }
8279a747e4fSDavid du Colombier tx->count = n;
8283e12c5d1SDavid du Colombier }
8293e12c5d1SDavid du Colombier
8303e12c5d1SDavid du Colombier void
rclunk(Fcall * rx,Fcall * tx)8319a747e4fSDavid du Colombier rclunk(Fcall *rx, Fcall *tx)
8323e12c5d1SDavid du Colombier {
8339a747e4fSDavid du Colombier char *e;
8349a747e4fSDavid du Colombier Fid *fid;
8353e12c5d1SDavid du Colombier
83650a9bdd4SDavid du Colombier if((fid = oldfidex(rx->fid, -1, &e)) == nil){
8379a747e4fSDavid du Colombier seterror(tx, e);
8389a747e4fSDavid du Colombier return;
8399a747e4fSDavid du Colombier }
84050a9bdd4SDavid du Colombier if (fid->auth) {
84150a9bdd4SDavid du Colombier if (auth->clunk) {
84250a9bdd4SDavid du Colombier e = (*auth->clunk)(rx, tx);
84350a9bdd4SDavid du Colombier if (e) {
84450a9bdd4SDavid du Colombier seterror(tx, e);
84550a9bdd4SDavid du Colombier return;
84650a9bdd4SDavid du Colombier }
84750a9bdd4SDavid du Colombier }
84850a9bdd4SDavid du Colombier }
84950a9bdd4SDavid du Colombier else if(fid->omode != -1 && fid->omode&ORCLOSE)
8509a747e4fSDavid du Colombier remove(fid->path);
8519a747e4fSDavid du Colombier freefid(fid);
8523e12c5d1SDavid du Colombier }
853219b2ee8SDavid du Colombier
8549a747e4fSDavid du Colombier void
rremove(Fcall * rx,Fcall * tx)8559a747e4fSDavid du Colombier rremove(Fcall *rx, Fcall *tx)
8563e12c5d1SDavid du Colombier {
8579a747e4fSDavid du Colombier char *e;
8589a747e4fSDavid du Colombier Fid *fid;
8593e12c5d1SDavid du Colombier
8609a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
8619a747e4fSDavid du Colombier seterror(tx, e);
8629a747e4fSDavid du Colombier return;
8633e12c5d1SDavid du Colombier }
8649a747e4fSDavid du Colombier if(userremove(fid, &e) < 0)
8659a747e4fSDavid du Colombier seterror(tx, e);
8669a747e4fSDavid du Colombier freefid(fid);
8679a747e4fSDavid du Colombier }
8689a747e4fSDavid du Colombier
8699a747e4fSDavid du Colombier void
rstat(Fcall * rx,Fcall * tx)8709a747e4fSDavid du Colombier rstat(Fcall *rx, Fcall *tx)
8719a747e4fSDavid du Colombier {
8729a747e4fSDavid du Colombier char *e;
8739a747e4fSDavid du Colombier Fid *fid;
8749a747e4fSDavid du Colombier Dir d;
8759a747e4fSDavid du Colombier
8769a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
8779a747e4fSDavid du Colombier seterror(tx, e);
8789a747e4fSDavid du Colombier return;
8799a747e4fSDavid du Colombier }
8809a747e4fSDavid du Colombier
8819a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
8829a747e4fSDavid du Colombier seterror(tx, e);
8839a747e4fSDavid du Colombier return;
8849a747e4fSDavid du Colombier }
8859a747e4fSDavid du Colombier
8869a747e4fSDavid du Colombier stat2dir(fid->path, &fid->st, &d);
8879a747e4fSDavid du Colombier if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ)
8889a747e4fSDavid du Colombier seterror(tx, "convD2M fails");
8899a747e4fSDavid du Colombier }
8909a747e4fSDavid du Colombier
8919a747e4fSDavid du Colombier void
rwstat(Fcall * rx,Fcall * tx)8929a747e4fSDavid du Colombier rwstat(Fcall *rx, Fcall *tx)
8939a747e4fSDavid du Colombier {
8949a747e4fSDavid du Colombier char *e;
8959a747e4fSDavid du Colombier char *p, *old, *new, *dir;
8969a747e4fSDavid du Colombier gid_t gid;
8979a747e4fSDavid du Colombier Dir d;
8989a747e4fSDavid du Colombier Fid *fid;
8999a747e4fSDavid du Colombier
9009a747e4fSDavid du Colombier if((fid = oldfid(rx->fid, &e)) == nil){
9019a747e4fSDavid du Colombier seterror(tx, e);
9029a747e4fSDavid du Colombier return;
9039a747e4fSDavid du Colombier }
9049a747e4fSDavid du Colombier
9059a747e4fSDavid du Colombier /*
9069a747e4fSDavid du Colombier * wstat is supposed to be atomic.
9079a747e4fSDavid du Colombier * we check all the things we can before trying anything.
9089a747e4fSDavid du Colombier * still, if we are told to truncate a file and rename it and only
9099a747e4fSDavid du Colombier * one works, we're screwed. in such cases we leave things
9109a747e4fSDavid du Colombier * half broken and return an error. it's hardly perfect.
9119a747e4fSDavid du Colombier */
9129a747e4fSDavid du Colombier if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){
9139a747e4fSDavid du Colombier seterror(tx, Ewstatbuffer);
9149a747e4fSDavid du Colombier return;
9159a747e4fSDavid du Colombier }
9169a747e4fSDavid du Colombier
9179a747e4fSDavid du Colombier if(fidstat(fid, &e) < 0){
9189a747e4fSDavid du Colombier seterror(tx, e);
9199a747e4fSDavid du Colombier return;
9209a747e4fSDavid du Colombier }
9219a747e4fSDavid du Colombier
9229a747e4fSDavid du Colombier /*
9239a747e4fSDavid du Colombier * The casting is necessary because d.mode is ulong and might,
9249a747e4fSDavid du Colombier * on some systems, be 64 bits. We only want to compare the
9259a747e4fSDavid du Colombier * bottom 32 bits, since that's all that gets sent in the protocol.
9269a747e4fSDavid du Colombier *
9279a747e4fSDavid du Colombier * Same situation for d.mtime and d.length (although that last check
9289a747e4fSDavid du Colombier * is admittedly superfluous, given the current lack of 128-bit machines).
9299a747e4fSDavid du Colombier */
9309a747e4fSDavid du Colombier gid = (gid_t)-1;
9319a747e4fSDavid du Colombier if(d.gid[0] != '\0'){
9329a747e4fSDavid du Colombier User *g;
9339a747e4fSDavid du Colombier
9349a747e4fSDavid du Colombier g = gname2user(d.gid);
9359a747e4fSDavid du Colombier if(g == nil){
9369a747e4fSDavid du Colombier seterror(tx, Eunknowngroup);
9379a747e4fSDavid du Colombier return;
9389a747e4fSDavid du Colombier }
9399a747e4fSDavid du Colombier gid = (gid_t)g->id;
9409a747e4fSDavid du Colombier
9419a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(gid), &e) < 0){
9429a747e4fSDavid du Colombier seterror(tx, e);
9439a747e4fSDavid du Colombier return;
9449a747e4fSDavid du Colombier }
9459a747e4fSDavid du Colombier }
9469a747e4fSDavid du Colombier
9479a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){
9489a747e4fSDavid du Colombier seterror(tx, Edirchange);
9499a747e4fSDavid du Colombier return;
9509a747e4fSDavid du Colombier }
9519a747e4fSDavid du Colombier
9529a747e4fSDavid du Colombier if(strcmp(fid->path, "/") == 0){
9539a747e4fSDavid du Colombier seterror(tx, "no wstat of root");
9549a747e4fSDavid du Colombier return;
9559a747e4fSDavid du Colombier }
9569a747e4fSDavid du Colombier
9579a747e4fSDavid du Colombier /*
9589a747e4fSDavid du Colombier * try things in increasing order of harm to the file.
9599a747e4fSDavid du Colombier * mtime should come after truncate so that if you
9609a747e4fSDavid du Colombier * do both the mtime actually takes effect, but i'd rather
9619a747e4fSDavid du Colombier * leave truncate until last.
9629a747e4fSDavid du Colombier * (see above comment about atomicity).
9639a747e4fSDavid du Colombier */
9649a747e4fSDavid du Colombier if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){
9659a747e4fSDavid du Colombier if(chatty9p)
9669a747e4fSDavid du Colombier fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d));
9679a747e4fSDavid du Colombier seterror(tx, strerror(errno));
9689a747e4fSDavid du Colombier return;
9699a747e4fSDavid du Colombier }
9709a747e4fSDavid du Colombier
9719a747e4fSDavid du Colombier if((u32int)d.mtime != (u32int)~0){
9729a747e4fSDavid du Colombier struct utimbuf t;
9739a747e4fSDavid du Colombier
9749a747e4fSDavid du Colombier t.actime = 0;
9759a747e4fSDavid du Colombier t.modtime = d.mtime;
9769a747e4fSDavid du Colombier if(utime(fid->path, &t) < 0){
9779a747e4fSDavid du Colombier if(chatty9p)
9789a747e4fSDavid du Colombier fprint(2, "utime(%s) failed\n", fid->path);
9799a747e4fSDavid du Colombier seterror(tx, strerror(errno));
9809a747e4fSDavid du Colombier return;
9819a747e4fSDavid du Colombier }
9829a747e4fSDavid du Colombier }
9839a747e4fSDavid du Colombier
9849a747e4fSDavid du Colombier if(gid != (gid_t)-1 && gid != fid->st.st_gid){
9859a747e4fSDavid du Colombier if(chown(fid->path, (uid_t)-1, gid) < 0){
9869a747e4fSDavid du Colombier if(chatty9p)
9879a747e4fSDavid du Colombier fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid);
9889a747e4fSDavid du Colombier seterror(tx, strerror(errno));
9899a747e4fSDavid du Colombier return;
9909a747e4fSDavid du Colombier }
9919a747e4fSDavid du Colombier }
9929a747e4fSDavid du Colombier
9939a747e4fSDavid du Colombier if(d.name[0]){
9949a747e4fSDavid du Colombier old = fid->path;
9959a747e4fSDavid du Colombier dir = estrdup(fid->path);
9969a747e4fSDavid du Colombier if((p = strrchr(dir, '/')) > dir)
9979a747e4fSDavid du Colombier *p = '\0';
9983e12c5d1SDavid du Colombier else{
9999a747e4fSDavid du Colombier seterror(tx, "whoops: can't happen in u9fs");
10009a747e4fSDavid du Colombier return;
10013e12c5d1SDavid du Colombier }
1002dfda52d8SDavid du Colombier new = estrpath(dir, d.name, 1);
10039a747e4fSDavid du Colombier if(strcmp(old, new) != 0 && rename(old, new) < 0){
10049a747e4fSDavid du Colombier if(chatty9p)
10059a747e4fSDavid du Colombier fprint(2, "rename(%s, %s) failed\n", old, new);
10069a747e4fSDavid du Colombier seterror(tx, strerror(errno));
10079a747e4fSDavid du Colombier free(new);
10089a747e4fSDavid du Colombier free(dir);
10099a747e4fSDavid du Colombier return;
10109a747e4fSDavid du Colombier }
10119a747e4fSDavid du Colombier fid->path = new;
10129a747e4fSDavid du Colombier free(old);
10139a747e4fSDavid du Colombier free(dir);
10149a747e4fSDavid du Colombier }
10159a747e4fSDavid du Colombier
10169a747e4fSDavid du Colombier if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){
10179a747e4fSDavid du Colombier fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length);
10189a747e4fSDavid du Colombier seterror(tx, strerror(errno));
10199a747e4fSDavid du Colombier return;
10209a747e4fSDavid du Colombier }
10219a747e4fSDavid du Colombier }
10229a747e4fSDavid du Colombier
10239a747e4fSDavid du Colombier /*
10249a747e4fSDavid du Colombier * we keep a table by numeric id. by name lookups happen infrequently
10259a747e4fSDavid du Colombier * while by-number lookups happen once for every directory entry read
10269a747e4fSDavid du Colombier * and every stat request.
10279a747e4fSDavid du Colombier */
10289a747e4fSDavid du Colombier User *utab[64];
10299a747e4fSDavid du Colombier User *gtab[64];
10309a747e4fSDavid du Colombier
10319a747e4fSDavid du Colombier User*
adduser(struct passwd * p)10329a747e4fSDavid du Colombier adduser(struct passwd *p)
10333e12c5d1SDavid du Colombier {
10349a747e4fSDavid du Colombier User *u;
10353e12c5d1SDavid du Colombier
10369a747e4fSDavid du Colombier u = emalloc(sizeof(*u));
10379a747e4fSDavid du Colombier u->id = p->pw_uid;
10389a747e4fSDavid du Colombier u->name = estrdup(p->pw_name);
10399a747e4fSDavid du Colombier u->next = utab[p->pw_uid%nelem(utab)];
10409a747e4fSDavid du Colombier u->defaultgid = p->pw_gid;
10419a747e4fSDavid du Colombier utab[p->pw_uid%nelem(utab)] = u;
10429a747e4fSDavid du Colombier return u;
10433e12c5d1SDavid du Colombier }
10443e12c5d1SDavid du Colombier
10453e12c5d1SDavid du Colombier int
useringroup(User * u,User * g)10469a747e4fSDavid du Colombier useringroup(User *u, User *g)
10473e12c5d1SDavid du Colombier {
10489a747e4fSDavid du Colombier int i;
10499a747e4fSDavid du Colombier
10509a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++)
10519a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0)
10523e12c5d1SDavid du Colombier return 1;
10539a747e4fSDavid du Colombier
10549a747e4fSDavid du Colombier /*
10559a747e4fSDavid du Colombier * Hack around common Unix problem that everyone has
10569a747e4fSDavid du Colombier * default group "user" but /etc/group lists no members.
10579a747e4fSDavid du Colombier */
10589a747e4fSDavid du Colombier if(u->defaultgid == g->id)
10599a747e4fSDavid du Colombier return 1;
10603e12c5d1SDavid du Colombier return 0;
10613e12c5d1SDavid du Colombier }
10623e12c5d1SDavid du Colombier
10639a747e4fSDavid du Colombier User*
addgroup(struct group * g)10649a747e4fSDavid du Colombier addgroup(struct group *g)
10653e12c5d1SDavid du Colombier {
10669a747e4fSDavid du Colombier User *u;
10679a747e4fSDavid du Colombier char **p;
10683e12c5d1SDavid du Colombier int n;
10693e12c5d1SDavid du Colombier
10709a747e4fSDavid du Colombier u = emalloc(sizeof(*u));
10719a747e4fSDavid du Colombier n = 0;
10729a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++)
10739a747e4fSDavid du Colombier n++;
10749a747e4fSDavid du Colombier u->mem = emalloc(sizeof(u->mem[0])*n);
10759a747e4fSDavid du Colombier n = 0;
10769a747e4fSDavid du Colombier for(p=g->gr_mem; *p; p++)
10779a747e4fSDavid du Colombier u->mem[n++] = estrdup(*p);
10789a747e4fSDavid du Colombier u->nmem = n;
10799a747e4fSDavid du Colombier u->id = g->gr_gid;
10809a747e4fSDavid du Colombier u->name = estrdup(g->gr_name);
10819a747e4fSDavid du Colombier u->next = gtab[g->gr_gid%nelem(gtab)];
10829a747e4fSDavid du Colombier gtab[g->gr_gid%nelem(gtab)] = u;
10839a747e4fSDavid du Colombier return u;
10843e12c5d1SDavid du Colombier }
10853e12c5d1SDavid du Colombier
10869a747e4fSDavid du Colombier User*
uname2user(char * name)10879a747e4fSDavid du Colombier uname2user(char *name)
10887dd7cddfSDavid du Colombier {
10897dd7cddfSDavid du Colombier int i;
10909a747e4fSDavid du Colombier User *u;
10919a747e4fSDavid du Colombier struct passwd *p;
10927dd7cddfSDavid du Colombier
10939a747e4fSDavid du Colombier for(i=0; i<nelem(utab); i++)
10949a747e4fSDavid du Colombier for(u=utab[i]; u; u=u->next)
10959a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0)
10969a747e4fSDavid du Colombier return u;
10979a747e4fSDavid du Colombier
10989a747e4fSDavid du Colombier if((p = getpwnam(name)) == nil)
10999a747e4fSDavid du Colombier return nil;
11009a747e4fSDavid du Colombier return adduser(p);
11017dd7cddfSDavid du Colombier }
11027dd7cddfSDavid du Colombier
11039a747e4fSDavid du Colombier User*
uid2user(int id)11049a747e4fSDavid du Colombier uid2user(int id)
11059a747e4fSDavid du Colombier {
11069a747e4fSDavid du Colombier User *u;
11079a747e4fSDavid du Colombier struct passwd *p;
11089a747e4fSDavid du Colombier
11099a747e4fSDavid du Colombier for(u=utab[id%nelem(utab)]; u; u=u->next)
11109a747e4fSDavid du Colombier if(u->id == id)
11119a747e4fSDavid du Colombier return u;
11129a747e4fSDavid du Colombier
11139a747e4fSDavid du Colombier if((p = getpwuid(id)) == nil)
11149a747e4fSDavid du Colombier return nil;
11159a747e4fSDavid du Colombier return adduser(p);
11169a747e4fSDavid du Colombier }
11179a747e4fSDavid du Colombier
11189a747e4fSDavid du Colombier User*
gname2user(char * name)11199a747e4fSDavid du Colombier gname2user(char *name)
11203e12c5d1SDavid du Colombier {
11213e12c5d1SDavid du Colombier int i;
11229a747e4fSDavid du Colombier User *u;
11239a747e4fSDavid du Colombier struct group *g;
11243e12c5d1SDavid du Colombier
11259a747e4fSDavid du Colombier for(i=0; i<nelem(gtab); i++)
11269a747e4fSDavid du Colombier for(u=gtab[i]; u; u=u->next)
11279a747e4fSDavid du Colombier if(strcmp(u->name, name) == 0)
11289a747e4fSDavid du Colombier return u;
11299a747e4fSDavid du Colombier
11309a747e4fSDavid du Colombier if((g = getgrnam(name)) == nil)
11319a747e4fSDavid du Colombier return nil;
11329a747e4fSDavid du Colombier return addgroup(g);
11339a747e4fSDavid du Colombier }
11349a747e4fSDavid du Colombier
11359a747e4fSDavid du Colombier User*
gid2user(int id)11369a747e4fSDavid du Colombier gid2user(int id)
11379a747e4fSDavid du Colombier {
11389a747e4fSDavid du Colombier User *u;
11399a747e4fSDavid du Colombier struct group *g;
11409a747e4fSDavid du Colombier
11419a747e4fSDavid du Colombier for(u=gtab[id%nelem(gtab)]; u; u=u->next)
11429a747e4fSDavid du Colombier if(u->id == id)
11439a747e4fSDavid du Colombier return u;
11449a747e4fSDavid du Colombier
11459a747e4fSDavid du Colombier if((g = getgrgid(id)) == nil)
11469a747e4fSDavid du Colombier return nil;
11479a747e4fSDavid du Colombier return addgroup(g);
11483e12c5d1SDavid du Colombier }
11493e12c5d1SDavid du Colombier
11503e12c5d1SDavid du Colombier void
sysfatal(char * fmt,...)11519a747e4fSDavid du Colombier sysfatal(char *fmt, ...)
11523e12c5d1SDavid du Colombier {
11539a747e4fSDavid du Colombier char buf[1024];
11549df35464SDavid du Colombier va_list va, temp;
11553e12c5d1SDavid du Colombier
11569a747e4fSDavid du Colombier va_start(va, fmt);
11579df35464SDavid du Colombier va_copy(temp, va);
11589df35464SDavid du Colombier doprint(buf, buf+sizeof buf, fmt, &temp);
11599df35464SDavid du Colombier va_end(temp);
11609a747e4fSDavid du Colombier va_end(va);
11619a747e4fSDavid du Colombier fprint(2, "u9fs: %s\n", buf);
11629a747e4fSDavid du Colombier fprint(2, "last unix error: %s\n", strerror(errno));
11633e12c5d1SDavid du Colombier exit(1);
11643e12c5d1SDavid du Colombier }
11653e12c5d1SDavid du Colombier
11663e12c5d1SDavid du Colombier void*
emalloc(size_t n)11679a747e4fSDavid du Colombier emalloc(size_t n)
11689a747e4fSDavid du Colombier {
11699a747e4fSDavid du Colombier void *p;
11709a747e4fSDavid du Colombier
1171d9306527SDavid du Colombier if(n == 0)
1172d9306527SDavid du Colombier n = 1;
11739a747e4fSDavid du Colombier p = malloc(n);
11749a747e4fSDavid du Colombier if(p == 0)
11759a747e4fSDavid du Colombier sysfatal("malloc(%ld) fails", (long)n);
11769a747e4fSDavid du Colombier memset(p, 0, n);
11779a747e4fSDavid du Colombier return p;
11789a747e4fSDavid du Colombier }
11799a747e4fSDavid du Colombier
11809a747e4fSDavid du Colombier void*
erealloc(void * p,size_t n)11819a747e4fSDavid du Colombier erealloc(void *p, size_t n)
11823e12c5d1SDavid du Colombier {
11833e12c5d1SDavid du Colombier if(p == 0)
11843e12c5d1SDavid du Colombier p = malloc(n);
11853e12c5d1SDavid du Colombier else
11863e12c5d1SDavid du Colombier p = realloc(p, n);
11873e12c5d1SDavid du Colombier if(p == 0)
11889a747e4fSDavid du Colombier sysfatal("realloc(..., %ld) fails", (long)n);
11893e12c5d1SDavid du Colombier return p;
11903e12c5d1SDavid du Colombier }
11913e12c5d1SDavid du Colombier
11923e12c5d1SDavid du Colombier char*
estrdup(char * p)11933e12c5d1SDavid du Colombier estrdup(char *p)
11943e12c5d1SDavid du Colombier {
11953e12c5d1SDavid du Colombier p = strdup(p);
11963e12c5d1SDavid du Colombier if(p == 0)
11979a747e4fSDavid du Colombier sysfatal("strdup(%.20s) fails", p);
11983e12c5d1SDavid du Colombier return p;
11993e12c5d1SDavid du Colombier }
1200219b2ee8SDavid du Colombier
12019a747e4fSDavid du Colombier char*
estrpath(char * p,char * q,int frog)1202dfda52d8SDavid du Colombier estrpath(char *p, char *q, int frog)
1203219b2ee8SDavid du Colombier {
12049a747e4fSDavid du Colombier char *r, *s;
1205219b2ee8SDavid du Colombier
12069a747e4fSDavid du Colombier if(strcmp(q, "..") == 0){
12079a747e4fSDavid du Colombier r = estrdup(p);
12089a747e4fSDavid du Colombier if((s = strrchr(r, '/')) && s > r)
12099a747e4fSDavid du Colombier *s = '\0';
12109a747e4fSDavid du Colombier else if(s == r)
12119a747e4fSDavid du Colombier s[1] = '\0';
12129a747e4fSDavid du Colombier return r;
1213219b2ee8SDavid du Colombier }
12149a747e4fSDavid du Colombier
1215dfda52d8SDavid du Colombier if(frog)
1216dfda52d8SDavid du Colombier q = defrog(q);
1217dfda52d8SDavid du Colombier else
1218dfda52d8SDavid du Colombier q = strdup(q);
12199a747e4fSDavid du Colombier r = emalloc(strlen(p)+1+strlen(q)+1);
12209a747e4fSDavid du Colombier strcpy(r, p);
12219a747e4fSDavid du Colombier if(r[0]=='\0' || r[strlen(r)-1] != '/')
12229a747e4fSDavid du Colombier strcat(r, "/");
12239a747e4fSDavid du Colombier strcat(r, q);
1224dfda52d8SDavid du Colombier free(q);
12259a747e4fSDavid du Colombier return r;
12269a747e4fSDavid du Colombier }
12279a747e4fSDavid du Colombier
12289a747e4fSDavid du Colombier Fid *fidtab[1];
12299a747e4fSDavid du Colombier
12309a747e4fSDavid du Colombier Fid*
lookupfid(int fid)12319a747e4fSDavid du Colombier lookupfid(int fid)
12329a747e4fSDavid du Colombier {
12339a747e4fSDavid du Colombier Fid *f;
12349a747e4fSDavid du Colombier
12359a747e4fSDavid du Colombier for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next)
12369a747e4fSDavid du Colombier if(f->fid == fid)
12379a747e4fSDavid du Colombier return f;
12389a747e4fSDavid du Colombier return nil;
12399a747e4fSDavid du Colombier }
12409a747e4fSDavid du Colombier
12419a747e4fSDavid du Colombier Fid*
newfid(int fid,char ** ep)12429a747e4fSDavid du Colombier newfid(int fid, char **ep)
12439a747e4fSDavid du Colombier {
12449a747e4fSDavid du Colombier Fid *f;
12459a747e4fSDavid du Colombier
12469a747e4fSDavid du Colombier if(lookupfid(fid) != nil){
12479a747e4fSDavid du Colombier *ep = Efidactive;
12489a747e4fSDavid du Colombier return nil;
12499a747e4fSDavid du Colombier }
12509a747e4fSDavid du Colombier
12519a747e4fSDavid du Colombier f = emalloc(sizeof(*f));
12529a747e4fSDavid du Colombier f->next = fidtab[fid%nelem(fidtab)];
12539a747e4fSDavid du Colombier if(f->next)
12549a747e4fSDavid du Colombier f->next->prev = f;
12559a747e4fSDavid du Colombier fidtab[fid%nelem(fidtab)] = f;
12569a747e4fSDavid du Colombier f->fid = fid;
12579a747e4fSDavid du Colombier f->fd = -1;
12589a747e4fSDavid du Colombier f->omode = -1;
12599a747e4fSDavid du Colombier return f;
12609a747e4fSDavid du Colombier }
12619a747e4fSDavid du Colombier
12629a747e4fSDavid du Colombier Fid*
newauthfid(int fid,void * magic,char ** ep)126350a9bdd4SDavid du Colombier newauthfid(int fid, void *magic, char **ep)
126450a9bdd4SDavid du Colombier {
126550a9bdd4SDavid du Colombier Fid *af;
126650a9bdd4SDavid du Colombier af = newfid(fid, ep);
126750a9bdd4SDavid du Colombier if (af == nil)
126850a9bdd4SDavid du Colombier return nil;
126950a9bdd4SDavid du Colombier af->auth = 1;
127050a9bdd4SDavid du Colombier af->authmagic = magic;
127150a9bdd4SDavid du Colombier return af;
127250a9bdd4SDavid du Colombier }
127350a9bdd4SDavid du Colombier
127450a9bdd4SDavid du Colombier Fid*
oldfidex(int fid,int auth,char ** ep)127550a9bdd4SDavid du Colombier oldfidex(int fid, int auth, char **ep)
12769a747e4fSDavid du Colombier {
12779a747e4fSDavid du Colombier Fid *f;
12789a747e4fSDavid du Colombier
12799a747e4fSDavid du Colombier if((f = lookupfid(fid)) == nil){
12809a747e4fSDavid du Colombier *ep = Ebadfid;
12819a747e4fSDavid du Colombier return nil;
12829a747e4fSDavid du Colombier }
12839a747e4fSDavid du Colombier
128450a9bdd4SDavid du Colombier if (auth != -1 && f->auth != auth) {
128550a9bdd4SDavid du Colombier *ep = Ebadfid;
128650a9bdd4SDavid du Colombier return nil;
128750a9bdd4SDavid du Colombier }
128850a9bdd4SDavid du Colombier
128950a9bdd4SDavid du Colombier if (!f->auth) {
12909a747e4fSDavid du Colombier if(userchange(f->u, ep) < 0)
12919a747e4fSDavid du Colombier return nil;
129250a9bdd4SDavid du Colombier }
12939a747e4fSDavid du Colombier
12949a747e4fSDavid du Colombier return f;
12959a747e4fSDavid du Colombier }
12969a747e4fSDavid du Colombier
129750a9bdd4SDavid du Colombier Fid*
oldfid(int fid,char ** ep)129850a9bdd4SDavid du Colombier oldfid(int fid, char **ep)
129950a9bdd4SDavid du Colombier {
130050a9bdd4SDavid du Colombier return oldfidex(fid, 0, ep);
130150a9bdd4SDavid du Colombier }
130250a9bdd4SDavid du Colombier
130350a9bdd4SDavid du Colombier Fid*
oldauthfid(int fid,void ** magic,char ** ep)130450a9bdd4SDavid du Colombier oldauthfid(int fid, void **magic, char **ep)
130550a9bdd4SDavid du Colombier {
130650a9bdd4SDavid du Colombier Fid *af;
130750a9bdd4SDavid du Colombier af = oldfidex(fid, 1, ep);
130850a9bdd4SDavid du Colombier if (af == nil)
130950a9bdd4SDavid du Colombier return nil;
131050a9bdd4SDavid du Colombier *magic = af->authmagic;
131150a9bdd4SDavid du Colombier return af;
131250a9bdd4SDavid du Colombier }
131350a9bdd4SDavid du Colombier
13149a747e4fSDavid du Colombier void
freefid(Fid * f)13159a747e4fSDavid du Colombier freefid(Fid *f)
13169a747e4fSDavid du Colombier {
13179a747e4fSDavid du Colombier if(f->prev)
13189a747e4fSDavid du Colombier f->prev->next = f->next;
13199a747e4fSDavid du Colombier else
13209a747e4fSDavid du Colombier fidtab[f->fid%nelem(fidtab)] = f->next;
13219a747e4fSDavid du Colombier if(f->next)
13229a747e4fSDavid du Colombier f->next->prev = f->prev;
13239a747e4fSDavid du Colombier if(f->dir)
13249a747e4fSDavid du Colombier closedir(f->dir);
13259a747e4fSDavid du Colombier if(f->fd)
13269a747e4fSDavid du Colombier close(f->fd);
13279a747e4fSDavid du Colombier free(f->path);
13289a747e4fSDavid du Colombier free(f);
13299a747e4fSDavid du Colombier }
13309a747e4fSDavid du Colombier
13319a747e4fSDavid du Colombier int
fidstat(Fid * fid,char ** ep)13329a747e4fSDavid du Colombier fidstat(Fid *fid, char **ep)
13339a747e4fSDavid du Colombier {
13349a747e4fSDavid du Colombier if(stat(fid->path, &fid->st) < 0){
13359a747e4fSDavid du Colombier fprint(2, "fidstat(%s) failed\n", fid->path);
13369a747e4fSDavid du Colombier if(ep)
13379a747e4fSDavid du Colombier *ep = strerror(errno);
13389a747e4fSDavid du Colombier return -1;
13399a747e4fSDavid du Colombier }
13409a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode))
13419a747e4fSDavid du Colombier fid->st.st_size = 0;
13429a747e4fSDavid du Colombier return 0;
13439a747e4fSDavid du Colombier }
13449a747e4fSDavid du Colombier
13459a747e4fSDavid du Colombier int
userchange(User * u,char ** ep)13469a747e4fSDavid du Colombier userchange(User *u, char **ep)
13479a747e4fSDavid du Colombier {
1348d9306527SDavid du Colombier if(defaultuser)
1349d9306527SDavid du Colombier return 0;
1350d9306527SDavid du Colombier
1351d9306527SDavid du Colombier if(setreuid(0, 0) < 0){
13529a747e4fSDavid du Colombier fprint(2, "setreuid(0, 0) failed\n");
13539a747e4fSDavid du Colombier *ep = "cannot setuid back to root";
13549a747e4fSDavid du Colombier return -1;
13559a747e4fSDavid du Colombier }
13569a747e4fSDavid du Colombier
13579a747e4fSDavid du Colombier /*
13589a747e4fSDavid du Colombier * Initgroups does not appear to be SUSV standard.
13599a747e4fSDavid du Colombier * But it exists on SGI and on Linux, which makes me
13609a747e4fSDavid du Colombier * think it's standard enough. We have to do something
13619a747e4fSDavid du Colombier * like this, and the closest other function I can find is
13629a747e4fSDavid du Colombier * setgroups (which initgroups eventually calls).
13639a747e4fSDavid du Colombier * Setgroups is the same as far as standardization though,
13649a747e4fSDavid du Colombier * so we're stuck using a non-SUSV call. Sigh.
13659a747e4fSDavid du Colombier */
13669a747e4fSDavid du Colombier if(initgroups(u->name, u->defaultgid) < 0)
13679a747e4fSDavid du Colombier fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno));
13689a747e4fSDavid du Colombier
13699a747e4fSDavid du Colombier if(setreuid(-1, u->id) < 0){
13709a747e4fSDavid du Colombier fprint(2, "setreuid(-1, %s) failed\n", u->name);
13719a747e4fSDavid du Colombier *ep = strerror(errno);
13729a747e4fSDavid du Colombier return -1;
13739a747e4fSDavid du Colombier }
13749a747e4fSDavid du Colombier
13759a747e4fSDavid du Colombier return 0;
13769a747e4fSDavid du Colombier }
13779a747e4fSDavid du Colombier
13789a747e4fSDavid du Colombier /*
13799a747e4fSDavid du Colombier * We do our own checking here, then switch to root temporarily
13809a747e4fSDavid du Colombier * to set our gid. In a perfect world, you'd be allowed to set your
13819a747e4fSDavid du Colombier * egid to any of the supplemental groups of your euid, but this
13829a747e4fSDavid du Colombier * is not the case on Linux 2.2.14 (and perhaps others).
13839a747e4fSDavid du Colombier *
13849a747e4fSDavid du Colombier * This is a race, of course, but it's a race against processes
13859a747e4fSDavid du Colombier * that can edit the group lists. If you can do that, you can
13869a747e4fSDavid du Colombier * change your own group without our help.
13879a747e4fSDavid du Colombier */
13889a747e4fSDavid du Colombier int
groupchange(User * u,User * g,char ** ep)13899a747e4fSDavid du Colombier groupchange(User *u, User *g, char **ep)
13909a747e4fSDavid du Colombier {
1391dc5a79c1SDavid du Colombier if(g == nil)
1392dc5a79c1SDavid du Colombier return -1;
13939a747e4fSDavid du Colombier if(!useringroup(u, g)){
13949a747e4fSDavid du Colombier if(chatty9p)
13959a747e4fSDavid du Colombier fprint(2, "%s not in group %s\n", u->name, g->name);
13969a747e4fSDavid du Colombier *ep = Enotingroup;
13979a747e4fSDavid du Colombier return -1;
13989a747e4fSDavid du Colombier }
13999a747e4fSDavid du Colombier
14009a747e4fSDavid du Colombier setreuid(0,0);
14019a747e4fSDavid du Colombier if(setregid(-1, g->id) < 0){
14029a747e4fSDavid du Colombier fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id);
14039a747e4fSDavid du Colombier *ep = strerror(errno);
14049a747e4fSDavid du Colombier return -1;
14059a747e4fSDavid du Colombier }
14069a747e4fSDavid du Colombier if(userchange(u, ep) < 0)
14079a747e4fSDavid du Colombier return -1;
14089a747e4fSDavid du Colombier
14099a747e4fSDavid du Colombier return 0;
14109a747e4fSDavid du Colombier }
14119a747e4fSDavid du Colombier
14129a747e4fSDavid du Colombier
14139a747e4fSDavid du Colombier /*
14149a747e4fSDavid du Colombier * An attempt to enforce permissions by looking at the
14159a747e4fSDavid du Colombier * file system. Separation of checking permission and
14169a747e4fSDavid du Colombier * actually performing the action is a terrible idea, of
14179a747e4fSDavid du Colombier * course, so we use setreuid for most of the permission
14189a747e4fSDavid du Colombier * enforcement. This is here only so we can give errors
14199a747e4fSDavid du Colombier * on open(ORCLOSE) in some cases.
14209a747e4fSDavid du Colombier */
14219a747e4fSDavid du Colombier int
userperm(User * u,char * path,int type,int need)14229a747e4fSDavid du Colombier userperm(User *u, char *path, int type, int need)
14239a747e4fSDavid du Colombier {
14249a747e4fSDavid du Colombier char *p, *q;
14259a747e4fSDavid du Colombier int i, have;
14269a747e4fSDavid du Colombier struct stat st;
14279a747e4fSDavid du Colombier User *g;
14289a747e4fSDavid du Colombier
14299a747e4fSDavid du Colombier switch(type){
14309a747e4fSDavid du Colombier default:
14319a747e4fSDavid du Colombier fprint(2, "bad type %d in userperm\n", type);
14329a747e4fSDavid du Colombier return -1;
14339a747e4fSDavid du Colombier case Tdot:
14349a747e4fSDavid du Colombier if(stat(path, &st) < 0){
14359a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) failed\n", path);
14369a747e4fSDavid du Colombier return -1;
14379a747e4fSDavid du Colombier }
14389a747e4fSDavid du Colombier break;
14399a747e4fSDavid du Colombier case Tdotdot:
14409a747e4fSDavid du Colombier p = estrdup(path);
14419a747e4fSDavid du Colombier if((q = strrchr(p, '/'))==nil){
14429a747e4fSDavid du Colombier fprint(2, "userperm(%s, ..): bad path\n", p);
14439a747e4fSDavid du Colombier free(p);
14449a747e4fSDavid du Colombier return -1;
14459a747e4fSDavid du Colombier }
14469a747e4fSDavid du Colombier if(q > p)
14479a747e4fSDavid du Colombier *q = '\0';
14489a747e4fSDavid du Colombier else
14499a747e4fSDavid du Colombier *(q+1) = '\0';
14509a747e4fSDavid du Colombier if(stat(p, &st) < 0){
14519a747e4fSDavid du Colombier fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n",
14529a747e4fSDavid du Colombier p, path);
14539a747e4fSDavid du Colombier free(p);
14549a747e4fSDavid du Colombier return -1;
14559a747e4fSDavid du Colombier }
14569a747e4fSDavid du Colombier free(p);
14579a747e4fSDavid du Colombier break;
14589a747e4fSDavid du Colombier }
14599a747e4fSDavid du Colombier
14609a747e4fSDavid du Colombier if(u == none){
14619a747e4fSDavid du Colombier fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode);
14629a747e4fSDavid du Colombier have = st.st_mode&7;
14639a747e4fSDavid du Colombier if((have&need)==need)
14649a747e4fSDavid du Colombier return 0;
14659a747e4fSDavid du Colombier return -1;
14669a747e4fSDavid du Colombier }
14679a747e4fSDavid du Colombier have = st.st_mode&7;
14689a747e4fSDavid du Colombier if((uid_t)u->id == st.st_uid)
14699a747e4fSDavid du Colombier have |= (st.st_mode>>6)&7;
14709a747e4fSDavid du Colombier if((have&need)==need)
14719a747e4fSDavid du Colombier return 0;
14729a747e4fSDavid du Colombier if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */
14739a747e4fSDavid du Colombier return -1;
14749a747e4fSDavid du Colombier g = gid2user(st.st_gid);
14759a747e4fSDavid du Colombier for(i=0; i<g->nmem; i++){
14769a747e4fSDavid du Colombier if(strcmp(g->mem[i], u->name) == 0){
14779a747e4fSDavid du Colombier have |= (st.st_mode>>3)&7;
14789a747e4fSDavid du Colombier break;
14799a747e4fSDavid du Colombier }
14809a747e4fSDavid du Colombier }
14819a747e4fSDavid du Colombier if((have&need)==need)
14829a747e4fSDavid du Colombier return 0;
14839a747e4fSDavid du Colombier return -1;
14849a747e4fSDavid du Colombier }
14859a747e4fSDavid du Colombier
14869a747e4fSDavid du Colombier int
userwalk(User * u,char ** path,char * elem,Qid * qid,char ** ep)14879a747e4fSDavid du Colombier userwalk(User *u, char **path, char *elem, Qid *qid, char **ep)
14889a747e4fSDavid du Colombier {
14899a747e4fSDavid du Colombier char *npath;
14909a747e4fSDavid du Colombier struct stat st;
14919a747e4fSDavid du Colombier
1492dfda52d8SDavid du Colombier npath = estrpath(*path, elem, 1);
14939a747e4fSDavid du Colombier if(stat(npath, &st) < 0){
14949a747e4fSDavid du Colombier free(npath);
14959a747e4fSDavid du Colombier *ep = strerror(errno);
14969a747e4fSDavid du Colombier return -1;
14979a747e4fSDavid du Colombier }
14989a747e4fSDavid du Colombier *qid = stat2qid(&st);
14999a747e4fSDavid du Colombier free(*path);
15009a747e4fSDavid du Colombier *path = npath;
15019a747e4fSDavid du Colombier return 0;
15029a747e4fSDavid du Colombier }
15039a747e4fSDavid du Colombier
15049a747e4fSDavid du Colombier int
useropen(Fid * fid,int omode,char ** ep)15059a747e4fSDavid du Colombier useropen(Fid *fid, int omode, char **ep)
15069a747e4fSDavid du Colombier {
15079a747e4fSDavid du Colombier int a, o;
15089a747e4fSDavid du Colombier
15099a747e4fSDavid du Colombier /*
15109a747e4fSDavid du Colombier * Check this anyway, to try to head off problems later.
15119a747e4fSDavid du Colombier */
15129a747e4fSDavid du Colombier if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){
15139a747e4fSDavid du Colombier *ep = Eperm;
15149a747e4fSDavid du Colombier return -1;
15159a747e4fSDavid du Colombier }
15169a747e4fSDavid du Colombier
15179a747e4fSDavid du Colombier switch(omode&3){
15189a747e4fSDavid du Colombier default:
15199a747e4fSDavid du Colombier *ep = "programmer error";
15209a747e4fSDavid du Colombier return -1;
15219a747e4fSDavid du Colombier case OREAD:
15221118d624SDavid du Colombier a = R_OK;
15239a747e4fSDavid du Colombier o = O_RDONLY;
15249a747e4fSDavid du Colombier break;
15259a747e4fSDavid du Colombier case ORDWR:
15269a747e4fSDavid du Colombier a = R_OK|W_OK;
15279a747e4fSDavid du Colombier o = O_RDWR;
15289a747e4fSDavid du Colombier break;
15299a747e4fSDavid du Colombier case OWRITE:
1530e5495c06SDavid du Colombier a = W_OK;
15319a747e4fSDavid du Colombier o = O_WRONLY;
15329a747e4fSDavid du Colombier break;
15339a747e4fSDavid du Colombier case OEXEC:
15349a747e4fSDavid du Colombier a = X_OK;
15359a747e4fSDavid du Colombier o = O_RDONLY;
15369a747e4fSDavid du Colombier break;
15379a747e4fSDavid du Colombier }
15389a747e4fSDavid du Colombier if(omode & OTRUNC){
15399a747e4fSDavid du Colombier a |= W_OK;
15409a747e4fSDavid du Colombier o |= O_TRUNC;
15419a747e4fSDavid du Colombier }
15429a747e4fSDavid du Colombier
15439a747e4fSDavid du Colombier if(S_ISDIR(fid->st.st_mode)){
15449a747e4fSDavid du Colombier if(a != R_OK){
15459a747e4fSDavid du Colombier fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode);
15469a747e4fSDavid du Colombier *ep = Eperm;
15479a747e4fSDavid du Colombier return -1;
15489a747e4fSDavid du Colombier }
15499a747e4fSDavid du Colombier if((fid->dir = opendir(fid->path)) == nil){
15509a747e4fSDavid du Colombier *ep = strerror(errno);
15519a747e4fSDavid du Colombier return -1;
15529a747e4fSDavid du Colombier }
15539a747e4fSDavid du Colombier }else{
15540c0e9c72SDavid du Colombier /*
15550c0e9c72SDavid du Colombier * This is wrong because access used the real uid
15560c0e9c72SDavid du Colombier * and not the effective uid. Let the open sort it out.
15570c0e9c72SDavid du Colombier *
15589a747e4fSDavid du Colombier if(access(fid->path, a) < 0){
15599a747e4fSDavid du Colombier *ep = strerror(errno);
15609a747e4fSDavid du Colombier return -1;
15619a747e4fSDavid du Colombier }
15620c0e9c72SDavid du Colombier *
15630c0e9c72SDavid du Colombier */
15649a747e4fSDavid du Colombier if((fid->fd = open(fid->path, o)) < 0){
15659a747e4fSDavid du Colombier *ep = strerror(errno);
15669a747e4fSDavid du Colombier return -1;
15679a747e4fSDavid du Colombier }
15689a747e4fSDavid du Colombier }
15699a747e4fSDavid du Colombier fid->omode = omode;
15709a747e4fSDavid du Colombier return 0;
15719a747e4fSDavid du Colombier }
15729a747e4fSDavid du Colombier
15739a747e4fSDavid du Colombier int
usercreate(Fid * fid,char * elem,int omode,long perm,char ** ep)15749a747e4fSDavid du Colombier usercreate(Fid *fid, char *elem, int omode, long perm, char **ep)
15759a747e4fSDavid du Colombier {
15769a747e4fSDavid du Colombier int o, m;
15779a747e4fSDavid du Colombier char *opath, *npath;
15789a747e4fSDavid du Colombier struct stat st, parent;
15799a747e4fSDavid du Colombier
15809a747e4fSDavid du Colombier if(stat(fid->path, &parent) < 0){
15819a747e4fSDavid du Colombier *ep = strerror(errno);
15829a747e4fSDavid du Colombier return -1;
15839a747e4fSDavid du Colombier }
15849a747e4fSDavid du Colombier
15859a747e4fSDavid du Colombier /*
15869a747e4fSDavid du Colombier * Change group so that created file has expected group
15879a747e4fSDavid du Colombier * by Plan 9 semantics. If that fails, might as well go
15889a747e4fSDavid du Colombier * with the user's default group.
15899a747e4fSDavid du Colombier */
15909a747e4fSDavid du Colombier if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0
15919a747e4fSDavid du Colombier && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0)
15929a747e4fSDavid du Colombier return -1;
15939a747e4fSDavid du Colombier
15949a747e4fSDavid du Colombier m = (perm & DMDIR) ? 0777 : 0666;
15959a747e4fSDavid du Colombier perm = perm & (~m | (fid->st.st_mode & m));
15969a747e4fSDavid du Colombier
1597dfda52d8SDavid du Colombier npath = estrpath(fid->path, elem, 1);
15989a747e4fSDavid du Colombier if(perm & DMDIR){
15999a747e4fSDavid du Colombier if((omode&~ORCLOSE) != OREAD){
16009a747e4fSDavid du Colombier *ep = Eperm;
16019a747e4fSDavid du Colombier free(npath);
16029a747e4fSDavid du Colombier return -1;
16039a747e4fSDavid du Colombier }
16049a747e4fSDavid du Colombier if(stat(npath, &st) >= 0 || errno != ENOENT){
16059a747e4fSDavid du Colombier *ep = Eexist;
16069a747e4fSDavid du Colombier free(npath);
16079a747e4fSDavid du Colombier return -1;
16089a747e4fSDavid du Colombier }
16099a747e4fSDavid du Colombier /* race */
1610*ad6ca847SDavid du Colombier if(mkdir(npath, (perm|0400)&0777) < 0){
16119a747e4fSDavid du Colombier *ep = strerror(errno);
16129a747e4fSDavid du Colombier free(npath);
16139a747e4fSDavid du Colombier return -1;
16149a747e4fSDavid du Colombier }
16159a747e4fSDavid du Colombier if((fid->dir = opendir(npath)) == nil){
16169a747e4fSDavid du Colombier *ep = strerror(errno);
16179a747e4fSDavid du Colombier remove(npath); /* race */
16189a747e4fSDavid du Colombier free(npath);
16199a747e4fSDavid du Colombier return -1;
16209a747e4fSDavid du Colombier }
16219a747e4fSDavid du Colombier }else{
16229a747e4fSDavid du Colombier o = O_CREAT|O_EXCL;
16239a747e4fSDavid du Colombier switch(omode&3){
16249a747e4fSDavid du Colombier default:
16259a747e4fSDavid du Colombier *ep = "programmer error";
16269a747e4fSDavid du Colombier return -1;
16279a747e4fSDavid du Colombier case OREAD:
16289a747e4fSDavid du Colombier case OEXEC:
16299a747e4fSDavid du Colombier o |= O_RDONLY;
16309a747e4fSDavid du Colombier break;
16319a747e4fSDavid du Colombier case ORDWR:
16329a747e4fSDavid du Colombier o |= O_RDWR;
16339a747e4fSDavid du Colombier break;
16349a747e4fSDavid du Colombier case OWRITE:
16359a747e4fSDavid du Colombier o |= O_WRONLY;
16369a747e4fSDavid du Colombier break;
16379a747e4fSDavid du Colombier }
16389a747e4fSDavid du Colombier if(omode & OTRUNC)
16399a747e4fSDavid du Colombier o |= O_TRUNC;
16409a747e4fSDavid du Colombier if((fid->fd = open(npath, o, perm&0777)) < 0){
16419a747e4fSDavid du Colombier if(chatty9p)
16429a747e4fSDavid du Colombier fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777);
16439a747e4fSDavid du Colombier *ep = strerror(errno);
16449a747e4fSDavid du Colombier free(npath);
16459a747e4fSDavid du Colombier return -1;
16469a747e4fSDavid du Colombier }
16479a747e4fSDavid du Colombier }
16489a747e4fSDavid du Colombier
16499a747e4fSDavid du Colombier opath = fid->path;
16509a747e4fSDavid du Colombier fid->path = npath;
16519a747e4fSDavid du Colombier if(fidstat(fid, ep) < 0){
16529a747e4fSDavid du Colombier fprint(2, "stat after create on %s failed\n", npath);
16539a747e4fSDavid du Colombier remove(npath); /* race */
16549a747e4fSDavid du Colombier free(npath);
16559a747e4fSDavid du Colombier fid->path = opath;
16569a747e4fSDavid du Colombier if(fid->fd >= 0){
16579a747e4fSDavid du Colombier close(fid->fd);
16589a747e4fSDavid du Colombier fid->fd = -1;
16599a747e4fSDavid du Colombier }else{
16609a747e4fSDavid du Colombier closedir(fid->dir);
16619a747e4fSDavid du Colombier fid->dir = nil;
16629a747e4fSDavid du Colombier }
16639a747e4fSDavid du Colombier return -1;
16649a747e4fSDavid du Colombier }
16659a747e4fSDavid du Colombier fid->omode = omode;
16669a747e4fSDavid du Colombier free(opath);
16679a747e4fSDavid du Colombier return 0;
16689a747e4fSDavid du Colombier }
16699a747e4fSDavid du Colombier
16709a747e4fSDavid du Colombier int
userremove(Fid * fid,char ** ep)16719a747e4fSDavid du Colombier userremove(Fid *fid, char **ep)
16729a747e4fSDavid du Colombier {
16739a747e4fSDavid du Colombier if(remove(fid->path) < 0){
16749a747e4fSDavid du Colombier *ep = strerror(errno);
16759a747e4fSDavid du Colombier return -1;
16769a747e4fSDavid du Colombier }
16779a747e4fSDavid du Colombier return 0;
16789a747e4fSDavid du Colombier }
16799a747e4fSDavid du Colombier
16809a747e4fSDavid du Colombier void
usage(void)16819a747e4fSDavid du Colombier usage(void)
16829a747e4fSDavid du Colombier {
16839a747e4fSDavid du Colombier fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n");
16849a747e4fSDavid du Colombier exit(1);
16859a747e4fSDavid du Colombier }
16869a747e4fSDavid du Colombier
16879a747e4fSDavid du Colombier int
main(int argc,char ** argv)16889a747e4fSDavid du Colombier main(int argc, char **argv)
16899a747e4fSDavid du Colombier {
16909a747e4fSDavid du Colombier char *authtype;
16919a747e4fSDavid du Colombier int i;
16929a747e4fSDavid du Colombier int fd;
16939a747e4fSDavid du Colombier int logflag;
16949a747e4fSDavid du Colombier
16959a747e4fSDavid du Colombier auth = authmethods[0];
16969a747e4fSDavid du Colombier logflag = O_WRONLY|O_APPEND|O_CREAT;
16979a747e4fSDavid du Colombier ARGBEGIN{
16989a747e4fSDavid du Colombier case 'D':
16999a747e4fSDavid du Colombier chatty9p = 1;
17009a747e4fSDavid du Colombier break;
17019a747e4fSDavid du Colombier case 'a':
17029a747e4fSDavid du Colombier authtype = EARGF(usage());
17039a747e4fSDavid du Colombier auth = nil;
17049a747e4fSDavid du Colombier for(i=0; i<nelem(authmethods); i++)
17059a747e4fSDavid du Colombier if(strcmp(authmethods[i]->name, authtype)==0)
17069a747e4fSDavid du Colombier auth = authmethods[i];
17079a747e4fSDavid du Colombier if(auth == nil)
17089a747e4fSDavid du Colombier sysfatal("unknown auth type '%s'", authtype);
17099a747e4fSDavid du Colombier break;
17109a747e4fSDavid du Colombier case 'A':
17119a747e4fSDavid du Colombier autharg = EARGF(usage());
17129a747e4fSDavid du Colombier break;
17139a747e4fSDavid du Colombier case 'l':
17149a747e4fSDavid du Colombier logfile = EARGF(usage());
17159a747e4fSDavid du Colombier break;
17169a747e4fSDavid du Colombier case 'm':
17179a747e4fSDavid du Colombier msize = strtol(EARGF(usage()), 0, 0);
17189a747e4fSDavid du Colombier break;
17199a747e4fSDavid du Colombier case 'n':
17209a747e4fSDavid du Colombier network = 0;
17219a747e4fSDavid du Colombier break;
17229a747e4fSDavid du Colombier case 'u':
17239a747e4fSDavid du Colombier defaultuser = EARGF(usage());
17249a747e4fSDavid du Colombier break;
17259a747e4fSDavid du Colombier case 'z':
17269a747e4fSDavid du Colombier logflag |= O_TRUNC;
17279a747e4fSDavid du Colombier }ARGEND
17289a747e4fSDavid du Colombier
17299a747e4fSDavid du Colombier if(argc > 1)
17309a747e4fSDavid du Colombier usage();
17319a747e4fSDavid du Colombier
17329a747e4fSDavid du Colombier fd = open(logfile, logflag, 0666);
17339a747e4fSDavid du Colombier if(fd < 0)
17349a747e4fSDavid du Colombier sysfatal("cannot open log '%s'", logfile);
17359a747e4fSDavid du Colombier
17369a747e4fSDavid du Colombier if(dup2(fd, 2) < 0)
17379a747e4fSDavid du Colombier sysfatal("cannot dup fd onto stderr");
17389a747e4fSDavid du Colombier fprint(2, "u9fs\nkill %d\n", (int)getpid());
17399a747e4fSDavid du Colombier
17409a747e4fSDavid du Colombier fmtinstall('F', fcallconv);
17419a747e4fSDavid du Colombier fmtinstall('D', dirconv);
17429a747e4fSDavid du Colombier fmtinstall('M', dirmodeconv);
17439a747e4fSDavid du Colombier
17449a747e4fSDavid du Colombier rxbuf = emalloc(msize);
17459a747e4fSDavid du Colombier txbuf = emalloc(msize);
17469a747e4fSDavid du Colombier databuf = emalloc(msize);
17479a747e4fSDavid du Colombier
17489a747e4fSDavid du Colombier if(auth->init)
17499a747e4fSDavid du Colombier auth->init();
17509a747e4fSDavid du Colombier
17519a747e4fSDavid du Colombier if(network)
17529a747e4fSDavid du Colombier getremotehostname(remotehostname, sizeof remotehostname);
17539a747e4fSDavid du Colombier
17549a747e4fSDavid du Colombier if(gethostname(hostname, sizeof hostname) < 0)
17559a747e4fSDavid du Colombier strcpy(hostname, "gnot");
17569a747e4fSDavid du Colombier
17579a747e4fSDavid du Colombier umask(0);
17589a747e4fSDavid du Colombier
17599a747e4fSDavid du Colombier if(argc == 1)
17609a747e4fSDavid du Colombier if(chroot(argv[0]) < 0)
17619a747e4fSDavid du Colombier sysfatal("chroot '%s' failed", argv[0]);
17629a747e4fSDavid du Colombier
17639a747e4fSDavid du Colombier none = uname2user("none");
1764*ad6ca847SDavid du Colombier if(none == nil)
1765*ad6ca847SDavid du Colombier none = uname2user("nobody");
17669df35464SDavid du Colombier
17679a747e4fSDavid du Colombier serve(0, 1);
17689a747e4fSDavid du Colombier return 0;
17699a747e4fSDavid du Colombier }
1770