Home | History | Annotate | Line # | Download | only in mount_sysctlfs
sysctlfs.c revision 1.2
      1  1.2  pooka /*	$NetBSD: sysctlfs.c,v 1.2 2007/08/09 22:03:20 pooka Exp $	*/
      2  1.1  pooka 
      3  1.1  pooka /*
      4  1.1  pooka  * Copyright (c) 2006, 2007  Antti Kantee.  All Rights Reserved.
      5  1.1  pooka  *
      6  1.1  pooka  * Redistribution and use in source and binary forms, with or without
      7  1.1  pooka  * modification, are permitted provided that the following conditions
      8  1.1  pooka  * are met:
      9  1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     10  1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     11  1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  pooka  *    documentation and/or other materials provided with the distribution.
     14  1.1  pooka  *
     15  1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16  1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  1.1  pooka  * SUCH DAMAGE.
     26  1.1  pooka  */
     27  1.1  pooka 
     28  1.1  pooka /*
     29  1.1  pooka  * sysctlfs: mount sysctls as a file system tree.  Supports query and
     30  1.1  pooka  * modify of nodes in the sysctl namespace in addition to namespace
     31  1.1  pooka  * traversal.
     32  1.1  pooka  */
     33  1.1  pooka 
     34  1.2  pooka #include <sys/cdefs.h>
     35  1.2  pooka #ifndef lint
     36  1.2  pooka __RCSID("$NetBSD: sysctlfs.c,v 1.2 2007/08/09 22:03:20 pooka Exp $");
     37  1.2  pooka #endif /* !lint */
     38  1.2  pooka 
     39  1.1  pooka #include <sys/types.h>
     40  1.1  pooka #include <sys/sysctl.h>
     41  1.1  pooka 
     42  1.1  pooka #include <assert.h>
     43  1.1  pooka #include <err.h>
     44  1.1  pooka #include <errno.h>
     45  1.1  pooka #include <mntopts.h>
     46  1.1  pooka #include <paths.h>
     47  1.1  pooka #include <puffs.h>
     48  1.1  pooka #include <stdlib.h>
     49  1.1  pooka #include <string.h>
     50  1.1  pooka #include <unistd.h>
     51  1.1  pooka #include <util.h>
     52  1.1  pooka 
     53  1.1  pooka PUFFSOP_PROTOS(sysctlfs)
     54  1.1  pooka 
     55  1.1  pooka struct sfsnode {
     56  1.1  pooka 	int sysctl_flags;
     57  1.1  pooka 	ino_t myid;
     58  1.1  pooka };
     59  1.1  pooka 
     60  1.1  pooka #define SFSPATH_DOTDOT 0
     61  1.1  pooka #define SFSPATH_NORMAL 1
     62  1.1  pooka 
     63  1.1  pooka #define N_HIERARCHY 10
     64  1.1  pooka typedef int SfsName[N_HIERARCHY];
     65  1.1  pooka 
     66  1.1  pooka struct sfsfid {
     67  1.1  pooka 	int len;
     68  1.1  pooka 	SfsName path;
     69  1.1  pooka };
     70  1.1  pooka 
     71  1.1  pooka struct sfsnode rn;
     72  1.1  pooka SfsName sname_root;
     73  1.1  pooka struct timespec fstime;
     74  1.1  pooka 
     75  1.1  pooka ino_t nextid = 3;
     76  1.1  pooka 
     77  1.1  pooka #define ISADIR(a) ((SYSCTL_TYPE(a->sysctl_flags) == CTLTYPE_NODE))
     78  1.1  pooka #define SFS_MAXFILE 8192
     79  1.1  pooka #define SFS_NODEPERDIR 128
     80  1.1  pooka 
     81  1.1  pooka static int sysctlfs_domount(struct puffs_usermount *);
     82  1.1  pooka 
     83  1.1  pooka /*
     84  1.1  pooka  * build paths.  doesn't support rename (but neither does the fs)
     85  1.1  pooka  */
     86  1.1  pooka static int
     87  1.1  pooka sysctlfs_pathbuild(struct puffs_usermount *pu,
     88  1.1  pooka 	const struct puffs_pathobj *parent, const struct puffs_pathobj *comp,
     89  1.1  pooka 	size_t offset, struct puffs_pathobj *res)
     90  1.1  pooka {
     91  1.1  pooka 	SfsName *sname;
     92  1.1  pooka 	size_t clen;
     93  1.1  pooka 
     94  1.1  pooka 	assert(parent->po_len < N_HIERARCHY); /* code uses +1 */
     95  1.1  pooka 
     96  1.1  pooka 	sname = malloc(sizeof(SfsName));
     97  1.1  pooka 	assert(sname != NULL);
     98  1.1  pooka 
     99  1.1  pooka 	clen = parent->po_len;
    100  1.1  pooka 	if (comp->po_len == SFSPATH_DOTDOT) {
    101  1.1  pooka 		assert(clen != 0);
    102  1.1  pooka 		clen--;
    103  1.1  pooka 	}
    104  1.1  pooka 
    105  1.1  pooka 	memcpy(sname, parent->po_path, clen * sizeof(int));
    106  1.1  pooka 
    107  1.1  pooka 	res->po_path = sname;
    108  1.1  pooka 	res->po_len = clen;
    109  1.1  pooka 
    110  1.1  pooka 	return 0;
    111  1.1  pooka }
    112  1.1  pooka 
    113  1.1  pooka static int
    114  1.1  pooka sysctlfs_pathtransform(struct puffs_usermount *pu,
    115  1.1  pooka 	const struct puffs_pathobj *p, const const struct puffs_cn *pcn,
    116  1.1  pooka 	struct puffs_pathobj *res)
    117  1.1  pooka {
    118  1.1  pooka 
    119  1.1  pooka 	res->po_path = NULL;
    120  1.1  pooka 	/*
    121  1.1  pooka 	 * XXX: overload.  prevents us from doing rename, but the fs
    122  1.1  pooka 	 * (and sysctl(3)) doesn't support it, so no biggie
    123  1.1  pooka 	 */
    124  1.1  pooka 	if (PCNISDOTDOT(pcn)) {
    125  1.1  pooka 		res->po_len = SFSPATH_DOTDOT;
    126  1.1  pooka 	}else {
    127  1.1  pooka 		res->po_len = SFSPATH_NORMAL;
    128  1.1  pooka 	}
    129  1.1  pooka 
    130  1.1  pooka 	return 0;
    131  1.1  pooka }
    132  1.1  pooka 
    133  1.1  pooka static int
    134  1.1  pooka sysctlfs_pathcmp(struct puffs_usermount *pu, struct puffs_pathobj *po1,
    135  1.1  pooka 	struct puffs_pathobj *po2, size_t clen, int checkprefix)
    136  1.1  pooka {
    137  1.1  pooka 
    138  1.1  pooka 	if (memcmp(po1->po_path, po2->po_path, clen * sizeof(int)) == 0)
    139  1.1  pooka 		return 0;
    140  1.1  pooka 	return 1;
    141  1.1  pooka }
    142  1.1  pooka 
    143  1.1  pooka static void
    144  1.1  pooka sysctlfs_pathfree(struct puffs_usermount *pu, struct puffs_pathobj *po)
    145  1.1  pooka {
    146  1.1  pooka 
    147  1.1  pooka 	free(po->po_path);
    148  1.1  pooka }
    149  1.1  pooka 
    150  1.1  pooka static struct puffs_node *
    151  1.1  pooka getnode(struct puffs_usermount *pu, struct puffs_pathobj *po, int nodetype)
    152  1.1  pooka {
    153  1.1  pooka 	struct sysctlnode sn[SFS_NODEPERDIR];
    154  1.1  pooka 	struct sysctlnode qnode;
    155  1.1  pooka 	struct puffs_node *pn;
    156  1.1  pooka 	struct sfsnode *sfs;
    157  1.1  pooka 	SfsName myname, *sname;
    158  1.1  pooka 	size_t sl;
    159  1.1  pooka 	int i;
    160  1.1  pooka 
    161  1.1  pooka 	/*
    162  1.1  pooka 	 * Check if we need to create a new in-memory node or if we
    163  1.1  pooka 	 * already have one for this path.  Shortcut for the rootnode.
    164  1.1  pooka 	 * Also, memcmp against zero-length would be quite true always.
    165  1.1  pooka 	 */
    166  1.1  pooka 	if (po->po_len == 0)
    167  1.1  pooka 		pn = puffs_getroot(pu);
    168  1.1  pooka 	else
    169  1.1  pooka 		pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp, po);
    170  1.1  pooka 
    171  1.1  pooka 	if (pn == NULL) {
    172  1.1  pooka 		/*
    173  1.1  pooka 		 * don't know nodetype?  query...
    174  1.1  pooka 		 *
    175  1.1  pooka 		 * XXX1: nothing really guarantees 0 is an invalid nodetype
    176  1.1  pooka 		 * XXX2: is there really no easier way of doing this?  we
    177  1.1  pooka 		 *       know the whole mib path
    178  1.1  pooka 		 */
    179  1.1  pooka 		if (!nodetype) {
    180  1.1  pooka 			sname = po->po_path;
    181  1.1  pooka 			memcpy(myname, po->po_path, po->po_len * sizeof(int));
    182  1.1  pooka 
    183  1.1  pooka 			memset(&qnode, 0, sizeof(qnode));
    184  1.1  pooka 			qnode.sysctl_flags = SYSCTL_VERSION;
    185  1.1  pooka 			myname[po->po_len-1] = CTL_QUERY;
    186  1.1  pooka 
    187  1.1  pooka 			sl = sizeof(sn);
    188  1.1  pooka 			if (sysctl(myname, po->po_len, sn, &sl,
    189  1.1  pooka 			    &qnode, sizeof(qnode)) == -1)
    190  1.1  pooka 				abort();
    191  1.1  pooka 
    192  1.1  pooka 			for (i = 0; i < sl / sizeof(struct sysctlnode); i++) {
    193  1.1  pooka 				 if (sn[i].sysctl_num==(*sname)[po->po_len-1]) {
    194  1.1  pooka 					nodetype = sn[i].sysctl_flags;
    195  1.1  pooka 					break;
    196  1.1  pooka 				}
    197  1.1  pooka 			}
    198  1.1  pooka 			if (!nodetype)
    199  1.1  pooka 				return NULL;
    200  1.1  pooka 		}
    201  1.1  pooka 
    202  1.1  pooka 		sfs = emalloc(sizeof(struct sfsnode));
    203  1.1  pooka 		sfs->sysctl_flags = nodetype;
    204  1.1  pooka 		sfs->myid = nextid++;
    205  1.1  pooka 
    206  1.1  pooka 		pn = puffs_pn_new(pu, sfs);
    207  1.1  pooka 		assert(pn);
    208  1.1  pooka 	}
    209  1.1  pooka 
    210  1.1  pooka 	return pn;
    211  1.1  pooka }
    212  1.1  pooka 
    213  1.1  pooka int
    214  1.1  pooka main(int argc, char *argv[])
    215  1.1  pooka {
    216  1.1  pooka 	struct puffs_usermount *pu;
    217  1.1  pooka 	struct puffs_ops *pops;
    218  1.1  pooka 	mntoptparse_t mp;
    219  1.1  pooka 	int mntflags, pflags, lflags;
    220  1.1  pooka 	int ch;
    221  1.1  pooka 
    222  1.1  pooka 	setprogname(argv[0]);
    223  1.1  pooka 
    224  1.1  pooka 	if (argc < 2)
    225  1.1  pooka 		errx(1, "usage: %s sysctlfs [-o mntopts]mountpath",
    226  1.1  pooka 		    getprogname());
    227  1.1  pooka 
    228  1.1  pooka 	mntflags = pflags = lflags = 0;
    229  1.1  pooka 	while ((ch = getopt(argc, argv, "o:s")) != -1) {
    230  1.1  pooka 		switch (ch) {
    231  1.1  pooka 		case 'o':
    232  1.1  pooka 			mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags);
    233  1.1  pooka 			if (mp == NULL)
    234  1.1  pooka 				err(1, "getmntopts");
    235  1.1  pooka 			freemntopts(mp);
    236  1.1  pooka 			break;
    237  1.1  pooka 		case 's':
    238  1.1  pooka 			lflags = PUFFSLOOP_NODAEMON;
    239  1.1  pooka 			break;
    240  1.1  pooka 		}
    241  1.1  pooka 	}
    242  1.1  pooka 	argv += optind;
    243  1.1  pooka 	argc -= optind;
    244  1.1  pooka 	pflags |= PUFFS_FLAG_BUILDPATH | PUFFS_KFLAG_NOCACHE;
    245  1.1  pooka 
    246  1.1  pooka 	if (pflags & PUFFS_FLAG_OPDUMP)
    247  1.1  pooka 		lflags |= PUFFSLOOP_NODAEMON;
    248  1.1  pooka 
    249  1.1  pooka 	if (argc != 2)
    250  1.1  pooka 		errx(1, "usage: %s [-o mntopts]mountpath", getprogname());
    251  1.1  pooka 
    252  1.1  pooka 	PUFFSOP_INIT(pops);
    253  1.1  pooka 
    254  1.1  pooka 	PUFFSOP_SETFSNOP(pops, unmount);
    255  1.1  pooka 	PUFFSOP_SETFSNOP(pops, sync);
    256  1.1  pooka 	PUFFSOP_SETFSNOP(pops, statvfs);
    257  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, fs, nodetofh);
    258  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, fs, fhtonode);
    259  1.1  pooka 
    260  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, lookup);
    261  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, getattr);
    262  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, setattr);
    263  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, readdir);
    264  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, read);
    265  1.1  pooka 	PUFFSOP_SET(pops, sysctlfs, node, write);
    266  1.1  pooka 	PUFFSOP_SET(pops, puffs_genfs, node, reclaim);
    267  1.1  pooka 
    268  1.1  pooka 	pu = puffs_init(pops, _PATH_PUFFS, "sysctlfs", NULL, pflags);
    269  1.1  pooka 	if (pu == NULL)
    270  1.1  pooka 		err(1, "puffs_init");
    271  1.1  pooka 
    272  1.1  pooka 	puffs_set_pathbuild(pu, sysctlfs_pathbuild);
    273  1.1  pooka 	puffs_set_pathtransform(pu, sysctlfs_pathtransform);
    274  1.1  pooka 	puffs_set_pathcmp(pu, sysctlfs_pathcmp);
    275  1.1  pooka 	puffs_set_pathfree(pu, sysctlfs_pathfree);
    276  1.1  pooka 
    277  1.1  pooka 	puffs_setfhsize(pu, sizeof(struct sfsfid), PUFFS_FHFLAG_NFSV3);
    278  1.1  pooka 
    279  1.1  pooka 	if (sysctlfs_domount(pu) != 0)
    280  1.1  pooka 		errx(1, "domount");
    281  1.1  pooka 
    282  1.1  pooka 	if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1)
    283  1.1  pooka 		err(1, "puffs_mount");
    284  1.1  pooka 
    285  1.1  pooka 	if (puffs_mainloop(pu, lflags) == -1)
    286  1.1  pooka 		err(1, "mainloop");
    287  1.1  pooka 
    288  1.1  pooka 	return 0;
    289  1.1  pooka }
    290  1.1  pooka 
    291  1.1  pooka static int
    292  1.1  pooka sysctlfs_domount(struct puffs_usermount *pu)
    293  1.1  pooka {
    294  1.1  pooka 	struct puffs_pathobj *po_root;
    295  1.1  pooka 	struct puffs_node *pn_root;
    296  1.1  pooka 	struct timeval tv_now;
    297  1.1  pooka 
    298  1.1  pooka 	rn.myid = 2;
    299  1.1  pooka 	rn.sysctl_flags = CTLTYPE_NODE;
    300  1.1  pooka 
    301  1.1  pooka 	gettimeofday(&tv_now, NULL);
    302  1.1  pooka 	TIMEVAL_TO_TIMESPEC(&tv_now, &fstime);
    303  1.1  pooka 
    304  1.1  pooka 	pn_root = puffs_pn_new(pu, &rn);
    305  1.1  pooka 	assert(pn_root != NULL);
    306  1.1  pooka 	puffs_setroot(pu, pn_root);
    307  1.1  pooka 
    308  1.1  pooka 	po_root = puffs_getrootpathobj(pu);
    309  1.1  pooka 	po_root->po_path = &sname_root;
    310  1.1  pooka 	po_root->po_len = 0;
    311  1.1  pooka 
    312  1.1  pooka 	return 0;
    313  1.1  pooka }
    314  1.1  pooka 
    315  1.1  pooka int
    316  1.1  pooka sysctlfs_fs_fhtonode(struct puffs_cc *pcc, void *fid, size_t fidsize,
    317  1.1  pooka 	struct puffs_newinfo *pni)
    318  1.1  pooka {
    319  1.1  pooka 	struct puffs_pathobj po;
    320  1.1  pooka 	struct puffs_node *pn;
    321  1.1  pooka 	struct sfsnode *sfs;
    322  1.1  pooka 	struct sfsfid *sfid;
    323  1.1  pooka 
    324  1.1  pooka 	sfid = fid;
    325  1.1  pooka 
    326  1.1  pooka 	po.po_len = sfid->len;
    327  1.1  pooka 	po.po_path = &sfid->path;
    328  1.1  pooka 
    329  1.1  pooka 	pn = getnode(puffs_cc_getusermount(pcc), &po, 0);
    330  1.1  pooka 	if (pn == NULL)
    331  1.1  pooka 		return EINVAL;
    332  1.1  pooka 	sfs = pn->pn_data;
    333  1.1  pooka 
    334  1.1  pooka 	puffs_newinfo_setcookie(pni, pn);
    335  1.1  pooka 	if (ISADIR(sfs))
    336  1.1  pooka 		puffs_newinfo_setvtype(pni, VDIR);
    337  1.1  pooka 	else
    338  1.1  pooka 		puffs_newinfo_setvtype(pni, VREG);
    339  1.1  pooka 
    340  1.1  pooka 	return 0;
    341  1.1  pooka }
    342  1.1  pooka 
    343  1.1  pooka int
    344  1.1  pooka sysctlfs_fs_nodetofh(struct puffs_cc *pcc, void *cookie,
    345  1.1  pooka 	void *fid, size_t *fidsize)
    346  1.1  pooka {
    347  1.1  pooka 	struct puffs_node *pn = cookie;
    348  1.1  pooka 	struct sfsfid *sfid;
    349  1.1  pooka 
    350  1.1  pooka 	sfid = fid;
    351  1.1  pooka 	sfid->len = PNPLEN(pn);
    352  1.1  pooka 	memcpy(&sfid->path, PNPATH(pn), sfid->len * sizeof(int));
    353  1.1  pooka 
    354  1.1  pooka 	return 0;
    355  1.1  pooka }
    356  1.1  pooka 
    357  1.1  pooka static void
    358  1.1  pooka doprint(struct sfsnode *sfs, struct puffs_pathobj *po,
    359  1.1  pooka 	char *buf, size_t bufsize)
    360  1.1  pooka {
    361  1.1  pooka 	size_t sz;
    362  1.1  pooka 
    363  1.1  pooka 	assert(!ISADIR(sfs));
    364  1.1  pooka 
    365  1.1  pooka 	memset(buf, 0, bufsize);
    366  1.1  pooka 	switch (SYSCTL_TYPE(sfs->sysctl_flags)) {
    367  1.1  pooka 	case CTLTYPE_INT: {
    368  1.1  pooka 		int i;
    369  1.1  pooka 		sz = sizeof(int);
    370  1.1  pooka 		if (sysctl(po->po_path, po->po_len, &i, &sz, NULL, 0) == -1)
    371  1.1  pooka 			break;
    372  1.1  pooka 		snprintf(buf, bufsize, "%d", i);
    373  1.1  pooka 		break;
    374  1.1  pooka 	}
    375  1.1  pooka 	case CTLTYPE_QUAD: {
    376  1.1  pooka 		quad_t q;
    377  1.1  pooka 		sz = sizeof(q);
    378  1.1  pooka 		if (sysctl(po->po_path, po->po_len, &q, &sz, NULL, 0) == -1)
    379  1.1  pooka 			break;
    380  1.1  pooka 		snprintf(buf, bufsize, "%" PRId64, q);
    381  1.1  pooka 		break;
    382  1.1  pooka 	}
    383  1.1  pooka 	case CTLTYPE_STRUCT:
    384  1.1  pooka 		snprintf(buf, bufsize, "CTLTYPE_STRUCT: implement me and "
    385  1.1  pooka 		    "score a cookie");
    386  1.1  pooka 		break;
    387  1.1  pooka 	case CTLTYPE_STRING: {
    388  1.1  pooka 		sz = bufsize;
    389  1.1  pooka 		if (sysctl(po->po_path, po->po_len, buf, &sz, NULL, 0) == -1)
    390  1.1  pooka 			break;
    391  1.1  pooka 		break;
    392  1.1  pooka 	}
    393  1.1  pooka 	default:
    394  1.1  pooka 		snprintf(buf, bufsize, "invalid sysctl CTLTYPE");
    395  1.1  pooka 		break;
    396  1.1  pooka 	}
    397  1.1  pooka }
    398  1.1  pooka 
    399  1.1  pooka static int
    400  1.1  pooka getlinks(struct sfsnode *sfs, struct puffs_pathobj *po)
    401  1.1  pooka {
    402  1.1  pooka 	struct sysctlnode sn[SFS_NODEPERDIR];
    403  1.1  pooka 	struct sysctlnode qnode;
    404  1.1  pooka 	SfsName *sname;
    405  1.1  pooka 	size_t sl;
    406  1.1  pooka 
    407  1.1  pooka 	if (!ISADIR(sfs))
    408  1.1  pooka 		return 1;
    409  1.1  pooka 
    410  1.1  pooka 	memset(&qnode, 0, sizeof(qnode));
    411  1.1  pooka 	sl = sizeof(sn);
    412  1.1  pooka 	qnode.sysctl_flags = SYSCTL_VERSION;
    413  1.1  pooka 	sname = po->po_path;
    414  1.1  pooka 	(*sname)[po->po_len] = CTL_QUERY;
    415  1.1  pooka 
    416  1.1  pooka 	if (sysctl(*sname, po->po_len + 1, sn, &sl,
    417  1.1  pooka 	    &qnode, sizeof(qnode)) == -1)
    418  1.1  pooka 		return 0;
    419  1.1  pooka 
    420  1.1  pooka 	return (sl / sizeof(sn[0])) + 2;
    421  1.1  pooka }
    422  1.1  pooka 
    423  1.1  pooka static int
    424  1.1  pooka getsize(struct sfsnode *sfs, struct puffs_pathobj *po)
    425  1.1  pooka {
    426  1.1  pooka 	char buf[SFS_MAXFILE];
    427  1.1  pooka 
    428  1.1  pooka 	if (ISADIR(sfs))
    429  1.1  pooka 		return getlinks(sfs, po) * 16; /* totally arbitrary */
    430  1.1  pooka 
    431  1.1  pooka 	doprint(sfs, po, buf, sizeof(buf));
    432  1.1  pooka 	return strlen(buf) + 1;
    433  1.1  pooka }
    434  1.1  pooka 
    435  1.1  pooka int
    436  1.1  pooka sysctlfs_node_lookup(struct puffs_cc *pcc, void *opc, struct puffs_newinfo *pni,
    437  1.1  pooka 	const struct puffs_cn *pcn)
    438  1.1  pooka {
    439  1.1  pooka 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
    440  1.1  pooka 	struct puffs_cn *p2cn = __UNCONST(pcn); /* XXX: fix the interface */
    441  1.1  pooka 	struct sysctlnode sn[SFS_NODEPERDIR];
    442  1.1  pooka 	struct sysctlnode qnode;
    443  1.1  pooka 	struct puffs_node *pn_dir = opc;
    444  1.1  pooka 	struct puffs_node *pn_new;
    445  1.1  pooka 	struct sfsnode *sfs_dir = pn_dir->pn_data, *sfs_new;
    446  1.1  pooka 	SfsName *sname = PCNPATH(pcn);
    447  1.1  pooka 	size_t sl;
    448  1.1  pooka 	int i, nodetype;
    449  1.1  pooka 
    450  1.1  pooka 	assert(ISADIR(sfs_dir));
    451  1.1  pooka 
    452  1.1  pooka 	/*
    453  1.1  pooka 	 * If we're looking for dotdot, we already have the entire pathname
    454  1.1  pooka 	 * in sname, courtesy of pathbuild, so we can skip this step.
    455  1.1  pooka 	 */
    456  1.1  pooka 	if (!PCNISDOTDOT(pcn)) {
    457  1.1  pooka 		memset(&qnode, 0, sizeof(qnode));
    458  1.1  pooka 		sl = SFS_NODEPERDIR * sizeof(struct sysctlnode);
    459  1.1  pooka 		qnode.sysctl_flags = SYSCTL_VERSION;
    460  1.1  pooka 		(*sname)[PCNPLEN(pcn)] = CTL_QUERY;
    461  1.1  pooka 
    462  1.1  pooka 		if (sysctl(*sname, PCNPLEN(pcn) + 1, sn, &sl,
    463  1.1  pooka 		    &qnode, sizeof(qnode)) == -1)
    464  1.1  pooka 			return ENOENT;
    465  1.1  pooka 
    466  1.1  pooka 		for (i = 0; i < sl / sizeof(struct sysctlnode); i++)
    467  1.1  pooka 			if (strcmp(sn[i].sysctl_name, pcn->pcn_name) == 0)
    468  1.1  pooka 				break;
    469  1.1  pooka 		if (i == sl / sizeof(struct sysctlnode))
    470  1.1  pooka 			return ENOENT;
    471  1.1  pooka 
    472  1.1  pooka 		(*sname)[PCNPLEN(pcn)] = sn[i].sysctl_num;
    473  1.1  pooka 		p2cn->pcn_po_full.po_len++;
    474  1.1  pooka 		nodetype = sn[i].sysctl_flags;
    475  1.1  pooka 	} else
    476  1.1  pooka 		nodetype = CTLTYPE_NODE;
    477  1.1  pooka 
    478  1.1  pooka 	pn_new = getnode(pu, &p2cn->pcn_po_full, nodetype);
    479  1.1  pooka 	sfs_new = pn_new->pn_data;
    480  1.1  pooka 
    481  1.1  pooka 	puffs_newinfo_setcookie(pni, pn_new);
    482  1.1  pooka 	if (ISADIR(sfs_new))
    483  1.1  pooka 		puffs_newinfo_setvtype(pni, VDIR);
    484  1.1  pooka 	else
    485  1.1  pooka 		puffs_newinfo_setvtype(pni, VREG);
    486  1.1  pooka 
    487  1.1  pooka 	return 0;
    488  1.1  pooka }
    489  1.1  pooka 
    490  1.1  pooka int
    491  1.1  pooka sysctlfs_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
    492  1.1  pooka 	const struct puffs_cred *pcr, const struct puffs_cid *pcid)
    493  1.1  pooka {
    494  1.1  pooka 	struct puffs_node *pn = opc;
    495  1.1  pooka 	struct sfsnode *sfs = pn->pn_data;
    496  1.1  pooka 
    497  1.1  pooka 	memset(va, 0, sizeof(struct vattr));
    498  1.1  pooka 
    499  1.1  pooka 	if (ISADIR(sfs)) {
    500  1.1  pooka 		va->va_type = VDIR;
    501  1.1  pooka 		va->va_mode = 0777;
    502  1.1  pooka 	} else {
    503  1.1  pooka 		va->va_type = VREG;
    504  1.1  pooka 		va->va_mode = 0666;
    505  1.1  pooka 	}
    506  1.1  pooka 	va->va_nlink = getlinks(sfs, &pn->pn_po);
    507  1.1  pooka 	va->va_fileid = sfs->myid;
    508  1.1  pooka 	va->va_size = getsize(sfs, &pn->pn_po);
    509  1.1  pooka 	va->va_gen = 1;
    510  1.1  pooka 	va->va_rdev = PUFFS_VNOVAL;
    511  1.1  pooka 	va->va_blocksize = 512;
    512  1.1  pooka 	va->va_filerev = 1;
    513  1.1  pooka 
    514  1.1  pooka 	va->va_atime = va->va_mtime = va->va_ctime = va->va_birthtime = fstime;
    515  1.1  pooka 
    516  1.1  pooka 	return 0;
    517  1.1  pooka }
    518  1.1  pooka 
    519  1.1  pooka int
    520  1.1  pooka sysctlfs_node_setattr(struct puffs_cc *pcc, void *opc,
    521  1.1  pooka 	const struct vattr *va, const struct puffs_cred *pcr,
    522  1.1  pooka 	const struct puffs_cid *pcid)
    523  1.1  pooka {
    524  1.1  pooka 
    525  1.1  pooka 	/* dummy, but required for write */
    526  1.1  pooka 	return 0;
    527  1.1  pooka }
    528  1.1  pooka 
    529  1.1  pooka int
    530  1.1  pooka sysctlfs_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent,
    531  1.1  pooka 	off_t *readoff, size_t *reslen, const struct puffs_cred *pcr,
    532  1.1  pooka 	int *eofflag, off_t *cookies, size_t *ncookies)
    533  1.1  pooka {
    534  1.1  pooka 	struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
    535  1.1  pooka 	struct sysctlnode sn[SFS_NODEPERDIR];
    536  1.1  pooka 	struct sysctlnode qnode;
    537  1.1  pooka 	struct puffs_node *pn_dir = opc;
    538  1.1  pooka 	struct puffs_node *pn_res;
    539  1.1  pooka 	struct puffs_pathobj po;
    540  1.1  pooka 	struct sfsnode *sfs_dir = pn_dir->pn_data, *sfs_ent;
    541  1.1  pooka 	SfsName *sname;
    542  1.1  pooka 	size_t sl;
    543  1.1  pooka 	enum vtype vt;
    544  1.1  pooka 	ino_t id;
    545  1.1  pooka 	int i;
    546  1.1  pooka 
    547  1.1  pooka 	*ncookies = 0;
    548  1.1  pooka 
    549  1.1  pooka  again:
    550  1.1  pooka 	if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) {
    551  1.1  pooka 		puffs_gendotdent(&dent, sfs_dir->myid, *readoff, reslen);
    552  1.1  pooka 		(*readoff)++;
    553  1.1  pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
    554  1.1  pooka 		goto again;
    555  1.1  pooka 	}
    556  1.1  pooka 
    557  1.1  pooka 	memset(&qnode, 0, sizeof(qnode));
    558  1.1  pooka 	sl = SFS_NODEPERDIR * sizeof(struct sysctlnode);
    559  1.1  pooka 	qnode.sysctl_flags = SYSCTL_VERSION;
    560  1.1  pooka 	sname = PNPATH(pn_dir);
    561  1.1  pooka 	(*sname)[PNPLEN(pn_dir)] = CTL_QUERY;
    562  1.1  pooka 
    563  1.1  pooka 	if (sysctl(*sname, PNPLEN(pn_dir) + 1, sn, &sl,
    564  1.1  pooka 	    &qnode, sizeof(qnode)) == -1)
    565  1.1  pooka 		return ENOENT;
    566  1.1  pooka 
    567  1.1  pooka 	po.po_path = sname;
    568  1.1  pooka 	po.po_len = PNPLEN(pn_dir)+1;
    569  1.1  pooka 
    570  1.1  pooka 	for (i = DENT_ADJ(*readoff); i < sl / sizeof(struct sysctlnode); i++) {
    571  1.1  pooka 		if (SYSCTL_TYPE(sn[i].sysctl_flags) == CTLTYPE_NODE)
    572  1.1  pooka 			vt = VDIR;
    573  1.1  pooka 		else
    574  1.1  pooka 			vt = VREG;
    575  1.1  pooka 
    576  1.1  pooka 		/*
    577  1.1  pooka 		 * check if the node exists.  if so, give it the real
    578  1.1  pooka 		 * inode number.  otherwise just fake it.
    579  1.1  pooka 		 */
    580  1.1  pooka 		(*sname)[PNPLEN(pn_dir)] = sn[i].sysctl_num;
    581  1.1  pooka 		pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp, &po);
    582  1.1  pooka 		if (pn_res) {
    583  1.1  pooka 			sfs_ent = pn_res->pn_data;
    584  1.1  pooka 			id = sfs_ent->myid;
    585  1.1  pooka 		} else {
    586  1.1  pooka 			id = nextid++;
    587  1.1  pooka 		}
    588  1.1  pooka 
    589  1.1  pooka 		if (!puffs_nextdent(&dent, sn[i].sysctl_name, id,
    590  1.1  pooka 		    puffs_vtype2dt(vt), reslen))
    591  1.1  pooka 			return 0;
    592  1.1  pooka 
    593  1.1  pooka 		(*readoff)++;
    594  1.1  pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
    595  1.1  pooka 	}
    596  1.1  pooka 
    597  1.1  pooka 	*eofflag = 1;
    598  1.1  pooka 	return 0;
    599  1.1  pooka }
    600  1.1  pooka 
    601  1.1  pooka int
    602  1.1  pooka sysctlfs_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    603  1.1  pooka 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
    604  1.1  pooka 	int ioflag)
    605  1.1  pooka {
    606  1.1  pooka 	char localbuf[SFS_MAXFILE];
    607  1.1  pooka 	struct puffs_node *pn = opc;
    608  1.1  pooka 	struct sfsnode *sfs = pn->pn_data;
    609  1.1  pooka 	int xfer;
    610  1.1  pooka 
    611  1.1  pooka 	if (ISADIR(sfs))
    612  1.1  pooka 		return EISDIR;
    613  1.1  pooka 
    614  1.1  pooka 	doprint(sfs, &pn->pn_po, localbuf, sizeof(localbuf));
    615  1.1  pooka 	xfer = MIN(*resid, strlen(localbuf) - offset);
    616  1.1  pooka 
    617  1.1  pooka 	if (xfer <= 0)
    618  1.1  pooka 		return 0;
    619  1.1  pooka 
    620  1.1  pooka 	memcpy(buf, localbuf + offset, xfer);
    621  1.1  pooka 	*resid -= xfer;
    622  1.1  pooka 
    623  1.1  pooka 	if (*resid) {
    624  1.1  pooka 		buf[xfer] = '\n';
    625  1.1  pooka 		(*resid)--;
    626  1.1  pooka 	}
    627  1.1  pooka 
    628  1.1  pooka 	return 0;
    629  1.1  pooka }
    630  1.1  pooka 
    631  1.1  pooka int
    632  1.1  pooka sysctlfs_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    633  1.1  pooka 	off_t offset, size_t *resid, const struct puffs_cred *cred,
    634  1.1  pooka 	int ioflag)
    635  1.1  pooka {
    636  1.1  pooka 	struct puffs_node *pn = opc;
    637  1.1  pooka 	struct sfsnode *sfs = pn->pn_data;
    638  1.1  pooka 	long long ll;
    639  1.1  pooka 	int i, rv;
    640  1.1  pooka 
    641  1.1  pooka 	if (puffs_cred_isjuggernaut(cred) == 0)
    642  1.1  pooka 		return EACCES;
    643  1.1  pooka 
    644  1.1  pooka 	if (ISADIR(sfs))
    645  1.1  pooka 		return EISDIR;
    646  1.1  pooka 
    647  1.1  pooka 	if (offset != 0)
    648  1.1  pooka 		return EINVAL;
    649  1.1  pooka 
    650  1.1  pooka 	if (ioflag & PUFFS_IO_APPEND)
    651  1.1  pooka 		return EINVAL;
    652  1.1  pooka 
    653  1.1  pooka 	switch (SYSCTL_TYPE(sfs->sysctl_flags)) {
    654  1.1  pooka 	case CTLTYPE_INT:
    655  1.1  pooka 		if (sscanf((const char *)buf, "%d", &i) != 1)
    656  1.1  pooka 			return EINVAL;
    657  1.1  pooka 		rv = sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL,
    658  1.1  pooka 		    &i, sizeof(int));
    659  1.1  pooka 		break;
    660  1.1  pooka 	case CTLTYPE_QUAD:
    661  1.1  pooka 		if (sscanf((const char *)buf, "%lld", &ll) != 1)
    662  1.1  pooka 			return EINVAL;
    663  1.1  pooka 		rv =  sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL,
    664  1.1  pooka 		    &ll, sizeof(long long));
    665  1.1  pooka 		break;
    666  1.1  pooka 	case CTLTYPE_STRING:
    667  1.1  pooka 		rv = sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL, buf, *resid);
    668  1.1  pooka 		break;
    669  1.1  pooka 	default:
    670  1.1  pooka 		rv = EINVAL;
    671  1.1  pooka 		break;
    672  1.1  pooka 	}
    673  1.1  pooka 
    674  1.1  pooka 	if (rv)
    675  1.1  pooka 		return rv;
    676  1.1  pooka 
    677  1.1  pooka 	*resid = 0;
    678  1.1  pooka 	return 0;
    679  1.1  pooka }
    680