This patch address two long-standing issues in u9fs: First, use of chroot causes complications when a root is specified; chroot requires /etc/^(passwd group) and friends be copied to the new root. This is uneccessary, and is obviated by use of a new function named rootpath. Second, files created with a default user are owned by the user of the process rather than the default user. This is addressed by issuing a chown after create to reinstate proper permission. --- /n/sources/plan9/sys/src/cmd/unix/u9fs/u9fs.c Fri Jul 29 22:16:34 2011 +++ /sys/src/cmd/unix/u9fs/u9fs.c Tue Aug 21 00:00:00 2012 @@ -12,6 +12,7 @@ #include /* for errno */ #include /* for remove [sic] */ #include /* for O_RDONLY, etc. */ +#include /* for PATH_MAX */ #include /* various networking crud */ #include @@ -147,6 +148,7 @@ int network = 1; int old9p = -1; int authed; +char* root; User* none; Auth *authmethods[] = { /* first is default */ @@ -171,6 +173,17 @@ [0x7f] 1, }; +char* +rootpath(char *path) +{ + static char buf[PATH_MAX]; + + if(root == nil) + return path; + snprintf(buf, sizeof buf, "%s%s", root, path); + return buf; +} + void getfcallnew(int fd, Fcall *fc, int have) { @@ -704,7 +717,7 @@ void rread(Fcall *rx, Fcall *tx) { - char *e, *path; + char *e, *path, *rpath; uchar *p, *ep; int n; Fid *fid; @@ -764,7 +777,8 @@ fid->dirent = nil; continue; } - path = estrpath(fid->path, fid->dirent->d_name, 0); + rpath = rootpath(fid->path); + path = estrpath(rpath, fid->dirent->d_name, 0); memset(&st, 0, sizeof st); if(stat(path, &st) < 0){ fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); @@ -830,7 +844,7 @@ void rclunk(Fcall *rx, Fcall *tx) { - char *e; + char *e, *rpath; Fid *fid; if((fid = oldfidex(rx->fid, -1, &e)) == nil){ @@ -846,8 +860,10 @@ } } } - else if(fid->omode != -1 && fid->omode&ORCLOSE) - remove(fid->path); + else if(fid->omode != -1 && fid->omode&ORCLOSE){ + rpath = rootpath(fid->path); + remove(rpath); + } freefid(fid); } @@ -891,7 +907,7 @@ void rwstat(Fcall *rx, Fcall *tx) { - char *e; + char *e, *opath, *npath; char *p, *old, *new, *dir; gid_t gid; Dir d; @@ -961,9 +977,10 @@ * leave truncate until last. * (see above comment about atomicity). */ - if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ + opath = estrdup(rootpath(fid->path)); + if((u32int)d.mode != (u32int)~0 && chmod(opath, unixmode(&d)) < 0){ if(chatty9p) - fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); + fprint(2, "chmod(%s, 0%luo) failed\n", opath, unixmode(&d)); seterror(tx, strerror(errno)); return; } @@ -973,18 +990,18 @@ t.actime = 0; t.modtime = d.mtime; - if(utime(fid->path, &t) < 0){ + if(utime(opath, &t) < 0){ if(chatty9p) - fprint(2, "utime(%s) failed\n", fid->path); + fprint(2, "utime(%s) failed\n", opath); seterror(tx, strerror(errno)); return; } } if(gid != (gid_t)-1 && gid != fid->st.st_gid){ - if(chown(fid->path, (uid_t)-1, gid) < 0){ + if(chown(opath, (uid_t)-1, gid) < 0){ if(chatty9p) - fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); + fprint(2, "chgrp(%s, %d) failed\n", opath, gid); seterror(tx, strerror(errno)); return; } @@ -1000,21 +1017,24 @@ return; } new = estrpath(dir, d.name, 1); - if(strcmp(old, new) != 0 && rename(old, new) < 0){ + npath = rootpath(new); + if(strcmp(old, new) != 0 && rename(opath, npath) < 0){ if(chatty9p) fprint(2, "rename(%s, %s) failed\n", old, new); seterror(tx, strerror(errno)); free(new); free(dir); + free(opath); return; } fid->path = new; free(old); free(dir); + free(opath); } - if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ - fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); + if((u64int)d.length != (u64int)~0 && truncate(opath, d.length) < 0){ + fprint(2, "truncate(%s, %lld) failed\n", opath, d.length); seterror(tx, strerror(errno)); return; } @@ -1331,8 +1351,11 @@ int fidstat(Fid *fid, char **ep) { - if(stat(fid->path, &fid->st) < 0){ - fprint(2, "fidstat(%s) failed\n", fid->path); + char *rpath; + + rpath = rootpath(fid->path); + if(stat(rpath, &fid->st) < 0){ + fprint(2, "fidstat(%s) failed\n", rpath); if(ep) *ep = strerror(errno); return -1; @@ -1421,7 +1444,7 @@ int userperm(User *u, char *path, int type, int need) { - char *p, *q; + char *p, *q, *rpath; int i, have; struct stat st; User *g; @@ -1431,13 +1454,15 @@ fprint(2, "bad type %d in userperm\n", type); return -1; case Tdot: - if(stat(path, &st) < 0){ - fprint(2, "userperm: stat(%s) failed\n", path); + rpath = rootpath(path); + if(stat(rpath, &st) < 0){ + fprint(2, "userperm: stat(%s) failed\n", rpath); return -1; } break; case Tdotdot: - p = estrdup(path); + rpath = rootpath(path); + p = estrdup(rpath); if((q = strrchr(p, '/'))==nil){ fprint(2, "userperm(%s, ..): bad path\n", p); free(p); @@ -1449,7 +1474,7 @@ *(q+1) = '\0'; if(stat(p, &st) < 0){ fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", - p, path); + p, rpath); free(p); return -1; } @@ -1486,11 +1511,12 @@ int userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) { - char *npath; + char *npath, *rpath; struct stat st; npath = estrpath(*path, elem, 1); - if(stat(npath, &st) < 0){ + rpath = rootpath(npath); + if(stat(rpath, &st) < 0){ free(npath); *ep = strerror(errno); return -1; @@ -1505,6 +1531,7 @@ useropen(Fid *fid, int omode, char **ep) { int a, o; + char *rpath; /* * Check this anyway, to try to head off problems later. @@ -1546,7 +1573,8 @@ *ep = Eperm; return -1; } - if((fid->dir = opendir(fid->path)) == nil){ + rpath = rootpath(fid->path); + if((fid->dir = opendir(rpath)) == nil){ *ep = strerror(errno); return -1; } @@ -1561,7 +1589,8 @@ } * */ - if((fid->fd = open(fid->path, o)) < 0){ + rpath = rootpath(fid->path); + if((fid->fd = open(rpath, o)) < 0){ *ep = strerror(errno); return -1; } @@ -1574,10 +1603,12 @@ usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) { int o, m; - char *opath, *npath; + char *opath, *npath, *rpath; struct stat st, parent; + User *u; - if(stat(fid->path, &parent) < 0){ + rpath = rootpath(fid->path); + if(stat(rpath, &parent) < 0){ *ep = strerror(errno); return -1; } @@ -1594,7 +1625,7 @@ m = (perm & DMDIR) ? 0777 : 0666; perm = perm & (~m | (fid->st.st_mode & m)); - npath = estrpath(fid->path, elem, 1); + npath = estrpath(rpath, elem, 1); if(perm & DMDIR){ if((omode&~ORCLOSE) != OREAD){ *ep = Eperm; @@ -1646,8 +1677,28 @@ } } + /* + * Change ownership if a default user is specified. + */ + if(defaultuser) + if((u = uname2user(defaultuser)) == nil + || chown(npath, u->id, -1) < 0){ + fprint(2, "chown after create on %s failed\n", npath); + remove(npath); /* race */ + free(npath); + fid->path = opath; + if(fid->fd >= 0){ + close(fid->fd); + fid->fd = -1; + }else{ + closedir(fid->dir); + fid->dir = nil; + } + return -1; + } + opath = fid->path; - fid->path = npath; + fid->path = estrpath(opath, elem, 1); if(fidstat(fid, ep) < 0){ fprint(2, "stat after create on %s failed\n", npath); remove(npath); /* race */ @@ -1670,7 +1721,10 @@ int userremove(Fid *fid, char **ep) { - if(remove(fid->path) < 0){ + char *rpath; + + rpath = rootpath(fid->path); + if(remove(rpath) < 0){ *ep = strerror(errno); return -1; } @@ -1757,8 +1811,7 @@ umask(0); if(argc == 1) - if(chroot(argv[0]) < 0) - sysfatal("chroot '%s' failed", argv[0]); + root = argv[0]; none = uname2user("none"); if(none == nil)