[BACK]Return to sysctl.c CVS log [TXT][DIR] Up to [local] / src / sbin / sysctl

File: [local] / src / sbin / sysctl / sysctl.c (download)

Revision 1.53, Fri Jun 30 16:00:10 2000 UTC (23 years, 11 months ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_2_8_BASE, OPENBSD_2_8
Changes since 1.52: +3 -3 lines

warnx?/errx? paranoia (use "%s" not a bare string unless it is a
constant).  These are not security holes but it is worth fixing
them anyway both for robustness and so folks looking for examples
in the tree are not misled into doing something potentially dangerous.
Furthermore, it is a bad idea to assume that pathnames will not
include '%' in them and that error routines don't return strings
with '%' in them (especially in light of the possibility of locales).

/*	$OpenBSD: sysctl.c,v 1.53 2000/06/30 16:00:10 millert Exp $	*/
/*	$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $	*/

/*
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1993\n\
	The Regents of the University of California.  All rights reserved.\n";
#endif /* not lint */

#ifndef lint
#if 0
static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
#else
static char *rcsid = "$OpenBSD: sysctl.c,v 1.53 2000/06/30 16:00:10 millert Exp $";
#endif
#endif /* not lint */

#include <sys/param.h>
#include <sys/gmon.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <vm/vm_param.h>
#include <machine/cpu.h>
#include <net/route.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipip.h>
#include <netinet/ip_ether.h>
#include <netinet/ip_ah.h>
#include <netinet/ip_esp.h>
#include <netinet/icmp_var.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/ip_gre.h>

#ifdef INET6
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/pim6_var.h>
#endif

#ifdef UVM
#include <uvm/uvm_swap_encrypt.h>
#endif

#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ffs/fs.h>
#include <ufs/ffs/ffs_extern.h>

#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>

#include <netipx/ipx.h>
#include <netipx/ipx_var.h>
#include <netipx/spx_var.h>
#include <ddb/db_var.h>
#include <dev/rndvar.h>

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef CPU_BIOS
#include <machine/biosvar.h>
#endif

struct ctlname topname[] = CTL_NAMES;
struct ctlname kernname[] = CTL_KERN_NAMES;
struct ctlname vmname[] = CTL_VM_NAMES;
struct ctlname fsname[] = CTL_FS_NAMES;
struct ctlname netname[] = CTL_NET_NAMES;
struct ctlname hwname[] = CTL_HW_NAMES;
struct ctlname username[] = CTL_USER_NAMES;
struct ctlname debugname[CTL_DEBUG_MAXID];
struct ctlname *vfsname;
#ifdef CTL_MACHDEP_NAMES
struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
#endif
struct ctlname ddbname[] = CTL_DDB_NAMES;
char names[BUFSIZ];
int lastused;

struct list {
	struct	ctlname *list;
	int	size;
};
struct list toplist = { topname, CTL_MAXID };
struct list secondlevel[] = {
	{ 0, 0 },			/* CTL_UNSPEC */
	{ kernname, KERN_MAXID },	/* CTL_KERN */
	{ vmname, VM_MAXID },		/* CTL_VM */
	{ fsname, FS_MAXID },		/* CTL_FS */
	{ netname, NET_MAXID },		/* CTL_NET */
	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
	{ hwname, HW_MAXID },		/* CTL_HW */
#ifdef CTL_MACHDEP_NAMES
	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
#else
	{ 0, 0 },			/* CTL_MACHDEP */
#endif
	{ username, USER_MAXID },	/* CTL_USER_NAMES */
	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
	{ 0, 0 },			/* CTL_VFS */
};

int	Aflag, aflag, nflag, wflag;

/*
 * Variables requiring special processing.
 */
#define	CLOCK		0x00000001
#define	BOOTTIME	0x00000002
#define	CHRDEV		0x00000004
#define	BLKDEV		0x00000008
#define	RNDSTATS	0x00000010
#define	BADDYNAMIC	0x00000020
#define	BIOSGEO		0x00000040
#define	BIOSDEV		0x00000080
#define	MAJ2DEV		0x00000100
#define	UNSIGNED	0x00000200

/* prototypes */
void debuginit __P((void));
void listall __P((char *, struct list *));
void parse __P((char *, int));
void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
void usage __P((void));
int findname __P((char *, char *, char **, struct list *));
int sysctl_inet __P((char *, char **, int *, int, int *));
#ifdef INET6
int sysctl_inet6 __P((char *, char **, int *, int, int *));
#endif
int sysctl_ipx __P((char *, char **, int *, int, int *));
int sysctl_fs __P((char *, char **, int *, int, int *));
static int sysctl_vfs __P((char *, char **, int[], int, int *));
static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
int sysctl_bios __P((char *, char **, int *, int, int *));
int sysctl_swpenc __P((char *, char **, int *, int, int *));
void vfsinit __P((void));

int
main(argc, argv)
	int argc;
	char *argv[];
{
	int ch, lvl1;

	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
		switch (ch) {

		case 'A':
			Aflag = 1;
			break;

		case 'a':
			aflag = 1;
			break;

		case 'n':
			nflag = 1;
			break;

		case 'w':
			wflag = 1;
			break;

		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0 && (Aflag || aflag)) {
		debuginit();
		vfsinit();
		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
		exit(0);
	}
	if (argc == 0)
		usage();
	for (; *argv != NULL; ++argv)
		parse(*argv, 1);
	exit(0);
}

/*
 * List all variables known to the system.
 */
void
listall(prefix, lp)
	char *prefix;
	struct list *lp;
{
	int lvl2;
	char *cp, name[BUFSIZ];

	if (lp->list == NULL)
		return;
	(void)strncpy(name, prefix, BUFSIZ-1);
	name[BUFSIZ-1] = '\0';
	cp = &name[strlen(name)];
	*cp++ = '.';
	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
		if (lp->list[lvl2].ctl_name == NULL)
			continue;
		(void)strcpy(cp, lp->list[lvl2].ctl_name);
		parse(name, Aflag);
	}
}

