via brian stuart Here's an update on the file system. There's a very rough initial cut at a man page and a few updates to the system itself. The main difference from the last one are improvements and fixes for the NFS UID management. BLS Reference: /n/atom/patch/applied/thetafs2 Date: Thu Feb 27 11:43:39 CET 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/θfs/cons.c Thu Feb 27 11:42:53 2014 +++ /sys/src/cmd/θfs/cons.c Thu Feb 27 11:42:54 2014 @@ -39,11 +39,13 @@ CMcheckalloc, CMcstat, CMdisallow, + CMdumpusers, CMfixfamilies, CMfixpaths, CMhalt, CMhelp, CMhstat, + CMinituid, CMlcreate, CMlls, CMlmeta, @@ -95,11 +97,13 @@ {CMcheckalloc, "checkalloc", 1}, {CMcstat, "cstat", 1}, {CMdisallow, "disallow", 1}, + {CMdumpusers, "dumpusers", 1}, {CMfixfamilies, "fixfamilies", 1}, {CMfixpaths, "fixpaths", 1}, {CMhalt, "halt", 1}, {CMhelp, "help", 1}, {CMhstat, "hstat", 1}, + {CMinituid, "inituid", 1}, {CMlcreate, "lcreate", 3}, {CMlls, "lls", 1}, {CMlmeta, "lmeta", 2}, @@ -506,6 +510,9 @@ case CMdisallow: allow = 0; break; + case CMdumpusers: + dumpusers(pfd[1]); + break; case CMfixfamilies: fixfamilies(pfd[1]); break; @@ -521,6 +528,9 @@ case CMhstat: fprint(pfd[1], "%s", prhstat()); break; + case CMinituid: + inituid(); + break; case CMlcreate: lcreate(cb->f[1], strtoull(cb->f[2], nil, 10)); break; @@ -666,6 +676,9 @@ break; case CMdisallow: allow = 0; + break; + case CMinituid: + inituid(); break; case CMlcreate: lcreate(cb->f[1], strtoull(cb->f[2], nil, 10)); --- /sys/src/cmd/θfs/dat.h Thu Feb 27 11:42:55 2014 +++ /sys/src/cmd/θfs/dat.h Thu Feb 27 11:42:56 2014 @@ -198,11 +198,14 @@ extern Super super; /* uid.c */ +extern void dumpusers(int); +extern int gname2id(char *, char *); extern char *id2gname(char *, int); extern char *id2uname(char *, int); extern int ingroup(char *, char *); extern void inituid(void); extern int isleader(char *, char *); +extern int uname2id(char *, char *); /* util.c */ extern void *θmalloc(ulong); --- /sys/src/cmd/θfs/nfs.c Thu Feb 27 11:42:59 2014 +++ /sys/src/cmd/θfs/nfs.c Thu Feb 27 11:43:01 2014 @@ -676,17 +676,27 @@ } static char * -fattr3(int fd, char *rp, Qid *qid) +fattr3(int fd, char *rp, Qid *qid, char *auth) { - char *symlink; + char *symlink, *ugid, *host; uvlong meta, len, mtime, x; + int n; meta = q2m(fd, qid->path, 0); if(meta == 0) -{ -fprint(2, "nil meta in fattr3: caller:%p qpath:%ulld fd:%d\n", getcallerpc(&fd), qid->path, fd); return nil; -} + host = nil; + switch(nhgetl(auth)) { + case AUTH_UNIX: + auth += 12; + n = nhgetl(auth); + host = emalloc9p(n + 1); + auth += 4; + memmove(host, auth, n); + break; + default: /* We're going to ignore the others for now */ + break; + } if(qid->type & QTDIR) rp = rpcputl(rp, NF3DIR); else { @@ -706,14 +716,20 @@ else rp = rpcputl(rp, 0777); rp = rpcputl(rp, 1); /* nlink */ - if(getmetaint(fd, meta, "nuid", &x) == MTnone) /* uid */ - rp = rpcputl(rp, -2); - else + if(getmetaint(fd, meta, "nuid", &x) != MTnone) /* uid */ rp = rpcputl(rp, x); - if(getmetaint(fd, meta, "ngid", &x) == MTnone) /* gid */ - rp = rpcputl(rp, -2); - else + else { + ugid = getmetastr(fd, meta, "uid"); + rp = rpcputl(rp, uname2id(host, ugid)); + free(ugid); + } + if(getmetaint(fd, meta, "ngid", &x) != MTnone) /* gid */ rp = rpcputl(rp, x); + else { + ugid = getmetastr(fd, meta, "gid"); + rp = rpcputl(rp, gname2id(host, ugid)); + free(ugid); + } if(getmetaint(fd, meta, "length", &len) == MTnone) len = 0; rp = rpcputv(rp, len); /* size */ @@ -751,18 +767,18 @@ rp = rpcputl(rp, x / 1000000000LL); rp = rpcputl(rp, x % 1000000000LL); } + free(host); return rp; } static char * -opattr(int fd, char *rp, Qid *qid) +opattr(int fd, char *rp, Qid *qid, char *auth) { char *trp; rp = rpcputl(rp, 1); - trp = fattr3(fd, rp, qid); + trp = fattr3(fd, rp, qid, auth); if(trp == nil) { -fprint(2, "nil in opattr from %p\n", getcallerpc(&fd)); rp -= 4; rp = rpcputl(rp, 0); return rp; @@ -791,7 +807,7 @@ host = emalloc9p(n + 1); auth += 4; memmove(host, auth, n); - auth += n; + auth += round4(n); nuid = nhgetl(auth); auth += 4; ngid = nhgetl(auth); @@ -851,7 +867,7 @@ } static char * -dowcc(int fd, char *rp, Qid *qid, uvlong prelen, uvlong premtime, uvlong prectime) +dowcc(int fd, char *rp, char *auth, Qid *qid, uvlong prelen, uvlong premtime, uvlong prectime) { rp = rpcputl(rp, 1); rp = rpcputv(rp, prelen); @@ -859,7 +875,7 @@ rp = rpcputl(rp, premtime % 1000000000LL); rp = rpcputl(rp, prectime / 1000000000LL); rp = rpcputl(rp, prectime % 1000000000LL); - rp = opattr(fd, rp, qid); + rp = opattr(fd, rp, qid, auth); return rp; } @@ -965,7 +981,7 @@ } static char * -nfsgetattr(char *buf, char *p, ulong xid, char *verf) +nfsgetattr(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp, *a; @@ -985,7 +1001,7 @@ qid = *((Qid *)(p + 4)); rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); rp = rpcputl(rp, NFS3_OK); - a = fattr3(fd, rp, &qid); + a = fattr3(fd, rp, &qid, auth); if(a == nil) hnputl(rp-4, NFS3ERR_BADHANDLE); else @@ -996,7 +1012,7 @@ } static char * -nfssetattr(char *buf, char *p, ulong xid, char *verf) +nfssetattr(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp; @@ -1022,7 +1038,7 @@ dosattr(meta, p); rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); rp = rpcputl(rp, NFS3_OK); - rp = dowcc(-1, rp, &qid, prelen, premeta, prectime); + rp = dowcc(-1, rp, auth, &qid, prelen, premeta, prectime); return rp; } @@ -1119,8 +1135,8 @@ rp += round4(sizeof(Qid)); if(fd != -1) rp = rpcputv(rp, sqid); - rp = opattr(fd, rp, &qid2); - rp = opattr(pfd, rp, &qid); + rp = opattr(fd, rp, &qid2, auth); + rp = opattr(pfd, rp, &qid, auth); free(name); if(fd != -1) close(fd); @@ -1170,7 +1186,7 @@ rspacc |= ACCESS3_LOOKUP | ACCESS3_EXECUTE; rspacc &= reqacc; rp = rpcputl(rp, NFS3_OK); - a = fattr3(fd, rp + 4, &qid); + a = fattr3(fd, rp + 4, &qid, auth); if(a == nil) { hnputl(rp-4, NFS3ERR_BADHANDLE); rpcputl(rp, 0); @@ -1186,7 +1202,7 @@ } static char * -nfsreadlink(char *buf, char *p, ulong xid, char *verf) +nfsreadlink(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp, *pp; @@ -1223,7 +1239,7 @@ } n = strlen(pp); rp = rpcputl(rp, NFS3_OK); - rp = opattr(fd, rp, &qid); + rp = opattr(fd, rp, &qid, auth); rp = rpcputl(rp, n); memmove(rp, pp, n); rp += round4(n); @@ -1282,7 +1298,7 @@ if(getmetaint(fd, meta, "length", &len) == MTnone) len = 0; count2 = θpread(fd, qid.path, a, count1, offset); - a = fattr3(fd, rp + 8, &qid); + a = fattr3(fd, rp + 8, &qid, auth); if(a == nil) { rp = rpcputl(rp, NFS3ERR_BADHANDLE); rp = rpcputl(rp, 0); @@ -1369,7 +1385,7 @@ return rp; } rp = rpcputl(rp, NFS3_OK); - rp = dowcc(-1, rp, &qid, prelen, premtime, prectime); + rp = dowcc(-1, rp, auth, &qid, prelen, premtime, prectime); rp = rpcputl(rp, count2); if(stable == UNSTABLE) rp = rpcputl(rp, UNSTABLE); @@ -1531,8 +1547,8 @@ rp = rpcputl(rp, round4(sizeof(Qid))); memmove(rp, &nqid, sizeof(Qid)); rp += round4(sizeof(Qid)); - rp = opattr(-1, rp, &nqid); - rp = dowcc(-1, rp, &qid, prelen, premeta, prectime); + rp = opattr(-1, rp, &nqid, auth); + rp = dowcc(-1, rp, auth, &qid, prelen, premeta, prectime); savesuper(); return rp; } @@ -1645,14 +1661,14 @@ rmp(path); rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); rp = rpcputl(rp, NFS3_OK); - rp = dowcc(-1, rp, &qid, prelen, premtime, prectime); + rp = dowcc(-1, rp, auth, &qid, prelen, premtime, prectime); free(name); free(path); return rp; } static char * -nfsfsstat(char *buf, char *p, ulong xid, char *verf) +nfsfsstat(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp, *a; @@ -1660,7 +1676,7 @@ qid = *((Qid *)(p + 4)); rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); rp = rpcputl(rp, NFS3_OK); - a = fattr3(-1, rp + 4, &qid); + a = fattr3(-1, rp + 4, &qid, auth); if(a == nil) { hnputl(rp - 4, NFS3ERR_BADHANDLE); hnputl(rp, 0); @@ -1679,7 +1695,7 @@ } static char * -nfsfsinfo(char *buf, char *p, ulong xid, char *verf) +nfsfsinfo(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp, *a; @@ -1688,7 +1704,7 @@ rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); hnputl(rp, NFS3_OK); rp += 4; - a = fattr3(-1, rp + 4, &qid); + a = fattr3(-1, rp + 4, &qid, auth); if(a == nil) { hnputl(rp - 4, NFS3ERR_BADHANDLE); hnputl(rp, 0); @@ -1711,7 +1727,7 @@ } static char * -nfspathconf(char *buf, char *p, ulong xid, char *verf) +nfspathconf(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp, *a; @@ -1720,7 +1736,7 @@ rp = initreply(buf, xid, MSG_ACCEPTED, verf, SUCCESS); hnputl(rp, NFS3_OK); rp += 4; - a = fattr3(-1, rp + 4, &qid); + a = fattr3(-1, rp + 4, &qid, auth); if(a == nil) { hnputl(rp - 4, NFS3ERR_BADHANDLE); return rp; @@ -1825,8 +1841,8 @@ setmetaint(fdmeta, "atime", nil, now); rp = rpcputl(rp, NFS3_OK); done: - rp = dowcc(-1, rp, &fqid, fprelen, fpremtime, fprectime); - rp = dowcc(-1, rp, &tqid, tprelen, tpremtime, tprectime); + rp = dowcc(-1, rp, auth, &fqid, fprelen, fpremtime, fprectime); + rp = dowcc(-1, rp, auth, &tqid, tprelen, tpremtime, tprectime); free(fname); free(fpath); free(tname); @@ -1916,7 +1932,7 @@ getmetaint(fd, meta, "sib", &cookie); count2 += round4(n) + 24; } - a = fattr3(fd, rp + 8, &qid); + a = fattr3(fd, rp + 8, &qid, auth); if(a == nil) { rp = rpcputl(rp, NFS3ERR_BADHANDLE); rp = rpcputl(rp, 0); @@ -2031,7 +2047,7 @@ a += round4(n); free(xs); a = rpcputv(a, cookie); /* cookie */ - a = opattr(fd, a, &qid2); /* name_attributes */ + a = opattr(fd, a, &qid2, auth); /* name_attributes */ a = rpcputl(a, 1); /* name_handle */ a = rpcputl(a, m); memmove(a, &qid2, sizeof(Qid)); @@ -2041,7 +2057,7 @@ getmetaint(fd, meta, "sib", &cookie); count2 += 4 + 8 + 4 + round4(n) + 8 + 88 + 4 + 4+ m; } - a = fattr3(fd, rp + 8, &qid); + a = fattr3(fd, rp + 8, &qid, auth); if(a == nil) { rp = rpcputl(rp, NFS3ERR_BADHANDLE); rp = rpcputl(rp, 0); @@ -2063,7 +2079,7 @@ } static char * -nfscommit(char *buf, char *p, ulong xid, char *verf) +nfscommit(char *buf, char *p, ulong xid, char *auth, char *verf) { Qid qid; char *rp; @@ -2086,7 +2102,7 @@ resetmeta(); csync(); rp = rpcputl(rp, NFS3_OK); - rp = dowcc(-1, rp, &qid, prelen, premtime, prectime); + rp = dowcc(-1, rp, auth, &qid, prelen, premtime, prectime); rp = rpcputv(rp, starttime); return rp; } @@ -2112,10 +2128,10 @@ rp = rpcnull(buf, xid, verf); break; case NFSPROC3_GETATTR: - rp = nfsgetattr(buf, p, xid, verf); + rp = nfsgetattr(buf, p, xid, auth, verf); break; case NFSPROC3_SETATTR: - rp = nfssetattr(buf, p, xid, verf); + rp = nfssetattr(buf, p, xid, auth, verf); break; case NFSPROC3_LOOKUP: rp = nfslookup(buf, p, xid, auth, verf); @@ -2124,7 +2140,7 @@ rp = nfsaccess(buf, p, xid, auth, verf); break; case NFSPROC3_READLINK: - rp = nfsreadlink(buf, p, xid, verf); + rp = nfsreadlink(buf, p, xid, auth, verf); break; case NFSPROC3_READ: rp = nfsread(buf, p, xid, auth, verf); @@ -2161,16 +2177,16 @@ rp = nfsreaddirplus(buf, p, xid, auth, verf); break; case NFSPROC3_FSSTAT: - rp = nfsfsstat(buf, p, xid, verf); + rp = nfsfsstat(buf, p, xid, auth, verf); break; case NFSPROC3_FSINFO: - rp = nfsfsinfo(buf, p, xid, verf); + rp = nfsfsinfo(buf, p, xid, auth, verf); break; case NFSPROC3_PATHCONF: - rp = nfspathconf(buf, p, xid, verf); + rp = nfspathconf(buf, p, xid, auth, verf); break; case NFSPROC3_COMMIT: - rp = nfscommit(buf, p, xid, verf); + rp = nfscommit(buf, p, xid, auth, verf); break; default: rp = initreply(buf, xid, MSG_DENIED, verf, PROC_UNAVAIL); --- /sys/src/cmd/θfs/uid.c Thu Feb 27 11:43:02 2014 +++ /sys/src/cmd/θfs/uid.c Thu Feb 27 11:43:02 2014 @@ -83,24 +83,34 @@ static int np9users; static Unixsys *unixhd; -/* -static void -dumpusers(void) +void +dumpusers(int fd) { P9user *u; - int i, j, fd; + Unixsys *us; + int i, j; - fd = create("/tmp/users.dump", OWRITE, 0666); + fprint(fd, "/adm/users:\n"); for(u = p9users, i = 0; i < np9users; ++u, ++i) { - fprint(fd, "id:%s name:%s leader:%s nmembers:%d\n", + fprint(fd, " id:%s name:%s leader:%s nmembers:%d\n ", u->id, u->name, u->leader, u->nmembers); for(j = 0; j < u->nmembers; ++j) fprint(fd, "%s ", u->members[j]); fprint(fd, "\n"); } - close(fd); + fprint(fd, "/adm/nfs:\n"); + for(us = unixhd; us; us = us->next) { + fprint(fd, " name=%s nusers=%d ngroup=%d\n", + us->name, us->nusers, us->ngroups); + fprint(fd, " users: "); + for(i = 0; i < us->nusers; ++i) + fprint(fd, "%s:%d, ", us->users[i].name, us->users[i].id); + fprint(fd, "\n groups: "); + for(i = 0; i < us->ngroups; ++i) + fprint(fd, "%s:%d, ", us->groups[i].name, us->groups[i].id); + fprint(fd, "\n"); + } } -*/ static Filebuf * loadfile(char *name) @@ -152,10 +162,10 @@ np9users = 0; fb = loadfile("//adm/users"); - if(fb == nil) { -fprint(2, "unexpected no /adm/users\n"); + if(fb == nil) return; -} + if(p9users) + free(p9users); p9users = θmalloc(fb->nlines * sizeof(P9user)); for(i = 0; i < fb->nlines; ++i) { if(fb->lines[i][0] == '#') @@ -163,7 +173,7 @@ n = getfields(fb->lines[i], flds, MAXFIELDS, 0, ":,"); if(n < 3) continue; - if(flds[3] == nil || flds[3][0] == 0) + if(n == 3 || flds[3] == nil || flds[3][0] == 0) p9users[np9users].nmembers = 0; else p9users[np9users].nmembers = n - 3; @@ -171,7 +181,9 @@ p9users[np9users].name = estrdup9p(flds[1]); if(flds[2] && flds[2][0] != '\0') p9users[np9users].leader = estrdup9p(flds[2]); - p9users[np9users].members = θmalloc((n - 2) * sizeof(char *)); + else + p9users[np9users].leader = estrdup9p(flds[1]); + p9users[np9users].members = θmalloc((n - 3) * sizeof(char *)); for(j = 3; j < n; ++j) p9users[np9users].members[j-3] = estrdup9p(flds[j]); ++np9users; @@ -185,7 +197,7 @@ Filebuf *ufb, *gfb; Unixsys *us; char *flds[MAXFIELDS]; - int i, j, n; + int i, j, k, n; ufb = loadfile(toks[1]); if(ufb == nil) @@ -201,24 +213,36 @@ us->users = θmalloc(us->nusers *sizeof(Unixuser)); us->ngroups = gfb->nlines; us->groups = θmalloc(us->ngroups *sizeof(Unixgroup)); - for(i = 0; i < us->nusers; ++i) { + for(i = 0, k = 0; i < us->nusers; ++i) { + if(ufb->lines[i][0] == '#') + continue; n = getfields(ufb->lines[i], flds, MAXFIELDS, 0, ":"); if(n < 3) continue; - us->users[i].name = estrdup9p(flds[0]); - us->users[i].id = atoi(estrdup9p(flds[2])); + us->users[k].name = estrdup9p(flds[0]); + if(us->users[k].name == nil) + continue; + us->users[k].id = atoi(flds[2]); + ++k; } - for(i = 0; i < us->ngroups; ++i) { + us->nusers = k; + for(i = 0, k = 0; i < us->ngroups; ++i) { + if(gfb->lines[i][0] == '#') + continue; n = getfields(gfb->lines[i], flds, MAXFIELDS, 0, ":,"); if(n < 3) continue; - us->groups[i].name = estrdup9p(flds[0]); - us->groups[i].id = atoi(estrdup9p(flds[1])); - us->groups[i].nmembers = n - 3; - us->groups[i].members = θmalloc(us->groups[i].nmembers * sizeof(char *)); - for(j = 0; j < us->groups[i].nmembers; ++j) - us->groups[i].members[j] = estrdup9p(flds[j+3]); + us->groups[k].name = estrdup9p(flds[0]); + if(us->groups[k].name == nil) + continue; + us->groups[k].id = atoi(flds[2]); + us->groups[k].nmembers = n - 3; + us->groups[k].members = θmalloc(us->groups[k].nmembers * sizeof(char *)); + for(j = 0; j < us->groups[k].nmembers; ++j) + us->groups[k].members[j] = estrdup9p(flds[j+3]); + ++k; } + us->ngroups = k; freefile(ufb); freefile(gfb); return us; @@ -230,7 +254,7 @@ Filebuf *fb; Unixsys *us; char *toks[3]; - int i; + int i, j; loadusers(); @@ -238,6 +262,22 @@ fb = loadfile("//adm/nfs"); if(fb != nil) { + while(unixhd) { + us = unixhd; + unixhd = unixhd->next; + free(us->name); + for(i = 0; i < us->nusers; ++i) + free(us->users[i].name); + free(us->users); + for(i = 0; i < us->ngroups; ++i) { + free(us->groups[i].name); + for(j = 0; j < us->groups[i].nmembers; ++j) + free(us->groups[i].members[j]); + free(us->groups[i].members); + } + free(us->groups); + free(us); + } for(i = 0; i < fb->nlines; ++i) { tokenize(fb->lines[i], toks, 3); us = buildsys(toks); @@ -287,6 +327,8 @@ Unixsys *s; int i; + if(debugnfs) + fprint(2, "In id2uname sys=%s, id=%d\n", sys, id); for(s = unixhd; s && strcmp(s->name, sys) != 0; s = s->next) ; if(s == nil) return nil; @@ -296,6 +338,31 @@ return s->users[i].name; } +int +uname2id(char *sys, char *uname) +{ + Unixsys *s; + int i; + + if(debugnfs) + fprint(2, "in uname2id: sys=%s uname=%s\n", sys, uname); + for(s = unixhd; s && strcmp(s->name, sys) != 0; s = s->next) ; + if(s == nil) + return -2; + if(uname) { + for(i = 0; i < s->nusers && strcmp(s->users[i].name, uname) != 0; ++i) ; + if(i < s->nusers) + return s->users[i].id; + } + for(i = 0; i < s->nusers && strcmp(s->users[i].name, "nfsnobody") != 0; ++i) ; + if(i < s->nusers) + return s->users[i].id; + for(i = 0; i < s->nusers && strcmp(s->users[i].name, "nobody") != 0; ++i) ; + if(i < s->nusers) + return s->users[i].id; + return -2; +} + char * id2gname(char *sys, int id) { @@ -309,4 +376,29 @@ if(i >= s->ngroups) return nil; return s->groups[i].name; +} + +int +gname2id(char *sys, char *gname) +{ + Unixsys *s; + int i; + + if(debugnfs) + fprint(2, "In gname2id: sys=%s gname=%s\n", sys, gname); + for(s = unixhd; s && strcmp(s->name, sys) != 0; s = s->next) ; + if(s == nil) + return -2; + if(gname) { + for(i = 0; i < s->ngroups && strcmp(gname, s->groups[i].name) != 0; ++i) ; + if(i < s->ngroups) + return s->groups[i].id; + } + for(i = 0; i < s->ngroups && strcmp(s->groups[i].name, "nfsnobody") != 0; ++i) ; + if(i < s->ngroups) + return s->groups[i].id; + for(i = 0; i < s->ngroups && strcmp(s->groups[i].name, "nobody") != 0; ++i) ; + if(i < s->ngroups) + return s->groups[i].id; + return -2; } --- /sys/man/4/θfs Thu Jan 1 00:00:00 1970 +++ /sys/man/4/θfs Thu Feb 27 11:43:03 2014 @@ -0,0 +1,292 @@ +.TH ΘFS 4 +.SH NAME +θfs \- disk file system +.SH SYNOPSIS +.B θfs +[ +.B -anrsACD +] [ +.B -m +.I nblk +] [ +.B -p +.I port +] +.B device +.SH DESCRIPTION +.I Θfs +is a user-level file, block, and object storage server for Plan 9. +When used in conjunction with +.IR snap (3), +it can be used to provide the same functionality as fossil/venti +or the classic Plan 9 file server. +In addition to exporting its file system via 9P as with other Plan 9 +file servers, +.I θfs +also exports its file system via NFSv3. +Finally, +.I θfs +also provides access to block storage via the AoE protocol +and to object storage via an experimental object extension to AoE +.PP +The command-line arguments for +.I θfs +are definted as follows: +.TP +.I -a +Disable AoE functionality, both the bock and object support. +.TP +.I -n +Disable NFS functionality. +.TP +.I -m +Set the number of blocks to keep in the in-memory cache. +.TP +.I -p +Set the port number on which to listen for 9P connections. +.TP +.I -r +Reame the file system on start up. +.TP +.I -s +Read 9P messages from the standard input. +This is used when a system takes its root from a local instance of +.IR θfs . +.TP +.I -A +Update access times on reads. +.TP +.I -C +Post a console descriptor to +.BR /srv . +.TP +.I -D +Turn on 9P debugging. +.PP +.SH CONSOLE +.PP +When invoked with the +.IR -C option, θfs +posts a file descriptor to +.BR /srv/θfscons . +This console can be accessed by connecting to the descriptor with +the command: +.IP +.EX +con -C /srv/θfscons +.EE +.PP +This interactive console supports the following commands: +.TP +.I allow +Turns off permissions checking and allows +.IR wstat (5) +messages to change file ownerships. +.TP +.I blockuse +Looks up a specified block number and reports its role. +This is intended primarily for debugging purposes. +.TP +.I checkalloc +Scans the file system looking for inconsistancies in the block +allocation, reporting what it finds. +It also rebuilds the free block map. +.TP +.I cstat +Reports on in-memory block cache statistics. +.TP +.I disallow +Reinstates permissions checking and prohibits file ownership +changes. +.TP +.I dumpusers +Prints a list of all Plan 9 users and all NFS UID information +loaded either at start-up or by the +.I inituid +command. +.TP +.I fixfamilies +Scans the file system examining all parent/child/sibling +relationships and removes entries with no valid metadata. +.TP +.I fixpaths +Removes path names in the path hash table that do not +have valid metadata. +.TP +.I halt +Flushes all modified blocks from the cache and terminates +9P and NFS service. +.TP +.I help +Prints a list of the commands supported in the console and the +number of command arguments each uses. +.TP +.I hstat +Prints a summary of hash table statistics. +In particular, it reports on the number of bucket collisions and +maximum search depth encountered since start-up. +.TP +.I inituid +Reloads the Plan 9 user file +.B /adm/users +and the NFS UID mappings specified in +.BR /adm/nfs . +.TP +.I lcreate +Creates an AoE LUN with a specified AoE ID and size. +.TP +.I lls +Prints a list of AoE LUNs. +.TP +.I lmeta +Prints the metadata for the specified AoE LUN. +.TP +.I lrm +Removes the specified AoE LUN. +.TP +.I mpred +Locates the predecessor to the specified meatadatum in the +metadata list of which it's a part. +.TP +.I mprint +Prints the details of the specified metadatum. +.TP +.I mstat +Prints a summary of metadata statistics. +.TP +.I newroot +Creates a new file tree within the file system storage +space. +The file tree named +.B dump +has a special role for storing the file system's snapshot +history. +Named roots are accessible by way of the mount specifier +in 9P and as top-level directories in a virtual root in NFS. +.TP +.I nfsdebug +Prints the current debug level of NFS when invoked with no +arguments. +Otherwise, sets the NFS debug level to the specified value. +.TP +.I p2q +Looks up and prints the QID path value for the specified path +name. +.TP +.I p9debug +Sets the value of the +.B chatty9p +variable. +.TP +.I phash +Shows the bucket number and the location of the hash list +for the specified path name. +.TP +.I pmeta +Prints the metadata list for the specified path name. +.TP +.I q2m +Looks up and prints the index of the first metadatum for +the specified QID path. +.TP +.I qmeta +Prints the metadata list for the specified QID path. +.TP +.I recovermeta +Scans the file system and rebuilds the free list of metadata +entries. +.TP +.I revert +Reverses the effect of changes made since a specified snapshot. +The file system is rolled back in time to the point at which the +specified snapshot was taken. +.TP +.I rmp +Removes the specified path name from the path hash table. +.TP +.I rootallow +Gives UID 0 unchecked access over NFS according to traditional +UNIX superuser privileges. +.TP +.I rootdisallow +Treats UID 0 as though it were any normal user and enforces +permissions checking for it as such. +.TP +.I setmeta +Adds (or modifies) a metadatum for the specified QID path. +Its arguments are QID path, metadata type, name, and value. +.TP +.I setmstruct +Explicitly sets the fields of a specified metadatum. +Useful mostly to do very low-level repairs on a mangled file +system. +.TP +.I setqhash +Points a QID hash table entry to a specified metadatum. +.TP +.I snap +Creates a file system snapshot when using +.IR snap (3) +and when using a dump file system. +Snapshots are named in the same style as fossil and the +traditional Plan 9 file server. +Each year for which at least one shapshot exists has a directory +and each snapshot is a directory named +.B mmddn +where +.B mm +is the month, +.B dd +is the day on which the snapshot is taken. +For the first snapshot of the day, +.B n +is the empty string. +For subsequent snapsthots it takes on the values: 1, 2, ... 9. +.TP +.I super +Prints a summary of the file system super block. +.TP +.I sync +Flushes any modified blocks in the cache. +.SH EXAMPLES +Create a file system listening on port 1992 and mount it on +.BR /n/θfs . +.IP +.EX +% θfs -rCp1992 /dev/sdE0/data +% srv tcp!127.1!1992 θfs +% mount -c /srv/θfs /n/θfs +.EE +.PP +.SH FILES +.TF /adm/users +.TP +.B /adm/users +File containing Plan 9 user and group IDs. +.TP +.B /adm/nfs +File specifying the other files containing NFS client +UID to Plan 9 user name mappings. +.SH SOURCE +.B /sys/src/cmd/θfs +.SH "SEE ALSO" +.IR fossil (4), +.IR kfs (4), +.IR mkfs (8), +.IR prep (8), +.IR sd (3) +.SH BUGS +Certainly numerous: +.TF \(bu +.IP \(bu +The mechanism for implementing daily snapshots is ugly and +there's no current way to set the time of day when this is +done. +.IP \(bu +The block and object storage support has had precious little testing. +.IP \(bu +The default cache size should be computed as a percentage of +the use memory space, rather than being a hard coded number of blocks. +.IP \(bu +Although performance has not yet been an issue, no significant effort +has yet gone into improving it.