support nfs exporting sysctlfs. it is now possible to manage the

sysctl tree for a host over nfs (for however megaexciting that is)
This commit is contained in:
pooka 2007-04-11 21:08:52 +00:00
parent 3e65ff17b5
commit 5af002af7d
1 changed files with 142 additions and 36 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysctlfs.c,v 1.15 2007/02/16 16:39:56 pooka Exp $ */
/* $NetBSD: sysctlfs.c,v 1.16 2007/04/11 21:08:52 pooka Exp $ */
/*
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
@ -57,9 +57,14 @@ struct sfsnode {
#define SFSPATH_DOTDOT 0
#define SFSPATH_NORMAL 1
#define N_HIERARCHY 16
#define N_HIERARCHY 10
typedef int SfsName[N_HIERARCHY];
struct sfsfid {
int len;
SfsName path;
};
struct sfsnode rn;
SfsName sname_root;
struct timespec fstime;
@ -139,6 +144,69 @@ sysctlfs_pathfree(struct puffs_usermount *pu, struct puffs_pathobj *po)
free(po->po_path);
}
static struct puffs_node *
getnode(struct puffs_usermount *pu, struct puffs_pathobj *po, int nodetype)
{
struct sysctlnode sn[SFS_NODEPERDIR];
struct sysctlnode qnode;
struct puffs_node *pn;
struct sfsnode *sfs;
SfsName myname, *sname;
size_t sl;
int i;
/*
* Check if we need to create a new in-memory node or if we
* already have one for this path. Shortcut for the rootnode.
* Also, memcmp against zero-length would be quite true always.
*/
if (po->po_len == 0)
pn = pu->pu_pn_root;
else
pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp, po);
if (pn == NULL) {
/*
* don't know nodetype? query...
*
* XXX1: nothing really guarantees 0 is an invalid nodetype
* XXX2: is there really no easier way of doing this? we
* know the whole mib path
*/
if (!nodetype) {
sname = po->po_path;
memcpy(myname, po->po_path, po->po_len * sizeof(int));
memset(&qnode, 0, sizeof(qnode));
qnode.sysctl_flags = SYSCTL_VERSION;
myname[po->po_len-1] = CTL_QUERY;
sl = sizeof(sn);
if (sysctl(myname, po->po_len, sn, &sl,
&qnode, sizeof(qnode)) == -1)
abort();
for (i = 0; i < sl / sizeof(struct sysctlnode); i++) {
if (sn[i].sysctl_num==(*sname)[po->po_len-1]) {
nodetype = sn[i].sysctl_flags;
break;
}
}
if (!nodetype)
return NULL;
}
sfs = emalloc(sizeof(struct sfsnode));
sfs->sysctl_flags = nodetype;
sfs->myid = nextid++;
pn = puffs_pn_new(pu, sfs);
assert(pn);
}
return pn;
}
int
main(int argc, char *argv[])
{
@ -169,7 +237,8 @@ main(int argc, char *argv[])
}
argv += optind;
argc -= optind;
pflags |= PUFFS_FLAG_BUILDPATH | PUFFS_KFLAG_NOCACHE;
pflags |= PUFFS_FLAG_BUILDPATH | PUFFS_KFLAG_NOCACHE
| PUFFS_KFLAG_CANEXPORT;
if (pflags & PUFFS_FLAG_OPDUMP)
lflags |= PUFFSLOOP_NODAEMON;
@ -182,6 +251,8 @@ main(int argc, char *argv[])
PUFFSOP_SETFSNOP(pops, unmount);
PUFFSOP_SETFSNOP(pops, sync);
PUFFSOP_SETFSNOP(pops, statvfs);
PUFFSOP_SET(pops, sysctlfs, fs, nodetofh);
PUFFSOP_SET(pops, sysctlfs, fs, fhtonode);
PUFFSOP_SET(pops, sysctlfs, node, lookup);
PUFFSOP_SET(pops, sysctlfs, node, getattr);
@ -235,6 +306,52 @@ sysctlfs_domount(struct puffs_usermount *pu)
return 0;
}
int
sysctlfs_fs_fhtonode(struct puffs_cc *pcc, void *fid, size_t fidsize,
void **fcookie, enum vtype *ftype, voff_t *fsize, dev_t *fdev)
{
struct puffs_pathobj po;
struct puffs_node *pn;
struct sfsnode *sfs;
struct sfsfid *sfid;
/* XXX: fidsize */
sfid = fid;
po.po_len = sfid->len;
po.po_path = &sfid->path;
pn = getnode(puffs_cc_getusermount(pcc), &po, 0);
if (pn == NULL)
return EINVAL;
sfs = pn->pn_data;
*fcookie = pn;
if (ISADIR(sfs))
*ftype = VDIR;
else
*ftype = VREG;
return 0;
}
int
sysctlfs_fs_nodetofh(struct puffs_cc *pcc, void *cookie,
void *fid, size_t *fidsize)
{
struct puffs_node *pn = cookie;
struct sfsfid *sfid;
/* XXX: fidsize */
sfid = fid;
sfid->len = PNPLEN(pn);
memcpy(&sfid->path, PNPATH(pn), sfid->len * sizeof(int));
return 0;
}
static void
doprint(struct sfsnode *sfs, struct puffs_pathobj *po,
char *buf, size_t bufsize)
@ -322,13 +439,12 @@ sysctlfs_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
struct puffs_cn *p2cn = __UNCONST(pcn); /* XXX: fix the interface */
struct sysctlnode sn[SFS_NODEPERDIR];
struct sysctlnode qnode;
struct puffs_pathobj po;
struct puffs_node *pn_dir = opc;
struct puffs_node *pn_new;
struct sfsnode *sfs_dir = pn_dir->pn_data, *sfs_new;
SfsName *sname = PCNPATH(pcn);
size_t sl;
int i;
int i, nodetype;
assert(ISADIR(sfs_dir));
@ -354,35 +470,12 @@ sysctlfs_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
(*sname)[PCNPLEN(pcn)] = sn[i].sysctl_num;
p2cn->pcn_po_full.po_len++;
}
nodetype = sn[i].sysctl_flags;
} else
nodetype = CTLTYPE_NODE;
/*
* Check if we need to create a new in-memory node or if we
* already have one for this path. Shortcut for the rootnode.
* Also, memcmp against zero-length would be quite true always.
*/
if (PCNPLEN(pcn) == 0) {
pn_new = pu->pu_pn_root;
} else {
po.po_path = sname;
po.po_len = PCNPLEN(pcn);
pn_new = puffs_pn_nodewalk(puffs_cc_getusermount(pcc),
puffs_path_walkcmp, &po);
}
if (pn_new != NULL) {
sfs_new = pn_new->pn_data;
} else {
sfs_new = emalloc(sizeof(struct sfsnode));
if (PCNISDOTDOT(pcn))
sfs_new->sysctl_flags = CTLTYPE_NODE;
else
sfs_new->sysctl_flags = sn[i].sysctl_flags;
sfs_new->myid = nextid++;
pn_new = puffs_pn_new(puffs_cc_getusermount(pcc), sfs_new);
assert(pn_new != NULL);
}
pn_new = getnode(pu, &p2cn->pcn_po_full, nodetype);
sfs_new = pn_new->pn_data;
*newnode = pn_new;
if (ISADIR(sfs_new))
@ -433,9 +526,9 @@ sysctlfs_node_setattr(struct puffs_cc *pcc, void *opc,
}
int
sysctlfs_node_readdir(struct puffs_cc *pcc, void *opc,
struct dirent *dent, const struct puffs_cred *pcr,
off_t *readoff, size_t *reslen)
sysctlfs_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent,
off_t *readoff, size_t *reslen, const struct puffs_cred *pcr,
int *eofflag, off_t *cookies, size_t *ncookies)
{
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
struct sysctlnode sn[SFS_NODEPERDIR];
@ -450,9 +543,16 @@ sysctlfs_node_readdir(struct puffs_cc *pcc, void *opc,
ino_t id;
int i;
if (cookies)
*ncookies = 0;
again:
if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) {
puffs_gendotdent(&dent, sfs_dir->myid, *readoff, reslen);
if (cookies) {
*(cookies++) = *readoff;
(*ncookies)++;
}
(*readoff)++;
goto again;
}
@ -494,8 +594,14 @@ sysctlfs_node_readdir(struct puffs_cc *pcc, void *opc,
if (!puffs_nextdent(&dent, sn[i].sysctl_name, id,
puffs_vtype2dt(vt), reslen))
return 0;
if (cookies) {
*(cookies++) = *readoff;
(*ncookies)++;
}
}
*eofflag = 1;
return 0;
}