/*
 * Parse a name into a MIB entry.
 * Lookup and print out the MIB entry if it exists.
 * Set a new value if requested.
 */
void
parse(string, flags)
	char *string;
	int flags;
{
	int indx, type, state, intval, len;
	size_t size, newsize = 0;
	int special = 0;
	void *newval = 0;
	quad_t quadval;
	struct list *lp;
	int mib[CTL_MAXNAME];
	char *cp, *bufp, buf[BUFSIZ];

	(void)strncpy(buf, string, sizeof(buf) - 1);
	buf[sizeof(buf) - 1] = '\0';
	bufp = buf;
	if ((cp = strchr(string, '=')) != NULL) {
		if (!wflag)
			errx(2, "must specify -w to set variables");
		*strchr(buf, '=') = '\0';
		*cp++ = '\0';
		while (isspace(*cp))
			cp++;
		newval = cp;
		newsize = strlen(cp);
	}
	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
		return;
	mib[0] = indx;
	if (indx == CTL_VFS)
		vfsinit();
	if (indx == CTL_DEBUG)
		debuginit();
	lp = &secondlevel[indx];
	if (lp->list == 0) {
		warnx("%s: class is not implemented", topname[indx].ctl_name);
		return;
	}
	if (bufp == NULL) {
		listall(topname[indx].ctl_name, lp);
		return;
	}
	if ((indx = findname(string, "second", &bufp, lp)) == -1)
		return;
	mib[1] = indx;
	type = lp->list[indx].ctl_type;
	len = 2;
	switch (mib[0]) {

	case CTL_KERN:
		switch (mib[1]) {
		case KERN_PROF:
			mib[2] = GPROF_STATE;
			size = sizeof(state);
			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
				if (flags == 0)
					return;
				if (!nflag)
					(void)printf("%s: ", string);
				(void)puts("kernel is not compiled for profiling");
				return;
			}
			if (!nflag)
				(void)printf("%s = %s\n", string,
				    state == GMON_PROF_OFF ? "off" : "running");
			return;
		case KERN_VNODE:
		case KERN_FILE:
			if (flags == 0)
				return;
			warnx("use pstat to view %s information", string);
			return;
		case KERN_PROC:
			if (flags == 0)
				return;
			warnx("use ps to view %s information", string);
			return;
		case KERN_NTPTIME:
			if (flags == 0)
				return;
			warnx("use xntpdc to view %s information", string);
			return;
		case KERN_CLOCKRATE:
			special |= CLOCK;
			break;
		case KERN_BOOTTIME:
			special |= BOOTTIME;
			break;
		case KERN_RND:
			special |= RNDSTATS;
			break;
		case KERN_HOSTID:
		case KERN_ARND:
			special |= UNSIGNED;
			break;
		}
		break;

	case CTL_HW:
		break;

	case CTL_VM:
		if (mib[1] == VM_LOADAVG) {
			double loads[3];

			getloadavg(loads, 3);
			if (!nflag)
				(void)printf("%s = ", string);
			(void)printf("%.2f %.2f %.2f\n", loads[0],
			    loads[1], loads[2]);
			return;
		} else if (mib[1] == VM_PSSTRINGS) {
			struct _ps_strings _ps;

			len = sizeof(_ps);
			if (sysctl(mib, 2, &_ps, &len, NULL, 0) == -1) {
				if (flags == 0)
					return;
				if (!nflag)
					(void)printf("%s: ", string);
				(void)puts("can't find ps strings");
				return;
			}
			if (!nflag)
				(void)printf("%s = ", string);
			(void)printf("%p\n", _ps.val);
			return;
		}
#ifdef UVM
		else if (mib[1] == VM_SWAPENCRYPT) {
			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
			if (len < 0)
				return;

			break;
		}
#endif
		if (flags == 0)
			return;
		warnx("use vmstat or systat to view %s information", string);
		return;

		break;

	case CTL_NET:
		if (mib[1] == PF_INET) {
			len = sysctl_inet(string, &bufp, mib, flags, &type);
			if (len < 0)
				return;

			if ((mib[2] == IPPROTO_TCP &&
			     mib[3] == TCPCTL_BADDYNAMIC) ||
			    (mib[2] == IPPROTO_UDP &&
			     mib[3] == UDPCTL_BADDYNAMIC)) {

				special |= BADDYNAMIC;

				if (newval != NULL)
					parse_baddynamic(mib, len, string,
					    &newval, &newsize, flags, nflag);
			}
			break;
		}
#ifdef INET6
		if (mib[1] == PF_INET6) {
			len = sysctl_inet6(string, &bufp, mib, flags, &type);
			if (len < 0)
				return;

			break;
		}
#endif
		if (mib[1] == PF_IPX) {
			len = sysctl_ipx(string, &bufp, mib, flags, &type);
			if (len >= 0)
				break;
			return;
		}
		if (flags == 0)
			return;
		warnx("use netstat to view %s information", string);
		return;

	case CTL_DEBUG:
		mib[2] = CTL_DEBUG_VALUE;
		len = 3;
		break;

	case CTL_MACHDEP:
#ifdef CPU_CONSDEV
		if (mib[1] == CPU_CONSDEV)
			special |= CHRDEV;
#endif
#ifdef CPU_BLK2CHR
		if (mib[1] == CPU_BLK2CHR) {
			if (bufp == NULL)
				return;
			mib[2] = makedev(atoi(bufp),0);
			bufp = NULL;
			len = 3;
			special |= CHRDEV;
			break;
		}
#endif
#ifdef CPU_CHR2BLK
		if (mib[1] == CPU_CHR2BLK) {
			if (bufp == NULL)
				return;
			mib[2] = makedev(atoi(bufp),0);
			bufp = NULL;
			len = 3;
			special |= BLKDEV;
			break;
		}
#endif
#ifdef CPU_BIOS
		if (mib[1] == CPU_BIOS) {
			len = sysctl_bios(string, &bufp, mib, flags, &type);
			if (len < 0)
				return;
			if (mib[2] == BIOS_DEV)
				special |= BIOSDEV;
			if (mib[2] == BIOS_DISKINFO)
				special |= BIOSGEO;
			break;
		}
#endif
		break;

	case CTL_FS:
		len = sysctl_fs(string, &bufp, mib, flags, &type);
		if (len >= 0)
			break;
		return;

	case CTL_VFS:
		if (mib[1])
			len = sysctl_vfs(string, &bufp, mib, flags, &type);
		else
			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
		if (len >= 0) {
			if (type == CTLTYPE_STRUCT) {
				if (flags)
					warnx("use nfsstat to view %s information",
					    MOUNT_NFS);
				return;
			} else
				break;
		}
		return;

	case CTL_USER:
	case CTL_DDB:
		break;

	default:
		warnx("illegal top level value: %d", mib[0]);
		return;
	
	}
	if (bufp) {
		warnx("name %s in %s is unknown", bufp, string);
		return;
	}
	if (newsize > 0) {
		switch (type) {
		case CTLTYPE_INT:
			errno = 0;
			if (special & UNSIGNED)
				intval = strtoul(newval, &cp, 10);
			else
				intval = strtol(newval, &cp, 10);
			if (*cp != '\0') {
				warnx("%s: illegal value: %s", string,
				    (char *)newval);
				return;
			}
			if (errno == ERANGE) {
				warnx("%s: value %s out of range", string,
				    (char *)newval);
				return;
			}
			newval = &intval;
			newsize = sizeof(intval);
			break;

		case CTLTYPE_QUAD:
			(void)sscanf(newval, "%qd", &quadval);
			newval = &quadval;
			newsize = sizeof(quadval);
			break;
		}
	}
	size = BUFSIZ;
	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
		if (flags == 0)
			return;
		switch (errno) {
		case EOPNOTSUPP:
			warnx("%s: value is not available", string);
			return;
		case ENOTDIR:
			warnx("%s: specification is incomplete", string);
			return;
		case ENOMEM:
			warnx("%s: type is unknown to this program", string);
			return;
		case ENXIO:
			if (special & BIOSGEO)
				return;
		default:
			warn("%s", string);
			return;
		}
	}
	if (special & CLOCK) {
		struct clockinfo *clkp = (struct clockinfo *)buf;

		if (!nflag)
			(void)printf("%s = ", string);
		(void)printf(
		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
		return;
	}
	if (special & BOOTTIME) {
		struct timeval *btp = (struct timeval *)buf;
		time_t boottime;

		if (!nflag) {
			boottime = btp->tv_sec;
			(void)printf("%s = %s", string, ctime(&boottime));
		} else
			(void)printf("%ld\n", btp->tv_sec);
		return;
	}
	if (special & BLKDEV) {
		dev_t dev = *(dev_t *)buf;

		if (!nflag)
			(void)printf("%s = %s\n", string,
			    devname(dev, S_IFBLK));
		else
			(void)printf("0x%x\n", dev);
		return;
	}
	if (special & CHRDEV) {
		dev_t dev = *(dev_t *)buf;

		if (!nflag)
			(void)printf("%s = %s\n", string,
			    devname(dev, S_IFCHR));
		else
			(void)printf("0x%x\n", dev);
		return;
	}
#ifdef CPU_BIOS
	if (special & BIOSGEO) {
		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;

		if (!nflag)
			(void)printf("%s = ", string);
		(void)printf("bootdev = 0x%x, "
			     "cylinders = %u, heads = %u, sectors = %u\n",
			     pdi->bsd_dev, pdi->bios_cylinders, pdi->bios_heads,
			     pdi->bios_sectors);
		return;
	}
	if (special & BIOSDEV) {
		int dev = *(int*)buf;

		if (!nflag)
			(void)printf("%s = ", string);
		(void) printf("0x%02x\n", dev);
		return;
	}
#endif
	if (special & UNSIGNED) {
		if (newsize == 0) {
			if (!nflag)
				(void)printf("%s = ", string);
			(void)printf("%u\n", *(u_int *)buf);
		} else {
			if (!nflag)
				(void)printf("%s: %u -> ", string,
				    *(u_int *)buf);
			(void)printf("%u\n", *(u_int *)newval);
		}
		return;
	}
	if (special & RNDSTATS) {
		struct rndstats *rndstats = (struct rndstats *)buf;
		int i;

		if (!nflag)
			(void)printf("%s = ", string);
		(void)printf(
		"%qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu",
		    rndstats->rnd_total,
		    rndstats->rnd_used, rndstats->rnd_reads,
		    rndstats->arc4_reads, rndstats->arc4_nstirs,
		    rndstats->arc4_stirs,
		    rndstats->rnd_pad[0],
		    rndstats->rnd_pad[1],
		    rndstats->rnd_pad[2],
		    rndstats->rnd_pad[3],
		    rndstats->rnd_pad[4],
		    rndstats->rnd_waits,
		    rndstats->rnd_enqs, rndstats->rnd_deqs,
		    rndstats->rnd_drops, rndstats->rnd_drople);
		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]); i++)
			(void)printf(" %qu", rndstats->rnd_ed[i]);
		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]); i++)
			(void)printf(" %qu", rndstats->rnd_sc[i]);
		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]); i++)
			(void)printf(" %qu", rndstats->rnd_sb[i]);
		printf("\n");
		return;
	}
	if (special & BADDYNAMIC) {
		in_port_t port, lastport;
		u_int32_t *baddynamic = (u_int32_t *)buf;

		if (!nflag)
			(void)printf("%s%s", string, newsize ? ": " : " = ");
		lastport = 0;
		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
			if (DP_ISSET(baddynamic, port)) {
				(void)printf("%s%hd", lastport ? "," : "",
				    port);
				lastport = port;
			}
		if (newsize != 0) {
			if (!nflag)
				fputs(" -> ", stdout);
			baddynamic = (u_int32_t *)newval;
			lastport = 0;
			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
			    port++)
				if (DP_ISSET(baddynamic, port)) {
					(void)printf("%s%hd",
					    lastport ? "," : "", port);
					lastport = port;
				}
		}
		(void)putchar('\n');
		return;
	}
	switch (type) {
	case CTLTYPE_INT:
		if (newsize == 0) {
			if (!nflag)
				(void)printf("%s = ", string);
			(void)printf("%d\n", *(int *)buf);
		} else {
			if (!nflag)
				(void)printf("%s: %d -> ", string,
				    *(int *)buf);
			(void)printf("%d\n", *(int *)newval);
		}
		return;

	case CTLTYPE_STRING:
		if (newsize == 0) {
			if (!nflag)
				(void)printf("%s = ", string);
			(void)puts(buf);
		} else {
			if (!nflag)
				(void)printf("%s: %s -> ", string, buf);
			(void)puts((char *)newval);
		}
		return;

	case CTLTYPE_QUAD:
		if (newsize == 0) {
			if (!nflag)
				(void)printf("%s = ", string);
			(void)printf("%qd\n", *(quad_t *)buf);
		} else {
			if (!nflag)
				(void)printf("%s: %qd -> ", string,
				    *(quad_t *)buf);
			(void)printf("%qd\n", *(quad_t *)newval);
		}
		return;

	case CTLTYPE_STRUCT:
		warnx("%s: unknown structure returned", string);
		return;

	default:
	case CTLTYPE_NODE:
		warnx("%s: unknown type returned", string);
		return;
	}
}

