Edit

IABSD.fr/src/sbin/sysctl/sysctl.c

Branch :

  • Show log

    Commit

  • Author : deraadt
    Date : 2026-03-31 16:46:46
    Hash : 1675bd6d
    Message : warn if hw.smt is used, and recommend hw.blockcpu

  • sbin/sysctl/sysctl.c
  • /*	$OpenBSD: sysctl.c,v 1.270 2026/03/31 16:46:46 deraadt 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. 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.
     */
    
    #include <sys/types.h>
    #include <sys/gmon.h>
    #include <sys/mount.h>
    #include <sys/sem.h>
    #include <sys/shm.h>
    #include <sys/sysctl.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <sys/malloc.h>
    #include <sys/uio.h>
    #include <sys/tty.h>
    #include <sys/namei.h>
    #include <sys/sched.h>
    #include <sys/sensors.h>
    #include <sys/vmmeter.h>
    #include <net/route.h>
    #include <net/if.h>
    
    #include <netinet/in.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/igmp_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>
    #include <netinet/ip_ipcomp.h>
    #include <netinet/ip_carp.h>
    #include <netinet/ip_divert.h>
    
    #include <net/pfvar.h>
    #include <net/if_pfsync.h>
    #include <net/pipex.h>
    
    #include <netinet/ip6.h>
    #include <netinet/icmp6.h>
    
    #include <netmpls/mpls.h>
    
    #include <uvm/uvm_swap_encrypt.h>
    
    #include <ufs/ufs/quota.h>
    #include <ufs/ufs/inode.h>
    #include <ufs/ffs/ffs_extern.h>
    
    #include <miscfs/fuse/fusefs.h>
    
    #include <nfs/nfsproto.h>
    #include <nfs/nfs.h>
    
    #include <ddb/db_var.h>
    
    #include <ctype.h>
    #include <err.h>
    #include <errno.h>
    #include <limits.h>
    #include <paths.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include <machine/cpu.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 netname[] = CTL_NET_NAMES;
    struct ctlname hwname[] = CTL_HW_NAMES;
    struct ctlname debugname[CTL_DEBUG_MAXID];
    struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
    struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
    struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
    struct ctlname ttysname[] = CTL_KERN_TTY_NAMES;
    struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
    struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
    struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
    struct ctlname tcname[] = CTL_KERN_TIMECOUNTER_NAMES;
    struct ctlname *vfsname;
    #ifdef CTL_MACHDEP_NAMES
    struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
    #endif
    struct ctlname ddbname[] = CTL_DDB_NAMES;
    struct ctlname audioname[] = CTL_KERN_AUDIO_NAMES;
    struct ctlname videoname[] = CTL_KERN_VIDEO_NAMES;
    struct ctlname witnessname[] = CTL_KERN_WITNESS_NAMES;
    struct ctlname batteryname[] = CTL_HW_BATTERY_NAMES;
    char names[BUFSIZ];
    int lastused;
    
    /* Maximum size object to expect from sysctl(2) */
    #define SYSCTL_BUFSIZ	8192
    
    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 */
    	{ 0, 0 },			/* was 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
    	{ 0, 0 },			/* was CTL_USER */
    	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
    	{ 0, 0 },			/* CTL_VFS */
    };
    
    int	Aflag, aflag, nflag, qflag;
    
    time_t boottime;
    
    /*
     * Variables requiring special processing.
     */
    #define	CLOCK		0x00000001
    #define	BOOTTIME	0x00000002
    #define	CHRDEV		0x00000004
    #define	BLKDEV		0x00000008
    #define	BADDYNAMIC	0x00000020
    #define	BIOSGEO		0x00000040
    #define	BIOSDEV		0x00000080
    #define	MAJ2DEV		0x00000100
    #define	UNSIGNED	0x00000200
    #define	KMEMBUCKETS	0x00000400
    #define	LONGARRAY	0x00000800
    #define	KMEMSTATS	0x00001000
    #define	SENSORS		0x00002000
    #define	SMALLBUF	0x00004000
    #define	HEX		0x00008000
    #define	TIMEOUT		0x00010000
    
    /* prototypes */
    void debuginit(void);
    void listall(char *, struct list *);
    int parse_hex_char(char);
    ssize_t parse_hex_string(unsigned char *, size_t, const char *);
    void parse(char *, int);
    void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
    void usage(void);
    int findname(char *, char *, char **, struct list *);
    int sysctl_inet(char *, char **, int *, int, int *);
    int sysctl_inet6(char *, char **, int *, int, int *);
    int sysctl_unix(char *, char **, int *, int, int *);
    int sysctl_link(char *, char **, int *, int, int *);
    int sysctl_bpf(char *, char **, int *, int, int *);
    int sysctl_mpls(char *, char **, int *, int, int *);
    int sysctl_pipex(char *, char **, int *, int, int *);
    static int sysctl_vfs(char *, char **, int[], int, int *);
    static int sysctl_vfsgen(char *, char **, int[], int, int *);
    int sysctl_bios(char *, char **, int *, int, int *);
    int sysctl_swpenc(char *, char **, int *, int, int *);
    int sysctl_forkstat(char *, char **, int *, int, int *);
    int sysctl_tty(char *, char **, int *, int, int *);
    int sysctl_nchstats(char *, char **, int *, int, int *);
    int sysctl_malloc(char *, char **, int *, int, int *);
    int sysctl_seminfo(char *, char **, int *, int, int *);
    int sysctl_shminfo(char *, char **, int *, int, int *);
    int sysctl_watchdog(char *, char **, int *, int, int *);
    int sysctl_tc(char *, char **, int *, int, int *);
    int sysctl_sensors(char *, char **, int *, int, int *);
    void print_sensordev(char *, int *, u_int, struct sensordev *);
    void print_sensor(struct sensor *);
    #ifdef CPU_CHIPSET
    int sysctl_chipset(char *, char **, int *, int, int *);
    #endif
    int sysctl_audio(char *, char **, int *, int, int *);
    int sysctl_video(char *, char **, int *, int, int *);
    int sysctl_witness(char *, char **, int *, int, int *);
    int sysctl_battery(char *, char **, int *, int, int *);
    void vfsinit(void);
    
    char *equ = "=";
    
    int
    main(int argc, char *argv[])
    {
    	int ch, lvl1;
    	const char *conffile = NULL;
    
    	while ((ch = getopt(argc, argv, "Aaf:nqw")) != -1) {
    		switch (ch) {
    
    		case 'A':
    			Aflag = 1;
    			break;
    
    		case 'a':
    			aflag = 1;
    			break;
    
    		case 'f':
    			conffile = optarg;
    			break;
    
    		case 'n':
    			nflag = 1;
    			break;
    
    		case 'q':
    			qflag = 1;
    			break;
    
    		case 'w':
    			/* flag no longer needed; var=value implies write */
    			break;
    
    		default:
    			usage();
    		}
    	}
    	argc -= optind;
    	argv += optind;
    
    	ctime(&boottime); /* satisfy potential $TZ expansion before unveil() */
    
    	if (unveil(_PATH_DEVDB, "r") == -1 && errno != ENOENT)
    		err(1,"unveil %s", _PATH_DEVDB);
    	if (unveil("/dev", "r") == -1 && errno != ENOENT)
    		err(1, "unveil /dev");
    	if (conffile != NULL)
    		if (unveil(conffile, "r") == -1 && errno != ENOENT)
    			err(1, "unveil %s", conffile);
    	if (unveil(NULL, NULL) == -1)
    		err(1, "unveil");
    
    	if ((argc == 0 && conffile == NULL) || (Aflag || aflag)) {
    		debuginit();
    		vfsinit();
    		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
    			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
    		return (0);
    	}
    
    	if (conffile != NULL) {
    		FILE *fp;
    		char *line = NULL, *lp;
    		size_t sz = 0;
    
    		if ((fp = fopen(conffile, "r")) == NULL)
    			err(1, "fopen");
    
    		while (getline(&line, &sz, fp) != -1) {
    			lp = line + strspn(line, " \t");
    			lp[strcspn(lp, " \t\n#")] = '\0';
    
    			if (lp[0] != '\0')
    				parse(line, 1);
    		}
    
    		free(line);
    		fclose(fp);
    	}
    
    	for (; *argv != NULL; ++argv)
    		parse(*argv, 1);
    	return (0);
    }
    
    /*
     * List all variables known to the system.
     */
    void
    listall(char *prefix, struct list *lp)
    {
    	char *cp, name[BUFSIZ];
    	int lvl2, len;
    
    	if (lp->list == NULL)
    		return;
    	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
    		errx(1, "%s: name too long", prefix);
    	cp = name + len++;
    	*cp++ = '.';
    	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
    		if (lp->list[lvl2].ctl_name == NULL)
    			continue;
    		if (strlcpy(cp, lp->list[lvl2].ctl_name,
    		    sizeof(name) - len) >= sizeof(name) - len)
    			warn("%s: name too long", lp->list[lvl2].ctl_name);
    		parse(name, Aflag);
    	}
    }
    
    int
    parse_hex_char(char ch)
    {
    	if (ch >= '0' && ch <= '9')
    		return (ch - '0');
    
    	ch = tolower((unsigned char)ch);
    	if (ch >= 'a' && ch <= 'f')
    		return (ch - 'a' + 10);
    
    	return (-1);
    }
    
    ssize_t
    parse_hex_string(unsigned char *dst, size_t dstlen, const char *src)
    {
    	ssize_t len = 0;
    	int digit;
    
    	while (len < dstlen) {
    		if (*src == '\0')
    			return (len);
    
    		digit = parse_hex_char(*src++);
    		if (digit == -1)
    			return (-1);
    		dst[len] = digit << 4;
    
    		digit = parse_hex_char(*src++);
    		if (digit == -1)
    			return (-1);
    		
    		dst[len] |= digit;
    		len++;
    	}
    
    	while (*src != '\0') {
    		if (parse_hex_char(*src++) == -1 ||
    		    parse_hex_char(*src++) == -1)
    			return (-1);
    
    		len++;
    	}
    
    	return (len);
    }
    
    /*
     * 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(char *string, int flags)
    {
    	int indx, type, state, intval, len;
    	size_t size, newsize = 0;
    	int lal = 0, special = 0;
    	void *newval = NULL;
    	int64_t quadval;
    	struct list *lp;
    	int mib[CTL_MAXNAME];
    	char *cp, *bufp, buf[SYSCTL_BUFSIZ];
    	unsigned char hex[SYSCTL_BUFSIZ];
    
    	(void)strlcpy(buf, string, sizeof(buf));
    	bufp = buf;
    	if ((cp = strchr(string, '=')) != NULL) {
    		*strchr(buf, '=') = '\0';
    		*cp++ = '\0';
    		while (isspace((unsigned char)*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;
    			mib[3] = 0; /* Assume CPU ID 0 is always valid. */
    			size = sizeof(state);
    			if (sysctl(mib, 4, &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_FORKSTAT:
    			sysctl_forkstat(string, &bufp, mib, flags, &type);
    			return;
    		case KERN_TTY:
    			len = sysctl_tty(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_NCHSTATS:
    			sysctl_nchstats(string, &bufp, mib, flags, &type);
    			return;
    		case KERN_MALLOCSTATS:
    			len = sysctl_malloc(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			if (mib[2] == KERN_MALLOC_BUCKET)
    				special |= KMEMBUCKETS;
    			if (mib[2] == KERN_MALLOC_KMEMSTATS)
    				special |= KMEMSTATS;
    			newsize = 0;
    			break;
    		case KERN_MBSTAT:
    			if (flags == 0)
    				return;
    			warnx("use netstat to view %s", string);
    			return;
    		case KERN_MSGBUF:
    			if (flags == 0)
    				return;
    			warnx("use dmesg to view %s", string);
    			return;
    		case KERN_PROC:
    			if (flags == 0)
    				return;
    			warnx("use ps to view %s information", string);
    			return;
    		case KERN_CLOCKRATE:
    			special |= CLOCK;
    			break;
    		case KERN_BOOTTIME:
    			special |= BOOTTIME;
    			break;
    		case KERN_HOSTID:
    			special |= UNSIGNED;
    			special |= SMALLBUF;
    			break;
    		case KERN_CPTIME:
    			special |= LONGARRAY;
    			lal = CPUSTATES;
    			break;
    		case KERN_SEMINFO:
    			len = sysctl_seminfo(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_SHMINFO:
    			len = sysctl_shminfo(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_INTRCNT:
    			if (flags == 0)
    				return;
    			warnx("use vmstat or systat to view %s information",
    			    string);
    			return;
    		case KERN_WATCHDOG:
    			len = sysctl_watchdog(string, &bufp, mib, flags,
    			    &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_TIMECOUNTER:
    			len = sysctl_tc(string, &bufp, mib, flags,
    			    &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_FILE:
    			if (flags == 0)
    				return;
    			warnx("use fstat to view %s information", string);
    			return;
    		case KERN_CONSDEV:
    			special |= CHRDEV;
    			break;
    		case KERN_NETLIVELOCKS:
    		case KERN_SOMAXCONN:
    		case KERN_SOMINCONN:
    			special |= UNSIGNED;
    			break;
    		case KERN_AUDIO:
    			len = sysctl_audio(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_VIDEO:
    			len = sysctl_video(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_WITNESS:
    			len = sysctl_witness(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case KERN_PFSTATUS:
    			if (flags == 0)
    				return;
    			warnx("use pfctl to view %s information", string);
    			return;
    		case KERN_TIMEOUT_STATS:
    			special |= TIMEOUT;
    			break;
    		}
    		break;
    
    	case CTL_HW:
    		switch (mib[1]) {
    		case HW_DISKSTATS:
    			/*
    			 * Only complain if someone asks explicitly for this,
    			 * otherwise "fail" silently.
    			 */
    			if (flags)
    				warnx("use vmstat to view %s information",
    				    string);
    			return;
    		case HW_SENSORS:
    			special |= SENSORS;
    			len = sysctl_sensors(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case HW_BATTERY:
    			len = sysctl_battery(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		case HW_PHYSMEM:
    		case HW_USERMEM:
    			/*
    			 * Don't print these; we'll print the 64-bit
    			 * variants instead.
    			 */
    			return;
    		case HW_SMT:
    			if (newsize > 0)
    				warnx("hw.smt deprecated, use hw.blockcpu");
    			break;
    		}
    		break;
    
    	case CTL_VM:
    		if (mib[1] == VM_LOADAVG) {
    			double loads[3];
    
    			getloadavg(loads, 3);
    			if (!nflag)
    				(void)printf("%s%s", string, equ);
    			(void)printf("%.2f %.2f %.2f\n", loads[0],
    			    loads[1], loads[2]);
    			return;
    		} else if (mib[1] == VM_PSSTRINGS) {
    			struct _ps_strings _ps;
    
    			size = sizeof(_ps);
    			if (sysctl(mib, 2, &_ps, &size, 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%s", string, equ);
    			(void)printf("%p\n", _ps.val);
    			return;
    		} else if (mib[1] == VM_SWAPENCRYPT) {
    			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    
    			break;
    		} else if (mib[1] == VM_NKMEMPAGES ||
    		    mib[1] == VM_ANONMIN ||
    		    mib[1] == VM_VTEXTMIN ||
    		    mib[1] == VM_VNODEMIN ||
    		    mib[1] == VM_MALLOC_CONF) {
    			break;
    		}
    		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_IP && mib[3] == IPCTL_MRTSTATS) ||
    			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_STATS) ||
    			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTMFC) ||
    			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTVIF) ||
    			    (mib[2] == IPPROTO_TCP && mib[3] == TCPCTL_STATS) ||
    			    (mib[2] == IPPROTO_UDP && mib[3] == UDPCTL_STATS) ||
    			    (mib[2] == IPPROTO_ESP && mib[3] == ESPCTL_STATS) ||
    			    (mib[2] == IPPROTO_AH && mib[3] == AHCTL_STATS) ||
    			    (mib[2] == IPPROTO_IGMP && mib[3] == IGMPCTL_STATS) ||
    			    (mib[2] == IPPROTO_ETHERIP && mib[3] == ETHERIPCTL_STATS) ||
    			    (mib[2] == IPPROTO_IPIP && mib[3] == IPIPCTL_STATS) ||
    			    (mib[2] == IPPROTO_IPCOMP && mib[3] == IPCOMPCTL_STATS) ||
    			    (mib[2] == IPPROTO_ICMP && mib[3] == ICMPCTL_STATS) ||
    			    (mib[2] == IPPROTO_CARP && mib[3] == CARPCTL_STATS) ||
    			    (mib[2] == IPPROTO_PFSYNC && mib[3] == PFSYNCCTL_STATS) ||
    			    (mib[2] == IPPROTO_DIVERT && mib[3] == DIVERTCTL_STATS)) {
    				if (flags == 0)
    					return;
    				warnx("use netstat to view %s information",
    				    string);
    				return;
    			} else if ((mib[2] == IPPROTO_TCP &&
    			    (mib[3] == TCPCTL_BADDYNAMIC ||
    			    mib[3] == TCPCTL_ROOTONLY)) ||
    			    (mib[2] == IPPROTO_UDP &&
    			    (mib[3] == UDPCTL_BADDYNAMIC ||
    			    mib[3] == UDPCTL_ROOTONLY))) {
    
    				special |= BADDYNAMIC;
    
    				if (newval != NULL)
    					parse_baddynamic(mib, len, string,
    					    &newval, &newsize, flags, nflag);
    			}
    			break;
    		}
    		if (mib[1] == PF_INET6) {
    			len = sysctl_inet6(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    
    			if ((mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMFC) ||
    			    (mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMIF)) {
    				if (flags == 0)
    					return;
    				warnx("use netstat to view %s information",
    				    string);
    				return;
    			}
    			break;
    		}
    		if (mib[1] == PF_UNIX) {
    			len = sysctl_unix(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    		if (mib[1] == PF_LINK) {
    			len = sysctl_link(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    		if (mib[1] == PF_BPF) {
    			len = sysctl_bpf(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    		if (mib[1] == PF_MPLS) {
    			len = sysctl_mpls(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    		if (mib[1] == PF_PIPEX) {
    			len = sysctl_pipex(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    		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_CPUID
    		if (mib[1] == CPU_CPUID)
    			special |= HEX;
    #endif
    #ifdef CPU_CPUFEATURE
    		if (mib[1] == CPU_CPUFEATURE)
    			special |= HEX;
    #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
    #ifdef CPU_CHIPSET
    		if (mib[1] == CPU_CHIPSET) {
    			len = sysctl_chipset(string, &bufp, mib, flags, &type);
    			if (len < 0)
    				return;
    			break;
    		}
    #endif
    		break;
    
    	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_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) {
    		const char *errstr;
    
    		switch (type) {
    		case CTLTYPE_INT:
    			if (special & UNSIGNED)
    				intval = strtonum(newval, 0, UINT_MAX, &errstr);
    			else
    				intval = strtonum(newval, INT_MIN, INT_MAX,
    				    &errstr);
    			if (errstr != NULL) {
    				warnx("%s: value is %s: %s", string, errstr,
    				    (char *)newval);
    				return;
    			}
    			newval = &intval;
    			newsize = sizeof(intval);
    			break;
    
    		case CTLTYPE_QUAD:
    			(void)sscanf(newval, "%lld", &quadval);
    			newval = &quadval;
    			newsize = sizeof(quadval);
    			break;
    		case CTLTYPE_STRING:
    			if (special & HEX) {
    				ssize_t len;
    
    				len = parse_hex_string(hex, sizeof(hex),
    				    newval);
    				if (len == -1) {
    					warnx("%s: hex string %s: invalid",
    					    string, (char *)newval);
    					return;
    				}
    				if (len > sizeof(hex)) {
    					warnx("%s: hex string %s: too long",
    					    string, (char *)newval);
    					return;
    				}
    
    				newval = hex;
    				newsize = len;
    			}
    			break;
    		}
    	}
    	size = (special & SMALLBUF) ? 512 : SYSCTL_BUFSIZ;
    	if (sysctl(mib, len, buf, &size, newval, 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 & KMEMBUCKETS) {
    		struct kmembuckets *kb = (struct kmembuckets *)buf;
    		if (!nflag)
    			(void)printf("%s%s", string, equ);
    		printf("(");
    		printf("calls = %llu ", (long long)kb->kb_calls);
    		printf("total_allocated = %llu ", (long long)kb->kb_total);
    		printf("total_free = %lld ", (long long)kb->kb_totalfree);
    		printf("elements = %lld ", (long long)kb->kb_elmpercl);
    		printf("high watermark = %lld ", (long long)kb->kb_highwat);
    		printf("could_free = %lld", (long long)kb->kb_couldfree);
    		printf(")\n");
    		return;
    	}
    	if (special & KMEMSTATS) {
    		struct kmemstats *km = (struct kmemstats *)buf;
    		int j, first = 1;
    
    		if (!nflag)
    			(void)printf("%s%s", string, equ);
    		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, "
    		    "limblocks = %d, maxused = %ldK, "
    		    "limit = %ldK, spare = %ld, sizes = (",
    		    km->ks_inuse, km->ks_calls,
    		    (km->ks_memuse + 1023) / 1024, km->ks_limblocks,
    		    (km->ks_maxused + 1023) / 1024,
    		    (km->ks_limit + 1023) / 1024, km->ks_spare);
    		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
    			if ((km->ks_size & j ) == 0)
    				continue;
    			if (first)
    				(void)printf("%d", j);
    			else
    				(void)printf(",%d", j);
    			first = 0;
    		}
    		if (first)
    			(void)printf("none");
    		(void)printf("))\n");
    		return;
    	}
    	if (special & CLOCK) {
    		struct clockinfo *clkp = (struct clockinfo *)buf;
    
    		if (!nflag)
    			(void)printf("%s%s", string, equ);
    		(void)printf(
    		    "tick = %d, hz = %d, profhz = %d, stathz = %d\n",
    		    clkp->tick, clkp->hz, clkp->profhz, clkp->stathz);
    		return;
    	}
    	if (special & BOOTTIME) {
    		struct timeval *btp = (struct timeval *)buf;
    
    		if (!nflag) {
    			char *ct;
    			boottime = btp->tv_sec;
    			ct = ctime(&boottime);
    			if (ct)
    				(void)printf("%s%s%s", string, equ, ct);
    			else
    				(void)printf("%s%s%lld\n", string, equ,
    				    boottime);
    		} else
    			(void)printf("%lld\n", (long long)btp->tv_sec);
    		return;
    	}
    	if (special & BLKDEV) {
    		dev_t dev = *(dev_t *)buf;
    
    		if (!nflag)
    			(void)printf("%s%s%s\n", string, equ,
    			    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%s\n", string, equ,
    			    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%s", string, equ);
    		(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%s", string, equ);
    		(void) printf("0x%02x\n", dev);
    		return;
    	}
    #endif
    	if (special & UNSIGNED) {
    		if (newsize == 0) {
    			if (!nflag)
    				(void)printf("%s%s", string, equ);
    			(void)printf("%u\n", *(u_int *)buf);
    		} else {
    			if (!qflag) {
    				if (!nflag)
    					(void)printf("%s: %u -> ", string,
    					    *(u_int *)buf);
    				(void)printf("%u\n", *(u_int *)newval);
    			}
    		}
    		return;
    	}
    	if (special & BADDYNAMIC) {
    		u_int port, lastport;
    		u_int32_t *baddynamic = (u_int32_t *)buf;
    
    		if (!qflag) {
    			if (!nflag)
    				(void)printf("%s%s", string,
    				    newsize ? ": " : equ);
    			lastport = 0;
    			for (port = 0; port < 65536; port++)
    				if (DP_ISSET(baddynamic, port)) {
    					(void)printf("%s%u",
    					    lastport ? "," : "", port);
    					lastport = port;
    				}
    			if (newsize != 0) {
    				if (!nflag)
    					fputs(" -> ", stdout);
    				baddynamic = (u_int32_t *)newval;
    				lastport = 0;
    				for (port = 0; port < 65536; port++)
    					if (DP_ISSET(baddynamic, port)) {
    						(void)printf("%s%u",
    						    lastport ? "," : "", port);
    						lastport = port;
    					}
    			}
    			(void)putchar('\n');
    		}
    		return;
    	}
    	if (special & LONGARRAY) {
    		long *la = (long *)buf;
    		if (!nflag)
    			printf("%s%s", string, equ);
    		while (lal--)
    			printf("%ld%s", *la++, lal? ",":"");
    		putchar('\n');
    		return;
    	}
    	if (special & SENSORS) {
    		struct sensor *s = (struct sensor *)buf;
    
    		if (size > 0 && (s->flags & SENSOR_FINVALID) == 0) {
    			if (!nflag)
    				printf("%s%s", string, equ);
    			print_sensor(s);
    			printf("\n");
    		}
    		return;
    	}
    	if (special & TIMEOUT) {
    		struct timeoutstat *tstat = (struct timeoutstat *)buf;
    
    		if (!nflag)
    			printf("%s%s", string, equ);
    		printf("added = %llu, cancelled = %llu, deleted = %llu, "
    		    "late = %llu, pending = %llu, readded = %llu, "
    		    "scheduled = %llu, rescheduled = %llu, "
    		    "run_softclock = %llu, run_thread = %llu, "
    		    "softclocks = %llu, thread_wakeups = %llu\n",
    		    tstat->tos_added, tstat->tos_cancelled, tstat->tos_deleted,
    		    tstat->tos_late, tstat->tos_pending, tstat->tos_readded,
    		    tstat->tos_scheduled, tstat->tos_rescheduled,
    		    tstat->tos_run_softclock, tstat->tos_run_thread,
    		    tstat->tos_softclocks, tstat->tos_thread_wakeups);
    		return;
    	}
    	switch (type) {
    	case CTLTYPE_INT:
    		if (newsize == 0) {
    			if (!nflag)
    				(void)printf("%s%s", string, equ);
    			if (special & HEX)
    				(void)printf("0x%x\n", *(int *)buf);
    			else
    				(void)printf("%d\n", *(int *)buf);
    		} else {
    			if (!qflag) {
    				if (!nflag)
    					(void)printf("%s: %d -> ", string,
    					    *(int *)buf);
    				if (special & HEX)
    					(void)printf("0x%x\n", *(int *)newval);
    				else
    					(void)printf("%d\n", *(int *)newval);
    			}
    		}
    		return;
    
    	case CTLTYPE_STRING:
    		if (newval == NULL) {
    			if (!nflag)
    				(void)printf("%s%s", string, equ);
    			if (special & HEX) {
    				size_t i;
    				for (i = 0; i < size; i++) {
    					(void)printf("%02x",
    					    (unsigned char)buf[i]);
    				}
    				(void)printf("\n");
    			} else
    				(void)puts(buf);
    		} else if (!qflag) {
    			if (!nflag) {
    				(void)printf("%s: ", string);
    				if (special & HEX) {
    					size_t i;
    					for (i = 0; i < size; i++) {
    						(void)printf("%02x",
    						    (unsigned char)buf[i]);
    					}
    				} else
    					(void)printf("%s", buf);
    
    				(void)printf(" -> ");
    			}
    			(void)puts(cp);
    		}
    		return;
    
    	case CTLTYPE_QUAD:
    		if (newsize == 0) {
    			int64_t tmp;
    
    			memcpy(&tmp, buf, sizeof tmp);
    			if (!nflag)
    				(void)printf("%s%s", string, equ);
    			(void)printf("%lld\n", tmp);
    		} else {
    			int64_t tmp;
    
    			memcpy(&tmp, buf, sizeof tmp);
    			if (!qflag) {
    				if (!nflag)
    					(void)printf("%s: %lld -> ",
    					    string, tmp);
    				memcpy(&tmp, newval, sizeof tmp);
    				(void)printf("%lld\n", tmp);
    			}
    		}
    		return;
    
    	case CTLTYPE_STRUCT:
    		warnx("%s: unknown structure returned", string);
    		return;
    
    	default:
    	case CTLTYPE_NODE:
    		warnx("%s: unknown type returned", string);
    		return;
    	}
    }
    
    static void
    parse_ports(char *portspec, int *port, int *high_port)
    {
    	char *dash;
    	const char *errstr;
    
    	if ((dash = strchr(portspec, '-')) != NULL)
    		*dash++ = '\0';
    	*port = strtonum(portspec, 0, 65535, &errstr);
    	if (errstr != NULL)
    		errx(1, "port is %s: %s", errstr, portspec);
    	if (dash != NULL) {
    		*high_port = strtonum(dash, 0, 65535, &errstr);
    		if (errstr != NULL)
    			errx(1, "high port is %s: %s", errstr, dash);
    		if (*high_port < *port)
    			errx(1, "high port %d is lower than %d",
    			    *high_port, *port);
    	} else
    		*high_port = *port;
    }
    
    void
    parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
        size_t *newsizep, int flags, int nflag)
    {
    	static u_int32_t newbaddynamic[DP_MAPSIZE];
    	int port, high_port, baddynamic_loaded = 0, full_list_set = 0;
    	size_t size;
    	char action, *cp;
    
    	while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
    		if (*cp == '+' || *cp == '-') {
    			if (full_list_set)
    				errx(1, "cannot mix +/- with full list");
    			action = *cp++;
    			if (!baddynamic_loaded) {
    				size = sizeof(newbaddynamic);
    				if (sysctl(mib, len, newbaddynamic,
    				    &size, 0, 0) == -1) {
    					if (flags == 0)
    						return;
    					if (!nflag)
    						printf("%s: ", string);
    					puts("kernel does not contain bad "
    					    "dynamic port tables");
    					return;
    				}
    				baddynamic_loaded = 1;
    			}
    			parse_ports(cp, &port, &high_port);
    			for (; port <= high_port; port++) {
    				if (action == '+')
    					DP_SET(newbaddynamic, port);
    				else
    					DP_CLR(newbaddynamic, port);
    			}
    		} else {
    			if (baddynamic_loaded)
    				errx(1, "cannot mix +/- with full list");
    			if (!full_list_set) {
    				bzero(newbaddynamic, sizeof(newbaddynamic));
    				full_list_set = 1;
    			}
    			parse_ports(cp, &port, &high_port);
    			for (; port <= high_port; port++)
    				DP_SET(newbaddynamic, port);
    		}
    	}
    	*newvalp = (void *)newbaddynamic;
    	*newsizep = sizeof(newbaddynamic);
    }
    
    /*
     * Initialize the set of debugging names
     */
    void
    debuginit(void)
    {
    	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 ctlname fusefsname[] = FUSEFS_NAMES;
    struct list *vfsvars;
    int *vfs_typenums;
    
    /*
     * Initialize the set of filesystem names
     */
    void
    vfsinit(void)
    {
    	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, NULL, 0) == -1)
    		return;
    	/*
             * We need to do 0..maxtypenum so add one, and then we offset them
    	 * all by (another) one by inserting VFS_GENERIC entries at zero
    	 */
    	maxtypenum += 2;
    	if ((vfs_typenums = calloc(maxtypenum, sizeof(int))) == NULL)
    		return;
    	if ((vfsvars = calloc(maxtypenum, sizeof(*vfsvars))) == NULL) {
    		free(vfs_typenums);
    		return;
    	}
    	if ((vfsname = calloc(maxtypenum, sizeof(*vfsname))) == NULL) {
    		free(vfs_typenums);
    		free(vfsvars);
    		return;
    	}
    	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, NULL, 0) == -1) {
    			if (errno == EOPNOTSUPP)
    				continue;
    			warn("vfsinit");
    			free(vfsname);
    			free(vfsvars);
    			free(vfs_typenums);
    			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;
    		}
    		if (!strcmp(vfc.vfc_name, MOUNT_FUSEFS)) {
    			vfsvars[cnt].list = fusefsname;
    			vfsvars[cnt].size = FUSEFS_MAXID;
    		}
    		vfs_typenums[cnt] = vfc.vfc_typenum;
    		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
    		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(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, NULL, 0) == -1) {
    		if (errno != EOPNOTSUPP)
    			warn("vfs print");
    		return -1;
    	}
    	if (flags == 0 && vfc.vfc_refcount == 0)
    		return -1;
    	if (!nflag)
    		fprintf(stdout, "%s has %u mounted instance%s\n",
    		    string, vfc.vfc_refcount,
    		    vfc.vfc_refcount != 1 ? "s" : "");
    	else
    		fprintf(stdout, "%u\n", vfc.vfc_refcount);
    
    	return -1;
    }
    
    int
    sysctl_vfs(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);
    }
    
    #ifdef CPU_BIOS
    struct ctlname biosname[] = CTL_BIOS_NAMES;
    struct list bioslist = { biosname, BIOS_MAXID };
    
    /*
     * handle BIOS requests
     */
    int
    sysctl_bios(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) {
    		const char *errstr;
    
    		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] = strtonum(name, 0, INT_MAX, &errstr);
    		if (errstr) {
    			warnx("%s: %s", string, errstr);
    			return (-1);
    		}
    		*typep = CTLTYPE_STRUCT;
    		return (4);
    	} else {
    		*typep = bioslist.list[indx].ctl_type;
    		return (3);
    	}
    }
    #endif
    
    struct ctlname swpencname[] = CTL_SWPENC_NAMES;
    struct list swpenclist = { swpencname, SWPENC_MAXID };
    
    /*
     * handle swap encrypt requests
     */
    int
    sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	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);
    }
    
    struct ctlname inetname[] = CTL_IPPROTO_NAMES;
    struct ctlname ipname[] = IPCTL_NAMES;
    struct ctlname icmpname[] = ICMPCTL_NAMES;
    struct ctlname igmpname[] = IGMPCTL_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 ipcompname[] = IPCOMPCTL_NAMES;
    struct ctlname carpname[] = CARPCTL_NAMES;
    struct ctlname pfsyncname[] = PFSYNCCTL_NAMES;
    struct ctlname divertname[] = DIVERTCTL_NAMES;
    struct ctlname bpfname[] = CTL_NET_BPF_NAMES;
    struct ctlname ifqname[] = CTL_IFQ_NAMES;
    struct ctlname pipexname[] = PIPEXCTL_NAMES;
    struct list inetlist = { inetname, IPPROTO_MAXID };
    struct list inetvars[] = {
    	{ ipname, IPCTL_MAXID },	/* ip */
    	{ icmpname, ICMPCTL_MAXID },	/* icmp */
    	{ igmpname, IGMPCTL_MAXID },	/* 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 },
    	{ 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 },
    	{ 0, 0 },
    	{ etheripname, ETHERIPCTL_MAXID },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ ipcompname, IPCOMPCTL_MAXID },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ carpname, CARPCTL_MAXID },
    	{ 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 },
    	{ 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 },
    	{ 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 },
    	{ 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 },
    	{ pfsyncname, PFSYNCCTL_MAXID },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ divertname, DIVERTCTL_MAXID },
    };
    struct list bpflist = { bpfname, NET_BPF_MAXID };
    struct list ifqlist = { ifqname, IFQCTL_MAXID };
    struct list pipexlist = { pipexname, PIPEXCTL_MAXID };
    
    struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
    struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
    struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
    struct list ttylist = { ttysname, KERN_TTY_MAXID };
    struct list semlist = { semname, KERN_SEMINFO_MAXID };
    struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
    struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
    struct list tclist = { tcname, KERN_TIMECOUNTER_MAXID };
    struct list audiolist = { audioname, KERN_AUDIO_MAXID };
    struct list videolist = { videoname, KERN_VIDEO_MAXID };
    struct list witnesslist = { witnessname, KERN_WITNESS_MAXID };
    struct list batterylist = { batteryname, HW_BATTERY_MAXID };
    
    /*
     * handle vfs namei cache statistics
     */
    int
    sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	static struct nchstats nch;
    	int indx;
    	size_t size;
    	static int keepvalue = 0;
    
    	if (*bufpp == NULL) {
    		bzero(&nch, sizeof(struct nchstats));
    		listall(string, &nchstatslist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	if (*bufpp != NULL) {
    		warnx("fourth level name in %s is invalid", string);
    		return (-1);
    	}
    	if (keepvalue == 0) {
    		size = sizeof(struct nchstats);
    		if (sysctl(mib, 2, &nch, &size, NULL, 0) == -1)
    			return (-1);
    		keepvalue = 1;
    	}
    	if (!nflag)
    		(void)printf("%s%s", string, equ);
    	switch (indx) {
    	case KERN_NCHSTATS_GOODHITS:
    		(void)printf("%llu\n", nch.ncs_goodhits);
    		break;
    	case KERN_NCHSTATS_NEGHITS:
    		(void)printf("%llu\n", nch.ncs_neghits);
    		break;
    	case KERN_NCHSTATS_BADHITS:
    		(void)printf("%llu\n", nch.ncs_badhits);
    		break;
    	case KERN_NCHSTATS_FALSEHITS:
    		(void)printf("%llu\n", nch.ncs_falsehits);
    		break;
    	case KERN_NCHSTATS_MISS:
    		(void)printf("%llu\n", nch.ncs_miss);
    		break;
    	case KERN_NCHSTATS_LONG:
    		(void)printf("%llu\n", nch.ncs_long);
    		break;
    	case KERN_NCHSTATS_PASS2:
    		(void)printf("%llu\n", nch.ncs_pass2);
    		break;
    	case KERN_NCHSTATS_2PASSES:
    		(void)printf("%llu\n", nch.ncs_2passes);
    		break;
    	case KERN_NCHSTATS_REVHITS:
    		(void)printf("%llu\n", nch.ncs_revhits);
    		break;
    	case KERN_NCHSTATS_REVMISS:
    		(void)printf("%llu\n", nch.ncs_revmiss);
    		break;
    	case KERN_NCHSTATS_DOTHITS:
    		(void)printf("%llu\n", nch.ncs_dothits);
    		break;
    	case KERN_NCHSTATS_DOTDOTHITS:
    		(void)printf("%llu\n", nch.ncs_dotdothits);
    		break;
    	}
    	return (-1);
    }
    
    /*
     * handle tty statistics
     */
    int
    sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &ttylist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
    		return (-1);
    	mib[2] = indx;
    
    	if ((*typep = ttylist.list[indx].ctl_type) == CTLTYPE_STRUCT) {
    		if (flags)
    			warnx("use pstat -t to view %s information",
    			    string);
    		return (-1);
    	}
    	return (3);
    }
    
    /*
     * handle fork statistics
     */
    int
    sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	static struct forkstat fks;
    	static int keepvalue = 0;
    	int indx;
    	size_t size;
    
    	if (*bufpp == NULL) {
    		bzero(&fks, sizeof(struct forkstat));
    		listall(string, &forkstatlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
    		return (-1);
    	if (*bufpp != NULL) {
    		warnx("fourth level name in %s is invalid", string);
    		return (-1);
    	}
    	if (keepvalue == 0) {
    		size = sizeof(struct forkstat);
    		if (sysctl(mib, 2, &fks, &size, NULL, 0) == -1)
    			return (-1);
    		keepvalue = 1;
    	}
    	if (!nflag)
    		(void)printf("%s%s", string, equ);
    	switch (indx)	{
    	case KERN_FORKSTAT_FORK:
    		(void)printf("%u\n", fks.cntfork);
    		break;
    	case KERN_FORKSTAT_VFORK:
    		(void)printf("%u\n", fks.cntvfork);
    		break;
    	case KERN_FORKSTAT_TFORK:
    		(void)printf("%u\n", fks.cnttfork);
    		break;
    	case KERN_FORKSTAT_KTHREAD:
    		(void)printf("%u\n", fks.cntkthread);
    		break;
    	case KERN_FORKSTAT_SIZFORK:
    		(void)printf("%llu\n", fks.sizfork);
    		break;
    	case KERN_FORKSTAT_SIZVFORK:
    		(void)printf("%llu\n", fks.sizvfork);
    		break;
    	case KERN_FORKSTAT_SIZTFORK:
    		(void)printf("%llu\n", fks.siztfork);
    		break;
    	case KERN_FORKSTAT_SIZKTHREAD:
    		(void)printf("%llu\n", fks.sizkthread);
    		break;
    	}
    	return (-1);
    }
    
    /*
     * handle malloc statistics
     */
    int
    sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx, stor, i;
    	char *name, bufp[SYSCTL_BUFSIZ], *buf, *ptr;
    	const char *errstr;
    	struct list lp;
    	size_t size;
    
    	if (*bufpp == NULL) {
    		listall(string, &kernmalloclist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	if (mib[2] == KERN_MALLOC_BUCKET) {
    		if ((name = strsep(bufpp, ".")) == NULL) {
    			size = SYSCTL_BUFSIZ;
    			stor = mib[2];
    			mib[2] = KERN_MALLOC_BUCKETS;
    			buf = bufp;
    			if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
    				return (-1);
    			mib[2] = stor;
    			for (stor = 0, i = 0; i < size; i++)
    				if (buf[i] == ',')
    					stor++;
    			lp.list = calloc(stor + 2, sizeof(struct ctlname));
    			if (lp.list == NULL)
    				return (-1);
    			lp.size = stor + 2;
    			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
    			        lp.list[i].ctl_name = ptr;
    				lp.list[i].ctl_type = CTLTYPE_STRUCT;
    			}
    			listall(string, &lp);
    			free(lp.list);
    			return (-1);
    		}
    		mib[3] = strtonum(name, 0, INT_MAX, &errstr);
    		if (errstr)
    			return -1;
    		return (4);
    	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
    		*typep = CTLTYPE_STRING;
    		return (3);
    	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
    		size = SYSCTL_BUFSIZ;
    		stor = mib[2];
    		mib[2] = KERN_MALLOC_KMEMNAMES;
    		buf = bufp;
    		if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
    			return (-1);
    		mib[2] = stor;
    		if ((name = strsep(bufpp, ".")) == NULL) {
    			for (stor = 0, i = 0; i < size; i++)
    				if (buf[i] == ',')
    					stor++;
    			lp.list = calloc(stor + 2, sizeof(struct ctlname));
    			if (lp.list == NULL)
    				return (-1);
    			lp.size = stor + 2;
    			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
    				if (ptr[0] == '\0') {
    					i--;
    					continue;
    				}
    			    	lp.list[i].ctl_name = ptr;
    				lp.list[i].ctl_type = CTLTYPE_STRUCT;
    			}
    			listall(string, &lp);
    			free(lp.list);
    			return (-1);
    		}
    		ptr = strstr(buf, name);
     tryagain:
    		if (ptr == NULL) {
    			warnx("fourth level name %s in %s is invalid", name,
    			    string);
    			return (-1);
    		}
    		if ((*(ptr + strlen(name)) != ',') &&
    		    (*(ptr + strlen(name)) != '\0')) {
    			ptr = strstr(ptr + 1, name); /* retry */
    			goto tryagain;
    		}
    		if ((ptr != buf) && (*(ptr - 1) != ',')) {
    			ptr = strstr(ptr + 1, name); /* retry */
    			goto tryagain;
    		}
    		for (i = 0, stor = 0; buf + i < ptr; i++)
    			if (buf[i] == ',')
    				stor++;
    		mib[3] = stor;
    		return (4);
    	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
    		*typep = CTLTYPE_STRING;
    		return (3);
    	}
    	return (-1);
    }
    
    #ifdef CPU_CHIPSET
    /*
     * handle machdep.chipset requests
     */
    struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
    struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
    
    int
    sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx, bwx;
    	static void *q;
    	size_t len;
    	char *p;
    
    	if (*bufpp == NULL) {
    		listall(string, &chipsetlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	if (!nflag)
    		printf("%s%s", string, equ);
    	switch(mib[2]) {
    	case CPU_CHIPSET_MEM:
    	case CPU_CHIPSET_DENSE:
    	case CPU_CHIPSET_PORTS:
    	case CPU_CHIPSET_HAE_MASK:
    		len = sizeof(void *);
    		if (sysctl(mib, 3, &q, &len, NULL, 0) == -1)
    			goto done;
    		printf("%p", q);
    		break;
    	case CPU_CHIPSET_BWX:
    		len = sizeof(int);
    		if (sysctl(mib, 3, &bwx, &len, NULL, 0) == -1)
    			goto done;
    		printf("%d", bwx);
    		break;
    	case CPU_CHIPSET_TYPE:
    		if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1)
    			goto done;
    		p = malloc(len + 1);
    		if (p == NULL)
    			goto done;
    		if (sysctl(mib, 3, p, &len, NULL, 0) == -1) {
    			free(p);
    			goto done;
    		}
    		p[len] = '\0';
    		printf("%s", p);
    		free(p);
    		break;
    	}
    done:
    	printf("\n");
    	return (-1);
    }
    #endif
    /*
     * handle internet requests
     */
    int
    sysctl_inet(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;
    	if (*typep == CTLTYPE_NODE) {
    		int tindx;
    
    		if (*bufpp == NULL) {
    			listall(string, &ifqlist);
    			return(-1);
    		}
    		lp = &ifqlist;
    		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
    			return (-1);
    		mib[4] = tindx;
    		*typep = lp->list[tindx].ctl_type;
    		return(5);
    	}
    	return (4);
    }
    
    struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
    struct ctlname ip6name[] = IPV6CTL_NAMES;
    struct ctlname icmp6name[] = ICMPV6CTL_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 },
    	{ 0, 0 },	/* pim6 */
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    /*110*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*120*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*130*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*140*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*150*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*160*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*170*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*180*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*190*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*200*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*210*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*220*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*230*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*240*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
    /*250*/	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    	{ 0, 0 },
    };
    
    /*
     * handle internet6 requests
     */
    int
    sysctl_inet6(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;
    	if (*typep == CTLTYPE_NODE) {
    		int tindx;
    
    		if (*bufpp == NULL) {
    			listall(string, &ifqlist);
    			return(-1);
    		}
    		lp = &ifqlist;
    		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
    			return (-1);
    		mib[4] = tindx;
    		*typep = lp->list[tindx].ctl_type;
    		return(5);
    	}
    	return (4);
    }
    
    /* handle net.unix requests */
    struct ctlname netunixname[] = CTL_NET_UNIX_NAMES;
    struct ctlname netunixprotoname[] = CTL_NET_UNIX_PROTO_NAMES;
    struct list netunixlist = { netunixname, NET_UNIX_MAXID };
    struct list netunixvars[] = {
    	[SOCK_STREAM] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
    	[SOCK_DGRAM] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
    	[SOCK_SEQPACKET] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
    	[NET_UNIX_MAXID] = { 0, 0 },
    };
    
    int
    sysctl_unix(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	struct list *lp;
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &netunixlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &netunixlist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = netunixname[indx].ctl_type;
    
    	if (indx < NET_UNIX_MAXID && netunixvars[indx].list != NULL)
    		lp = &netunixvars[indx];
    	else
    		return (3);
    
    	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);
    }
    
    /* handle net.link requests */
    struct ctlname netlinkname[] = CTL_NET_LINK_NAMES;
    struct ctlname ifrxqname[] = CTL_NET_LINK_IFRXQ_NAMES;
    struct list netlinklist = { netlinkname, NET_LINK_MAXID };
    struct list netlinkvars[] = {
    	[NET_LINK_IFRXQ] = { ifrxqname, NET_LINK_IFRXQ_MAXID },
    };
    
    int
    sysctl_link(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	struct list *lp;
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &netlinklist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &netlinklist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	if (indx < NET_LINK_MAXID && netlinkvars[indx].list != NULL)
    		lp = &netlinkvars[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);
    }
    
    /* handle bpf requests */
    int
    sysctl_bpf(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &bpflist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &bpflist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = CTLTYPE_INT;
    	return (3);
    }
    
    struct ctlname mplsname[] = MPLSCTL_NAMES;
    struct list mplslist = { mplsname, MPLSCTL_MAXID };
    
    /* handle MPLS requests */
    int
    sysctl_mpls(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	struct list *lp;
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &mplslist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &mplslist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = mplslist.list[indx].ctl_type;
    	if (*typep == CTLTYPE_NODE) {
    		int tindx;
    
    		if (*bufpp == NULL) {
    			listall(string, &ifqlist);
    			return(-1);
    		}
    		lp = &ifqlist;
    		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
    			return (-1);
    		mib[3] = tindx;
    		*typep = lp->list[tindx].ctl_type;
    		return(4);
    	}
    	return (3);
    }
    
    /* handle PIPEX requests */
    int
    sysctl_pipex(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	struct list *lp;
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &pipexlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &pipexlist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = pipexlist.list[indx].ctl_type;
    	if (*typep == CTLTYPE_NODE) {
    		int tindx;
    
    		if (*bufpp == NULL) {
    			listall(string, &ifqlist);
    			return(-1);
    		}
    		lp = &ifqlist;
    		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
    			return (-1);
    		mib[3] = tindx;
    		*typep = lp->list[tindx].ctl_type;
    		return(4);
    	}
    	return (3);
    }
    
    /*
     * Handle SysV semaphore info requests
     */
    int
    sysctl_seminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &semlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = CTLTYPE_INT;
    	return (3);
    }
    
    /*
     * Handle SysV shared memory info requests
     */
    int
    sysctl_shminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &shmlist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = CTLTYPE_INT;
    	return (3);
    }
    
    /*
     * Handle watchdog support
     */
    int
    sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
        int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &watchdoglist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = watchdoglist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Handle timecounter support
     */
    int
    sysctl_tc(char *string, char **bufpp, int mib[], int flags,
        int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &tclist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &tclist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = tclist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Handle hardware monitoring sensors support
     */
    int
    sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	char *devname, *typename;
    	int dev, numt, i;
    	enum sensor_type type;
    	struct sensordev snsrdev;
    	size_t sdlen = sizeof(snsrdev);
    
    	if (*bufpp == NULL) {
    		char buf[SYSCTL_BUFSIZ];
    
    		/* scan all sensor devices */
    		for (dev = 0; ; dev++) {
    			mib[2] = dev;
    			if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
    				if (errno == ENXIO)
    					continue;
    				if (errno == ENOENT)
    					break;
    				warn("sensors dev %d", dev);
    				return (-1);
    			}
    			snprintf(buf, sizeof(buf), "%s.%s",
    			    string, snsrdev.xname);
    			print_sensordev(buf, mib, 3, &snsrdev);
    		}
    		return (-1);
    	}
    
    	/*
    	 * If we get this far, it means that some arguments were
    	 * provided below hw.sensors tree.
    	 * The first branch of hw.sensors tree is the device name.
    	 */
    	if ((devname = strsep(bufpp, ".")) == NULL) {
    		warnx("%s: incomplete specification", string);
    		return (-1);
    	}
    	/* convert sensor device string to an integer */
    	for (dev = 0; ; dev++) {
    		mib[2] = dev;
    		if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
    			if (errno == ENXIO)
    				continue;
    			if (errno == ENOENT)
    				break;
    			warn("sensors dev %d", dev);
    			return (-1);
    		}
    		if (strcmp(devname, snsrdev.xname) == 0)
    			break;
    	}
    	if (strcmp(devname, snsrdev.xname) != 0) {
    		warnx("%s: sensor device not found: %s", string, devname);
    		return (-1);
    	}
    	if (*bufpp == NULL) {
    		/* only device name was provided -- let's print all sensors
    		 * that are attached to the specified device
    		 */
    		print_sensordev(string, mib, 3, &snsrdev);
    		return (-1);
    	}
    
    	/*
    	 * At this point we have identified the sensor device,
    	 * now let's go further and identify sensor type.
    	 */
    	if ((typename = strsep(bufpp, ".")) == NULL) {
    		warnx("%s: incomplete specification", string);
    		return (-1);
    	}
    	numt = -1;
    	for (i = 0; typename[i] != '\0'; i++)
    		if (isdigit((unsigned char)typename[i])) {
    			const char *errstr;
    
    			numt = strtonum(&typename[i], 0, INT_MAX, &errstr);
    			if (errstr) {
    				warnx("%s: %s", string, errstr);
    				return (-1);
    			}
    			typename[i] = '\0';
    			break;
    		}
    	for (type = 0; type < SENSOR_MAX_TYPES; type++)
    		if (strcmp(typename, sensor_type_s[type]) == 0)
    			break;
    	if (type == SENSOR_MAX_TYPES) {
    		warnx("%s: sensor type not recognised: %s", string, typename);
    		return (-1);
    	}
    	mib[3] = type;
    
    	/*
    	 * If no integer was provided after sensor_type, let's
    	 * print all sensors of the specified type.
    	 */
    	if (numt == -1) {
    		print_sensordev(string, mib, 4, &snsrdev);
    		return (-1);
    	}
    
    	/*
    	 * At this point we know that we have received a direct request
    	 * via command-line for a specific sensor. Let's have the parse()
    	 * function deal with it further, and report any errors if such
    	 * sensor node does not exist.
    	 */
    	mib[4] = numt;
    	*typep = CTLTYPE_STRUCT;
    	return (5);
    }
    
    /*
     * Print sensors from the specified device.
     */
    
    void
    print_sensordev(char *string, int mib[], u_int mlen, struct sensordev *snsrdev)
    {
    	char buf[SYSCTL_BUFSIZ];
    	enum sensor_type type;
    
    	if (mlen == 3) {
    		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
    			mib[3] = type;
    			snprintf(buf, sizeof(buf), "%s.%s",
    			    string, sensor_type_s[type]);
    			print_sensordev(buf, mib, mlen+1, snsrdev);
    		}
    		return;
    	}
    
    	if (mlen == 4) {
    		int numt;
    
    		type = mib[3];
    		for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
    			mib[4] = numt;
    			snprintf(buf, sizeof(buf), "%s%u", string, numt);
    			print_sensordev(buf, mib, mlen+1, snsrdev);
    		}
    		return;
    	}
    
    	if (mlen == 5) {
    		struct sensor snsr;
    		size_t slen = sizeof(snsr);
    
    		/* this function is only printing sensors in bulk, so we
    		 * do not return any error messages if the requested sensor
    		 * is not found by sysctl(3)
    		 */
    		if (sysctl(mib, 5, &snsr, &slen, NULL, 0) == -1)
    			return;
    
    		if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0) {
    			if (!nflag)
    				printf("%s%s", string, equ);
    			print_sensor(&snsr);
    			printf("\n");
    		}
    		return;
    	}
    }
    
    void
    print_sensor(struct sensor *s)
    {
    	const char *name;
    
    	if (s->flags & SENSOR_FUNKNOWN)
    		printf("unknown");
    	else {
    		switch (s->type) {
    		case SENSOR_TEMP:
    			printf("%.2f degC",
    			    (s->value - 273150000) / 1000000.0);
    			break;
    		case SENSOR_FANRPM:
    			printf("%lld RPM", s->value);
    			break;
    		case SENSOR_VOLTS_DC:
    			printf("%.2f VDC", s->value / 1000000.0);
    			break;
    		case SENSOR_VOLTS_AC:
    			printf("%.2f VAC", s->value / 1000000.0);
    			break;
    		case SENSOR_OHMS:
    			printf("%lld ohm", s->value);
    			break;
    		case SENSOR_WATTS:
    			printf("%.2f W", s->value / 1000000.0);
    			break;
    		case SENSOR_AMPS:
    			printf("%.2f A", s->value / 1000000.0);
    			break;
    		case SENSOR_WATTHOUR:
    			printf("%.2f Wh", s->value / 1000000.0);
    			break;
    		case SENSOR_AMPHOUR:
    			printf("%.2f Ah", s->value / 1000000.0);
    			break;
    		case SENSOR_INDICATOR:
    			printf("%s", s->value ? "On" : "Off");
    			break;
    		case SENSOR_INTEGER:
    			printf("%lld", s->value);
    			break;
    		case SENSOR_PERCENT:
    			printf("%.2f%%", s->value / 1000.0);
    			break;
    		case SENSOR_LUX:
    			printf("%.2f lx", s->value / 1000000.0);
    			break;
    		case SENSOR_DRIVE:
    			switch (s->value) {
    			case SENSOR_DRIVE_EMPTY:
    				name = "empty";
    				break;
    			case SENSOR_DRIVE_READY:
    				name = "ready";
    				break;
    			case SENSOR_DRIVE_POWERUP:
    				name = "powering up";
    				break;
    			case SENSOR_DRIVE_ONLINE:
    				name = "online";
    				break;
    			case SENSOR_DRIVE_IDLE:
    				name = "idle";
    				break;
    			case SENSOR_DRIVE_ACTIVE:
    				name = "active";
    				break;
    			case SENSOR_DRIVE_REBUILD:
    				name = "rebuilding";
    				break;
    			case SENSOR_DRIVE_POWERDOWN:
    				name = "powering down";
    				break;
    			case SENSOR_DRIVE_FAIL:
    				name = "failed";
    				break;
    			case SENSOR_DRIVE_PFAIL:
    				name = "degraded";
    				break;
    			default:
    				name = "unknown";
    				break;
    			}
    			printf("%s", name);
    			break;
    		case SENSOR_TIMEDELTA:
    			printf("%.6f secs", s->value / 1000000000.0);
    			break;
    		case SENSOR_HUMIDITY:
    			printf("%.2f%%", s->value / 1000.0);
    			break;
    		case SENSOR_FREQ:
    			printf("%.2f Hz", s->value / 1000000.0);
    			break;
    		case SENSOR_ANGLE:
    			printf("%3.4f degrees", s->value / 1000000.0);
    			break;
    		case SENSOR_DISTANCE:
    			printf("%.3f m", s->value / 1000000.0);
    			break;
    		case SENSOR_PRESSURE:
    			printf("%.2f Pa", s->value / 1000.0);
    			break;
    		case SENSOR_ACCEL:
    			printf("%2.4f m/s^2", s->value / 1000000.0);
    			break;
    		case SENSOR_VELOCITY:
    			printf("%4.3f m/s", s->value / 1000000.0);
    			break;
    		case SENSOR_ENERGY:
    			printf("%.2f J", s->value / 1000000.0);
    			break;
    		default:
    			printf("unknown");
    		}
    	}
    
    	if (s->desc[0] != '\0')
    		printf(" (%s)", s->desc);
    
    	switch (s->status) {
    	case SENSOR_S_UNSPEC:
    		break;
    	case SENSOR_S_OK:
    		printf(", OK");
    		break;
    	case SENSOR_S_WARN:
    		printf(", WARNING");
    		break;
    	case SENSOR_S_CRIT:
    		printf(", CRITICAL");
    		break;
    	case SENSOR_S_UNKNOWN:
    		printf(", UNKNOWN");
    		break;
    	}
    
    	if (s->tv.tv_sec) {
    		time_t t = s->tv.tv_sec;
    		char ct[26];
    
    		if (ctime_r(&t, ct)) {
    			ct[19] = '\0';
    			printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
    		} else
    			printf(", %lld.%03ld", t, s->tv.tv_usec / 1000);
    	}
    }
    
    /*
     * Handle audio support
     */
    int
    sysctl_audio(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &audiolist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &audiolist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = audiolist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Handle video support
     */
    int
    sysctl_video(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &videolist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &videolist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = videolist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Handle witness support
     */
    int
    sysctl_witness(char *string, char **bufpp, int mib[], int flags, int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &witnesslist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &witnesslist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = witnesslist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Handle battery support
     */
    int
    sysctl_battery(char *string, char **bufpp, int mib[], int flags,
        int *typep)
    {
    	int indx;
    
    	if (*bufpp == NULL) {
    		listall(string, &batterylist);
    		return (-1);
    	}
    	if ((indx = findname(string, "third", bufpp, &batterylist)) == -1)
    		return (-1);
    	mib[2] = indx;
    	*typep = batterylist.list[indx].ctl_type;
    	return (3);
    }
    
    /*
     * Scan a list of names searching for a particular name.
     */
    int
    findname(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)
    {
    	(void)fprintf(stderr,
    	    "usage: sysctl [-Aanq] [-f file] [name[=value] ...]\n");
    	exit(1);
    }