void
parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
	int mib[];
	size_t len;
	char *string;
	void **newvalp;
	size_t *newsizep;
	int flags;
	int nflag;
{
	static u_int32_t newbaddynamic[DP_MAPSIZE];
	in_port_t port;
	size_t size;
	char action, *cp;

	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
		size = sizeof(newbaddynamic);
		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
			if (flags == 0)
				return;
			if (!nflag)
				(void)printf("%s: ", string);
			(void)puts("kernel does contain bad dynamic port tables");
			return;
		}

		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
			if (*cp != '+' && *cp != '-')
				errx(1, "cannot mix +/- with full list");
			action = *cp++;
			port = atoi(cp);
			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
				errx(1, "invalid port, range is %d to %d",
				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
			if (action == '+')
				DP_SET(newbaddynamic, port);
			else
				DP_CLR(newbaddynamic, port);
		}
	} else {
		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
			port = atoi(cp);
			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
				errx(1, "invalid port, range is %d to %d",
				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
			DP_SET(newbaddynamic, port);
		}
	}

	*newvalp = (void *)newbaddynamic;
	*newsizep = sizeof(newbaddynamic);
}

/*
 * Initialize the set of debugging names
 */
void
debuginit()
{
	int mib[3], loc, i;
	size_t size;

	if (secondlevel[CTL_DEBUG].list != 0)
		return;
	secondlevel[CTL_DEBUG].list = debugname;
	mib[0] = CTL_DEBUG;
	mib[2] = CTL_DEBUG_NAME;
	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
		mib[1] = i;
		size = BUFSIZ - loc;
		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
			continue;
		debugname[i].ctl_name = &names[loc];
		debugname[i].ctl_type = CTLTYPE_INT;
		loc += size;
	}
	lastused = loc;
}

struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
struct ctlname ffsname[] = FFS_NAMES;
struct ctlname nfsname[] = FS_NFS_NAMES;
struct list *vfsvars;
int *vfs_typenums;

/*
 * Initialize the set of filesystem names
 */
void
vfsinit()
{
	int mib[4], maxtypenum, cnt, loc, size;
	struct vfsconf vfc;
	size_t buflen;

	if (secondlevel[CTL_VFS].list != 0)
		return;
	mib[0] = CTL_VFS;
	mib[1] = VFS_GENERIC;
	mib[2] = VFS_MAXTYPENUM;
	buflen = 4;
	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
		return;
	maxtypenum++;	/* + generic */
	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
		return;
	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
		free(vfs_typenums);
		return;
	}
	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
		free(vfs_typenums);
		free(vfsvars);
		return;
	}
	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
	mib[2] = VFS_CONF;
	buflen = sizeof vfc;
	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
		mib[3] = cnt - 1;
		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
			if (errno == EOPNOTSUPP)
				continue;
			warn("vfsinit");
			free(vfsname);
			return;
		}
		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
			vfsvars[cnt].list = ffsname;
			vfsvars[cnt].size = FFS_MAXID;
		}
		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
			vfsvars[cnt].list = nfsname;
			vfsvars[cnt].size = NFS_MAXID;
		}
		vfs_typenums[cnt] = vfc.vfc_typenum;
		strcat(&names[loc], vfc.vfc_name);
		vfsname[cnt].ctl_name = &names[loc];
		vfsname[cnt].ctl_type = CTLTYPE_NODE;
		size = strlen(vfc.vfc_name) + 1;
		loc += size;
	}
	lastused = loc;

	vfsname[0].ctl_name = "mounts";
	vfsname[0].ctl_type = CTLTYPE_NODE;
	vfsvars[0].list = vfsname + 1;
	vfsvars[0].size = maxtypenum - 1;

	secondlevel[CTL_VFS].list = vfsname;
	secondlevel[CTL_VFS].size = maxtypenum;
	return;
}

int
sysctl_vfsgen(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	int indx;
	size_t size;
	struct vfsconf vfc;

	if (*bufpp == NULL) {
		listall(string, vfsvars);
		return (-1);
	}

	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
		return (-1);

	mib[1] = VFS_GENERIC;
	mib[2] = VFS_CONF;
	mib[3] = indx;
	size = sizeof vfc;
	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
		if (errno != EOPNOTSUPP)
			warn("vfs print");
		return -1;
	}
	if (flags == 0 && vfc.vfc_refcount == 0)
		return -1;
	if (!nflag)
		fprintf(stdout, "%s has %d mounted instance%s\n",
		    string, vfc.vfc_refcount,
		    vfc.vfc_refcount != 1 ? "s" : "");
	else
		fprintf(stdout, "%d\n", vfc.vfc_refcount);

	return -1;
}

int
sysctl_vfs(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	struct list *lp = &vfsvars[mib[1]];
	int indx;

	if (lp->list == NULL) {
		if (flags)
			warnx("No variables defined for file system %s", string);
		return(-1);
	}
	if (*bufpp == NULL) {
		listall(string, lp);
		return (-1);
	}
	if ((indx = findname(string, "third", bufpp, lp)) == -1)
		return (-1);

	mib[1] = vfs_typenums[mib[1]];
	mib[2] = indx;
	*typep = lp->list[indx].ctl_type;
	return (3);
}

struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
struct list fslist = { posixname, FS_POSIX_MAXID };

/*
 * handle file system requests
 */
int
sysctl_fs(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	int indx;

	if (*bufpp == NULL) {
		listall(string, &fslist);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
		return(-1);
	mib[2] = indx;
	*typep = fslist.list[indx].ctl_type;
	return(3);
}

#ifdef CPU_BIOS
struct ctlname biosname[] = CTL_BIOS_NAMES;
struct list bioslist = { biosname, BIOS_MAXID };

/*
 * handle BIOS requests
 */
int
sysctl_bios(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	char *name;
	int indx;

	if (*bufpp == NULL) {
		listall(string, &bioslist);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
		return(-1);
	mib[2] = indx;
	if (indx == BIOS_DISKINFO) {
		if (*bufpp == NULL) {
			char name[BUFSIZ];

			/* scan all the bios devices */
			for (indx = 0; indx < 256; indx++) {
				snprintf(name, sizeof(name), "%s.%u",
					 string, indx);
				parse(name, 1);
			}
			return(-1);
		}
		if ((name = strsep(bufpp, ".")) == NULL) {
			warnx("%s: incomplete specification", string);
			return(-1);
		}
		mib[3] = atoi(name);
		*typep = CTLTYPE_STRUCT;
		return 4;
	} else {
		*typep = bioslist.list[indx].ctl_type;
		return(3);
	}
}
#endif

#ifdef UVM
struct ctlname swpencname[] = CTL_SWPENC_NAMES;
struct list swpenclist = { swpencname, SWPENC_MAXID };

/*
 * handle swap encrypt requests
 */
int
sysctl_swpenc(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	char *name;
	int indx;

	if (*bufpp == NULL) {
		listall(string, &swpenclist);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
		return(-1);
	mib[2] = indx;
	*typep = swpenclist.list[indx].ctl_type;
	return(3);
}
#endif

struct ctlname inetname[] = CTL_IPPROTO_NAMES;
struct ctlname ipname[] = IPCTL_NAMES;
struct ctlname icmpname[] = ICMPCTL_NAMES;
struct ctlname ipipname[] = IPIPCTL_NAMES;
struct ctlname tcpname[] = TCPCTL_NAMES;
struct ctlname udpname[] = UDPCTL_NAMES;
struct ctlname espname[] = ESPCTL_NAMES;
struct ctlname ahname[] = AHCTL_NAMES;
struct ctlname etheripname[] = ETHERIPCTL_NAMES;
struct ctlname grename[] = GRECTL_NAMES;
struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
struct list inetlist = { inetname, IPPROTO_MAXID };
struct list inetvars[] = {
	{ ipname, IPCTL_MAXID },	/* ip */
	{ icmpname, ICMPCTL_MAXID },	/* icmp */
	{ 0, 0 },			/* igmp */
	{ 0, 0 },			/* ggmp */
	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
	{ 0, 0 },
	{ tcpname, TCPCTL_MAXID },	/* tcp */
	{ 0, 0 },
	{ 0, 0 },			/* egp */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },			/* pup */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ udpname, UDPCTL_MAXID },	/* udp */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ grename, GRECTL_MAXID }, /* GRE */
	{ 0, 0 },
	{ 0, 0 },
	{ espname, ESPCTL_MAXID },	/* esp */
	{ ahname, AHCTL_MAXID },	/* ah */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ etheripname, ETHERIPCTL_MAXID },
};

/*
 * handle internet requests
 */
int
sysctl_inet(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	struct list *lp;
	int indx;

	if (*bufpp == NULL) {
		listall(string, &inetlist);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
		return(-1);
	mib[2] = indx;
	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
		lp = &inetvars[indx];
	else if (!flags)
		return(-1);
	else {
		warnx("%s: no variables defined for this protocol", string);
		return(-1);
	}
	if (*bufpp == NULL) {
		listall(string, lp);
		return(-1);
	}
	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
		return(-1);
	mib[3] = indx;
	*typep = lp->list[indx].ctl_type;
	return(4);
}

#ifdef INET6
struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
struct ctlname ip6name[] = IPV6CTL_NAMES;
struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
struct ctlname pim6name[] = PIM6CTL_NAMES;
struct list inet6list = { inet6name, IPV6PROTO_MAXID };
struct list inet6vars[] = {
/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*40*/	{ 0, 0 },
	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
	{ 0, 0 },
/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
/*100*/	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
};

/*
 * handle internet6 requests
 */
int
sysctl_inet6(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	struct list *lp;
	int indx;

	if (*bufpp == NULL) {
		listall(string, &inet6list);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
		return(-1);
	mib[2] = indx;
	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
		lp = &inet6vars[indx];
	else if (!flags)
		return(-1);
	else {
		warnx("%s: no variables defined for this protocol", string);
		return(-1);
	}
	if (*bufpp == NULL) {
		listall(string, lp);
		return(-1);
	}
	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
		return(-1);
	mib[3] = indx;
	*typep = lp->list[indx].ctl_type;
	return(4);
}
#endif

struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
struct ctlname ipxpname[] = IPXCTL_NAMES;
struct ctlname spxpname[] = SPXCTL_NAMES;
struct list ipxlist = { ipxname, IPXCTL_MAXID };
struct list ipxvars[] = {
	{ ipxpname, IPXCTL_MAXID },	/* ipx */
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ 0, 0 },
	{ spxpname, SPXCTL_MAXID },
};

/*
 * Handle internet requests
 */
int
sysctl_ipx(string, bufpp, mib, flags, typep)
	char *string;
	char **bufpp;
	int mib[];
	int flags;
	int *typep;
{
	struct list *lp;
	int indx;

	if (*bufpp == NULL) {
		listall(string, &ipxlist);
		return(-1);
	}
	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
		return(-1);
	mib[2] = indx;
	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
		lp = &ipxvars[indx];
	else if (!flags)
		return(-1);
	else {
		warnx("%s: no variables defined for this protocol", string);
		return(-1);
	}
	if (*bufpp == NULL) {
		listall(string, lp);
		return(-1);
	}
	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
		return(-1);
	mib[3] = indx;
	*typep = lp->list[indx].ctl_type;
	return(4);
}

/*
 * Scan a list of names searching for a particular name.
 */
int
findname(string, level, bufp, namelist)
	char *string;
	char *level;
	char **bufp;
	struct list *namelist;
{
	char *name;
	int i;

	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
		warnx("%s: incomplete specification", string);
		return(-1);
	}
	for (i = 0; i < namelist->size; i++)
		if (namelist->list[i].ctl_name != NULL &&
		    strcmp(name, namelist->list[i].ctl_name) == 0)
			break;
	if (i == namelist->size) {
		warnx("%s level name %s in %s is invalid", level, name, string);
		return(-1);
	}
	return(i);
}

void
usage()
{

	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
	    "sysctl [-n] -a", "sysctl [-n] -A");
	exit(1);
}