Home | History | Annotate | Line # | Download | only in sysctl
sysctl.c revision 1.129
      1  1.129  christos /*	$NetBSD: sysctl.c,v 1.129 2009/04/01 15:55:27 christos Exp $ */
      2   1.75    atatat 
      3   1.75    atatat /*-
      4   1.75    atatat  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5   1.75    atatat  *	All rights reserved.
      6   1.75    atatat  *
      7   1.75    atatat  * This code is derived from software contributed to The NetBSD Foundation
      8   1.75    atatat  * by Andrew Brown.
      9   1.75    atatat  *
     10   1.75    atatat  * Redistribution and use in source and binary forms, with or without
     11   1.75    atatat  * modification, are permitted provided that the following conditions
     12   1.75    atatat  * are met:
     13   1.75    atatat  * 1. Redistributions of source code must retain the above copyright
     14   1.75    atatat  *    notice, this list of conditions and the following disclaimer.
     15   1.75    atatat  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.75    atatat  *    notice, this list of conditions and the following disclaimer in the
     17   1.75    atatat  *    documentation and/or other materials provided with the distribution.
     18   1.75    atatat  *
     19   1.75    atatat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.75    atatat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.75    atatat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.75    atatat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.75    atatat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.75    atatat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.75    atatat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.75    atatat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.75    atatat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.75    atatat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.75    atatat  * POSSIBILITY OF SUCH DAMAGE.
     30   1.75    atatat  */
     31    1.9   thorpej 
     32    1.1       cgd /*
     33    1.1       cgd  * Copyright (c) 1993
     34    1.1       cgd  *	The Regents of the University of California.  All rights reserved.
     35    1.1       cgd  *
     36    1.1       cgd  * Redistribution and use in source and binary forms, with or without
     37    1.1       cgd  * modification, are permitted provided that the following conditions
     38    1.1       cgd  * are met:
     39    1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     40    1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     41    1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     42    1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     43    1.1       cgd  *    documentation and/or other materials provided with the distribution.
     44   1.71       agc  * 3. Neither the name of the University nor the names of its contributors
     45    1.1       cgd  *    may be used to endorse or promote products derived from this software
     46    1.1       cgd  *    without specific prior written permission.
     47    1.1       cgd  *
     48    1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     49    1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     50    1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     51    1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     52    1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     53    1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     54    1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     55    1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     56    1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     57    1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     58    1.1       cgd  * SUCH DAMAGE.
     59    1.1       cgd  */
     60    1.1       cgd 
     61   1.14  christos #include <sys/cdefs.h>
     62    1.1       cgd #ifndef lint
     63  1.124     lukem __COPYRIGHT("@(#) Copyright (c) 1993\
     64  1.124     lukem  The Regents of the University of California.  All rights reserved.");
     65    1.1       cgd #endif /* not lint */
     66    1.1       cgd 
     67    1.1       cgd #ifndef lint
     68    1.9   thorpej #if 0
     69    1.9   thorpej static char sccsid[] = "@(#)sysctl.c	8.1 (Berkeley) 6/6/93";
     70    1.9   thorpej #else
     71  1.129  christos __RCSID("$NetBSD: sysctl.c,v 1.129 2009/04/01 15:55:27 christos Exp $");
     72    1.9   thorpej #endif
     73    1.1       cgd #endif /* not lint */
     74    1.1       cgd 
     75   1.75    atatat #include <sys/types.h>
     76    1.1       cgd #include <sys/param.h>
     77    1.1       cgd #include <sys/sysctl.h>
     78   1.17   thorpej #include <sys/mount.h>
     79   1.22    bouyer #include <sys/resource.h>
     80   1.75    atatat #include <sys/stat.h>
     81   1.75    atatat #include <sys/sched.h>
     82   1.75    atatat #include <sys/socket.h>
     83    1.1       cgd #include <netinet/in.h>
     84    1.1       cgd #include <netinet/ip_var.h>
     85    1.8   thorpej #include <netinet/tcp.h>
     86    1.8   thorpej #include <netinet/tcp_timer.h>
     87    1.8   thorpej #include <netinet/tcp_var.h>
     88   1.24    itojun #include <netinet/icmp6.h>
     89   1.75    atatat #include <nfs/rpcv2.h>
     90   1.75    atatat #include <nfs/nfsproto.h>
     91   1.75    atatat #include <nfs/nfs.h>
     92   1.75    atatat #include <machine/cpu.h>
     93   1.20    itojun #include <netkey/key_var.h>
     94   1.20    itojun 
     95   1.75    atatat #include <assert.h>
     96   1.75    atatat #include <ctype.h>
     97   1.14  christos #include <err.h>
     98    1.1       cgd #include <errno.h>
     99   1.75    atatat #include <inttypes.h>
    100   1.98    atatat #include <regex.h>
    101   1.75    atatat #include <stdarg.h>
    102    1.1       cgd #include <stdio.h>
    103    1.1       cgd #include <stdlib.h>
    104    1.1       cgd #include <string.h>
    105   1.75    atatat #include <time.h>
    106   1.15      tron #include <unistd.h>
    107    1.1       cgd 
    108   1.75    atatat /*
    109   1.75    atatat  * this needs to be able to do the printing and the setting
    110   1.75    atatat  */
    111   1.75    atatat #define HANDLER_PROTO const char *, const char *, char *, \
    112   1.75    atatat 	int *, u_int, const struct sysctlnode *, \
    113   1.75    atatat 	u_int, void *
    114   1.75    atatat #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
    115   1.75    atatat 	int *name, u_int namelen, const struct sysctlnode *pnode, \
    116   1.75    atatat 	u_int type, void *v
    117   1.75    atatat #define DISPLAY_VALUE	0
    118   1.75    atatat #define DISPLAY_OLD	1
    119   1.75    atatat #define DISPLAY_NEW	2
    120   1.75    atatat 
    121   1.75    atatat /*
    122   1.75    atatat  * generic routines
    123   1.75    atatat  */
    124   1.98    atatat static const struct handlespec *findhandler(const char *, int);
    125   1.98    atatat static void canonicalize(const char *, char *);
    126  1.100    atatat static void purge_tree(struct sysctlnode *);
    127   1.75    atatat static void print_tree(int *, u_int, struct sysctlnode *, u_int, int);
    128   1.75    atatat static void write_number(int *, u_int, struct sysctlnode *, char *);
    129   1.75    atatat static void write_string(int *, u_int, struct sysctlnode *, char *);
    130   1.75    atatat static void display_number(const struct sysctlnode *, const char *,
    131   1.75    atatat 			   const void *, size_t, int);
    132   1.75    atatat static void display_string(const struct sysctlnode *, const char *,
    133   1.75    atatat 			   const void *, size_t, int);
    134   1.75    atatat static void display_struct(const struct sysctlnode *, const char *,
    135   1.75    atatat 			   const void *, size_t, int);
    136   1.75    atatat static void hex_dump(const unsigned char *, size_t);
    137   1.75    atatat static void usage(void);
    138   1.75    atatat static void parse(char *);
    139   1.82    atatat static void parse_create(char *);
    140   1.82    atatat static void parse_destroy(char *);
    141   1.84    atatat static void parse_describe(char *);
    142   1.84    atatat static void getdesc1(int *, u_int, struct sysctlnode *);
    143   1.84    atatat static void getdesc(int *, u_int, struct sysctlnode *);
    144   1.92    atatat static void trim_whitespace(char *, int);
    145   1.75    atatat static void sysctlerror(int);
    146   1.92    atatat static void sysctlparseerror(u_int, const char *);
    147   1.92    atatat static void sysctlperror(const char *, ...);
    148   1.92    atatat #define EXIT(n) do { \
    149   1.92    atatat 	if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
    150   1.56  christos 
    151   1.75    atatat /*
    152   1.85    atatat  * "borrowed" from libc:sysctlgetmibinfo.c
    153   1.75    atatat  */
    154   1.85    atatat int __learn_tree(int *, u_int, struct sysctlnode *);
    155   1.22    bouyer 
    156   1.75    atatat /*
    157   1.75    atatat  * "handlers"
    158   1.75    atatat  */
    159   1.75    atatat static void printother(HANDLER_PROTO);
    160   1.75    atatat static void kern_clockrate(HANDLER_PROTO);
    161   1.75    atatat static void kern_boottime(HANDLER_PROTO);
    162   1.75    atatat static void kern_consdev(HANDLER_PROTO);
    163   1.75    atatat static void kern_cp_time(HANDLER_PROTO);
    164  1.103  christos static void kern_cp_id(HANDLER_PROTO);
    165  1.118  christos static void kern_drivers(HANDLER_PROTO);
    166   1.75    atatat static void vm_loadavg(HANDLER_PROTO);
    167   1.75    atatat static void proc_limit(HANDLER_PROTO);
    168   1.75    atatat #ifdef CPU_DISKINFO
    169   1.75    atatat static void machdep_diskinfo(HANDLER_PROTO);
    170   1.75    atatat #endif /* CPU_DISKINFO */
    171  1.108      elad static void mode_bits(HANDLER_PROTO);
    172    1.1       cgd 
    173   1.95  jdolecek static const struct handlespec {
    174   1.98    atatat 	const char *ps_re;
    175   1.75    atatat 	void (*ps_p)(HANDLER_PROTO);
    176   1.75    atatat 	void (*ps_w)(HANDLER_PROTO);
    177  1.104  christos 	const void *ps_d;
    178   1.75    atatat } handlers[] = {
    179  1.118  christos 	{ "/kern/clockrate",			kern_clockrate, NULL, NULL },
    180   1.98    atatat 	{ "/kern/vnode",			printother, NULL, "pstat" },
    181   1.98    atatat 	{ "/kern/proc(2|_args)?",		printother, NULL, "ps" },
    182   1.98    atatat 	{ "/kern/file2?",			printother, NULL, "pstat" },
    183   1.98    atatat 	{ "/kern/ntptime",			printother, NULL,
    184   1.98    atatat 						"ntpdc -c kerninfo" },
    185   1.98    atatat 	{ "/kern/msgbuf",			printother, NULL, "dmesg" },
    186  1.118  christos 	{ "/kern/boottime",			kern_boottime, NULL, NULL },
    187  1.118  christos 	{ "/kern/consdev",			kern_consdev, NULL, NULL },
    188  1.118  christos 	{ "/kern/cp_time(/[0-9]+)?",		kern_cp_time, NULL, NULL },
    189   1.98    atatat 	{ "/kern/sysvipc_info",			printother, NULL, "ipcs" },
    190  1.118  christos 	{ "/kern/cp_id(/[0-9]+)?",		kern_cp_id, NULL, NULL },
    191   1.98    atatat 
    192  1.118  christos 	{ "/kern/coredump/setid/mode",		mode_bits, mode_bits, NULL },
    193  1.118  christos 	{ "/kern/drivers",			kern_drivers, NULL, NULL },
    194  1.116      elad 
    195   1.98    atatat 	{ "/vm/vmmeter",			printother, NULL,
    196   1.98    atatat 						"vmstat' or 'systat" },
    197  1.118  christos 	{ "/vm/loadavg",			vm_loadavg, NULL, NULL },
    198   1.98    atatat 	{ "/vm/uvmexp2?",			printother, NULL,
    199   1.98    atatat 						"vmstat' or 'systat" },
    200   1.98    atatat 
    201   1.98    atatat 	{ "/vfs/nfs/nfsstats",			printother, NULL, "nfsstat" },
    202   1.98    atatat 
    203   1.98    atatat 	{ "/net/inet6?/tcp6?/ident",		printother, NULL, "identd" },
    204   1.98    atatat 	{ "/net/inet6/icmp6/nd6_[dp]rlist",	printother, NULL, "ndp" },
    205   1.98    atatat 	{ "/net/key/dumps[ap]",			printother, NULL, "setkey" },
    206   1.98    atatat 	{ "/net/[^/]+/[^/]+/pcblist",		printother, NULL,
    207   1.98    atatat 						"netstat' or 'sockstat" },
    208  1.106    rpaulo 	{ "/net/(inet|inet6)/[^/]+/stats",	printother, NULL, "netstat"},
    209  1.105    rpaulo 	{ "/net/bpf/(stats|peers)",		printother, NULL, "netstat"},
    210   1.98    atatat 
    211  1.107    rpaulo 	{ "/net/inet.*/tcp.*/deb.*",		printother, NULL, "trpt" },
    212  1.107    rpaulo 
    213  1.107    rpaulo 	{ "/net/ns/spp/deb.*",			printother, NULL, "trsp" },
    214  1.107    rpaulo 
    215   1.98    atatat 	{ "/hw/diskstats",			printother, NULL, "iostat" },
    216   1.98    atatat 
    217   1.75    atatat #ifdef CPU_CONSDEV
    218  1.118  christos 	{ "/machdep/consdev",			kern_consdev, NULL, NULL },
    219   1.75    atatat #endif /* CPU_CONSDEV */
    220   1.75    atatat #ifdef CPU_DISKINFO
    221  1.118  christos 	{ "/machdep/diskinfo",			machdep_diskinfo, NULL, NULL },
    222   1.75    atatat #endif /* CPU_CONSDEV */
    223   1.98    atatat 
    224  1.118  christos 	{ "/proc/[^/]+/rlimit/[^/]+/[^/]+",	proc_limit, proc_limit, NULL },
    225   1.98    atatat 
    226   1.98    atatat 	/*
    227   1.98    atatat 	 * these will only be called when the given node has no children
    228   1.98    atatat 	 */
    229   1.98    atatat 	{ "/net/[^/]+",				printother, NULL, NULL },
    230   1.98    atatat 	{ "/debug",				printother, NULL, NULL },
    231   1.98    atatat 	{ "/ddb",				printother, NULL, NULL },
    232   1.98    atatat 	{ "/vendor",				printother, NULL, NULL },
    233   1.98    atatat 
    234  1.118  christos 	{ NULL,					NULL, NULL, NULL },
    235    1.1       cgd };
    236   1.56  christos 
    237   1.75    atatat struct sysctlnode my_root = {
    238   1.83    atatat 	.sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
    239   1.86        he 	sysc_init_field(_sysctl_size, sizeof(struct sysctlnode)),
    240   1.75    atatat 	.sysctl_num = 0,
    241   1.75    atatat 	.sysctl_name = "(prog_root)",
    242    1.1       cgd };
    243    1.1       cgd 
    244   1.84    atatat int	Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag;
    245   1.92    atatat size_t	nr;
    246   1.92    atatat char	*fn;
    247  1.121  christos int	req, stale, errs;
    248   1.65     lukem FILE	*warnfp = stderr;
    249    1.1       cgd 
    250    1.1       cgd /*
    251   1.75    atatat  * vah-riables n stuff
    252    1.1       cgd  */
    253   1.75    atatat char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
    254   1.98    atatat 	canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
    255   1.75    atatat 	gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
    256  1.104  christos char sep[] = ".";
    257  1.104  christos const char *eq = " = ";
    258   1.75    atatat const char *lname[] = {
    259   1.75    atatat 	"top", "second", "third", "fourth", "fifth", "sixth",
    260   1.75    atatat 	"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
    261   1.75    atatat };
    262    1.1       cgd 
    263   1.22    bouyer /*
    264   1.75    atatat  * you've heard of main, haven't you?
    265   1.22    bouyer  */
    266    1.1       cgd int
    267   1.53    simonb main(int argc, char *argv[])
    268    1.1       cgd {
    269   1.75    atatat 	int name[CTL_MAXNAME];
    270   1.75    atatat 	int ch;
    271    1.1       cgd 
    272   1.84    atatat 	while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) {
    273    1.1       cgd 		switch (ch) {
    274    1.1       cgd 		case 'A':
    275   1.75    atatat 			Aflag++;
    276    1.1       cgd 			break;
    277    1.1       cgd 		case 'a':
    278   1.75    atatat 			aflag++;
    279    1.1       cgd 			break;
    280   1.84    atatat 		case 'd':
    281   1.84    atatat 			dflag++;
    282   1.84    atatat 			break;
    283   1.72     grant 		case 'e':
    284   1.75    atatat 			eq = "=";
    285   1.72     grant 			break;
    286   1.27    tsarna 		case 'f':
    287   1.27    tsarna 			fn = optarg;
    288   1.75    atatat 			wflag++;
    289   1.75    atatat 			break;
    290   1.75    atatat 		case 'M':
    291   1.75    atatat 			Mflag++;
    292   1.27    tsarna 			break;
    293    1.1       cgd 		case 'n':
    294   1.75    atatat 			nflag++;
    295    1.1       cgd 			break;
    296   1.58  sommerfe 		case 'q':
    297   1.75    atatat 			qflag++;
    298   1.75    atatat 			break;
    299   1.82    atatat 		case 'b':	/* FreeBSD compat */
    300   1.75    atatat 		case 'r':
    301   1.75    atatat 			rflag++;
    302   1.58  sommerfe 			break;
    303    1.1       cgd 		case 'w':
    304   1.75    atatat 			wflag++;
    305   1.75    atatat 			break;
    306   1.75    atatat 		case 'x':
    307   1.75    atatat 			xflag++;
    308    1.1       cgd 			break;
    309    1.1       cgd 		default:
    310    1.1       cgd 			usage();
    311    1.1       cgd 		}
    312    1.1       cgd 	}
    313   1.58  sommerfe 
    314   1.75    atatat 	argc -= optind;
    315   1.75    atatat 	argv += optind;
    316   1.75    atatat 
    317   1.58  sommerfe 	if (qflag && !wflag)
    318   1.58  sommerfe 		usage();
    319   1.75    atatat 	if (xflag && rflag)
    320   1.75    atatat 		usage();
    321   1.75    atatat 	/* if ((xflag || rflag) && wflag)
    322   1.75    atatat 		usage(); */
    323   1.75    atatat 	/* if (aflag && Mflag)
    324   1.75    atatat 		usage(); */
    325   1.84    atatat 	if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL)
    326   1.75    atatat 		aflag = 1;
    327   1.58  sommerfe 
    328   1.75    atatat 	if (Aflag)
    329   1.75    atatat 		warnfp = stdout;
    330  1.100    atatat 	stale = req = 0;
    331    1.1       cgd 
    332   1.75    atatat 	if (aflag) {
    333   1.75    atatat 		print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1);
    334   1.75    atatat 		/* if (argc == 0) */
    335   1.75    atatat 		return (0);
    336    1.1       cgd 	}
    337   1.27    tsarna 
    338   1.27    tsarna 	if (fn) {
    339   1.27    tsarna 		FILE *fp;
    340   1.27    tsarna 		char *l;
    341   1.58  sommerfe 
    342   1.27    tsarna 		fp = fopen(fn, "r");
    343   1.27    tsarna 		if (fp == NULL) {
    344   1.27    tsarna 			err(1, "%s", fn);
    345   1.27    tsarna 		} else {
    346   1.92    atatat 			nr = 0;
    347   1.92    atatat 			while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL)
    348   1.75    atatat 			{
    349   1.75    atatat 				if (*l) {
    350   1.75    atatat 					parse(l);
    351   1.75    atatat 					free(l);
    352   1.75    atatat 				}
    353   1.27    tsarna 			}
    354   1.27    tsarna 			fclose(fp);
    355   1.27    tsarna 		}
    356  1.121  christos 		return errs ? 1 : 0;
    357   1.27    tsarna 	}
    358   1.75    atatat 
    359   1.75    atatat 	if (argc == 0)
    360   1.75    atatat 		usage();
    361   1.75    atatat 
    362   1.75    atatat 	while (argc-- > 0)
    363   1.75    atatat 		parse(*argv++);
    364   1.75    atatat 
    365  1.121  christos 	return errs ? 1 : 0;
    366    1.1       cgd }
    367    1.1       cgd 
    368    1.1       cgd /*
    369   1.75    atatat  * ********************************************************************
    370   1.75    atatat  * how to find someone special to handle the reading (or maybe even
    371   1.75    atatat  * writing) of a particular node
    372   1.75    atatat  * ********************************************************************
    373    1.1       cgd  */
    374   1.95  jdolecek static const struct handlespec *
    375   1.98    atatat findhandler(const char *s, int w)
    376   1.75    atatat {
    377   1.95  jdolecek 	const struct handlespec *p;
    378   1.98    atatat 	regex_t re;
    379   1.98    atatat 	int i, j, l;
    380   1.98    atatat 	char eb[64];
    381   1.98    atatat 	regmatch_t match[1];
    382   1.75    atatat 
    383   1.75    atatat 	p = &handlers[0];
    384   1.98    atatat 	l = strlen(s);
    385   1.98    atatat 	for (i = 0; p[i].ps_re != NULL; i++) {
    386   1.98    atatat 		j = regcomp(&re, p[i].ps_re, REG_EXTENDED);
    387   1.98    atatat 		if (j != 0) {
    388   1.98    atatat 			regerror(j, &re, eb, sizeof(eb));
    389   1.98    atatat 			errx(1, "regcomp: %s: %s", p[i].ps_re, eb);
    390   1.98    atatat 		}
    391   1.98    atatat 		j = regexec(&re, s, 1, match, 0);
    392   1.98    atatat 		if (j == 0) {
    393   1.98    atatat 			if (match[0].rm_so == 0 && match[0].rm_eo == l &&
    394  1.120  christos 			    (w ? p[i].ps_w : p[i].ps_p) != NULL) {
    395  1.120  christos 				regfree(&re);
    396   1.98    atatat 				return (&p[i]);
    397  1.120  christos 			}
    398   1.98    atatat 		}
    399   1.98    atatat 		else if (j != REG_NOMATCH) {
    400   1.98    atatat 			regerror(j, &re, eb, sizeof(eb));
    401   1.98    atatat 			errx(1, "regexec: %s: %s", p[i].ps_re, eb);
    402   1.98    atatat 		}
    403  1.120  christos 		regfree(&re);
    404   1.75    atatat 	}
    405   1.75    atatat 
    406   1.75    atatat 	return (NULL);
    407   1.75    atatat }
    408   1.75    atatat 
    409   1.98    atatat /*
    410   1.98    atatat  * after sysctlgetmibinfo is done with the name, we convert all
    411   1.98    atatat  * separators to / and stuff one at the front if it was missing
    412   1.98    atatat  */
    413   1.98    atatat static void
    414   1.98    atatat canonicalize(const char *i, char *o)
    415    1.1       cgd {
    416   1.98    atatat 	const char *t;
    417   1.98    atatat 	char p[SYSCTL_NAMELEN + 1];
    418   1.98    atatat 	int l;
    419   1.98    atatat 
    420   1.98    atatat 	if (i[0] != *sep) {
    421   1.98    atatat 		o[0] = '/';
    422   1.98    atatat 		o[1] = '\0';
    423    1.1       cgd 	}
    424   1.98    atatat 	else
    425   1.98    atatat 		o[0] = '\0';
    426   1.75    atatat 
    427   1.98    atatat 	t = i;
    428   1.98    atatat 	do {
    429   1.98    atatat 		i = t;
    430   1.98    atatat 		t = strchr(i, sep[0]);
    431   1.98    atatat 		if (t == NULL)
    432   1.98    atatat 			strcat(o, i);
    433   1.98    atatat 		else {
    434   1.98    atatat 			l = t - i;
    435   1.98    atatat 			t++;
    436   1.98    atatat 			memcpy(p, i, l);
    437   1.98    atatat 			p[l] = '\0';
    438   1.98    atatat 			strcat(o, p);
    439   1.98    atatat 			strcat(o, "/");
    440   1.98    atatat 		}
    441   1.98    atatat 	} while (t != NULL);
    442    1.1       cgd }
    443    1.1       cgd 
    444    1.1       cgd /*
    445   1.75    atatat  * ********************************************************************
    446   1.75    atatat  * convert this special number to a special string so we can print the
    447   1.75    atatat  * mib
    448   1.75    atatat  * ********************************************************************
    449    1.1       cgd  */
    450   1.75    atatat static const char *
    451   1.75    atatat sf(u_int f)
    452    1.1       cgd {
    453   1.75    atatat 	static char s[256];
    454  1.104  christos 	const char *c;
    455   1.75    atatat 
    456   1.75    atatat 	s[0] = '\0';
    457   1.75    atatat 	c = "";
    458   1.75    atatat 
    459   1.75    atatat #define print_flag(_f, _s, _c, _q, _x) \
    460   1.83    atatat 	if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
    461   1.75    atatat 		strlcat((_s), (_c), sizeof(_s)); \
    462   1.75    atatat 		strlcat((_s), __STRING(_q), sizeof(_s)); \
    463   1.75    atatat 		(_c) = ","; \
    464   1.83    atatat 		(_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
    465   1.75    atatat 	}
    466   1.83    atatat 	print_flag(f, s, c, READONLY,  READWRITE);
    467   1.83    atatat 	print_flag(f, s, c, READWRITE, READWRITE);
    468   1.83    atatat 	print_flag(f, s, c, ANYWRITE,  ANYWRITE);
    469   1.83    atatat 	print_flag(f, s, c, PRIVATE,   PRIVATE);
    470   1.83    atatat 	print_flag(f, s, c, PERMANENT, PERMANENT);
    471   1.83    atatat 	print_flag(f, s, c, OWNDATA,   OWNDATA);
    472   1.83    atatat 	print_flag(f, s, c, IMMEDIATE, IMMEDIATE);
    473   1.83    atatat 	print_flag(f, s, c, HEX,       HEX);
    474   1.83    atatat 	print_flag(f, s, c, ROOT,      ROOT);
    475   1.83    atatat 	print_flag(f, s, c, ANYNUMBER, ANYNUMBER);
    476   1.83    atatat 	print_flag(f, s, c, HIDDEN,    HIDDEN);
    477   1.83    atatat 	print_flag(f, s, c, ALIAS,     ALIAS);
    478   1.75    atatat #undef print_flag
    479   1.75    atatat 
    480   1.75    atatat 	if (f) {
    481   1.75    atatat 		char foo[9];
    482   1.75    atatat 		snprintf(foo, sizeof(foo), "%x", f);
    483   1.75    atatat 		strlcat(s, c, sizeof(s));
    484   1.75    atatat 		strlcat(s, foo, sizeof(s));
    485   1.75    atatat 	}
    486    1.1       cgd 
    487   1.75    atatat 	return (s);
    488   1.75    atatat }
    489   1.72     grant 
    490   1.75    atatat static const char *
    491   1.75    atatat st(u_int t)
    492   1.75    atatat {
    493    1.1       cgd 
    494   1.75    atatat 	switch (t) {
    495   1.75    atatat 	case CTLTYPE_NODE:
    496   1.75    atatat 		return "NODE";
    497   1.75    atatat 	case CTLTYPE_INT:
    498   1.75    atatat 		return "INT";
    499   1.75    atatat 	case CTLTYPE_STRING:
    500   1.75    atatat 		return "STRING";
    501   1.75    atatat 	case CTLTYPE_QUAD:
    502   1.75    atatat                 return "QUAD";
    503   1.75    atatat 	case CTLTYPE_STRUCT:
    504   1.75    atatat 		return "STRUCT";
    505   1.75    atatat 	}
    506    1.1       cgd 
    507   1.75    atatat 	return "???";
    508   1.75    atatat }
    509   1.46       chs 
    510   1.75    atatat /*
    511   1.75    atatat  * ********************************************************************
    512  1.100    atatat  * recursively eliminate all data belonging to the given node
    513  1.100    atatat  * ********************************************************************
    514  1.100    atatat  */
    515  1.100    atatat static void
    516  1.100    atatat purge_tree(struct sysctlnode *rnode)
    517  1.100    atatat {
    518  1.100    atatat 	struct sysctlnode *node;
    519  1.100    atatat 
    520  1.100    atatat 	if (rnode == NULL ||
    521  1.100    atatat 	    SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE ||
    522  1.100    atatat 	    rnode->sysctl_child == NULL)
    523  1.100    atatat 		return;
    524  1.100    atatat 
    525  1.100    atatat 	for (node = rnode->sysctl_child;
    526  1.100    atatat 	     node < &rnode->sysctl_child[rnode->sysctl_clen];
    527  1.100    atatat 	     node++)
    528  1.100    atatat 		purge_tree(node);
    529  1.100    atatat 	free(rnode->sysctl_child);
    530  1.100    atatat 	rnode->sysctl_csize = 0;
    531  1.100    atatat 	rnode->sysctl_clen = 0;
    532  1.100    atatat 	rnode->sysctl_child = NULL;
    533  1.100    atatat 
    534  1.100    atatat 	if (rnode->sysctl_desc == (const char*)-1)
    535  1.100    atatat 		rnode->sysctl_desc = NULL;
    536  1.100    atatat 	if (rnode->sysctl_desc != NULL)
    537  1.104  christos 		free(__UNCONST(rnode->sysctl_desc));
    538  1.100    atatat 	rnode->sysctl_desc = NULL;
    539  1.100    atatat }
    540  1.100    atatat 
    541  1.100    atatat /*
    542  1.100    atatat  * ********************************************************************
    543   1.75    atatat  * print this node and any others underneath it
    544   1.75    atatat  * ********************************************************************
    545   1.75    atatat  */
    546   1.75    atatat static void
    547   1.75    atatat print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
    548   1.75    atatat 	   int add)
    549   1.75    atatat {
    550   1.75    atatat 	struct sysctlnode *node;
    551  1.128     lukem 	int rc;
    552  1.128     lukem 	size_t ni, sz;
    553   1.75    atatat 	char *sp, *dp, n[20];
    554   1.95  jdolecek 	const struct handlespec *p;
    555   1.75    atatat 
    556   1.75    atatat 	sp = &gsname[strlen(gsname)];
    557   1.75    atatat 	dp = &gdname[strlen(gdname)];
    558   1.75    atatat 
    559   1.75    atatat 	if (sp != &gsname[0] && dp == &gdname[0]) {
    560   1.75    atatat 		/*
    561   1.75    atatat 		 * aw...shucks.  now we must play catch up
    562   1.75    atatat 		 */
    563   1.75    atatat 		for (ni = 0; ni < namelen; ni++) {
    564   1.75    atatat 			(void)snprintf(n, sizeof(n), "%d", name[ni]);
    565   1.75    atatat 			if (ni > 0)
    566   1.75    atatat 				strncat(gdname, ".", sizeof(gdname));
    567   1.75    atatat 			strncat(gdname, n, sizeof(gdname));
    568    1.1       cgd 		}
    569   1.75    atatat 	}
    570    1.1       cgd 
    571   1.75    atatat 	if (pnode == NULL)
    572   1.75    atatat 		pnode = &my_root;
    573   1.75    atatat 	else if (add) {
    574   1.75    atatat 		snprintf(n, sizeof(n), "%d", pnode->sysctl_num);
    575   1.75    atatat 		if (namelen > 1) {
    576   1.75    atatat 			strncat(gsname, sep, sizeof(gsname));
    577   1.75    atatat 			strncat(gdname, ".", sizeof(gdname));
    578   1.75    atatat 		}
    579   1.75    atatat 		strncat(gsname, pnode->sysctl_name, sizeof(gsname));
    580   1.75    atatat 		strncat(gdname, n, sizeof(gdname));
    581   1.75    atatat 	}
    582   1.75    atatat 
    583   1.75    atatat 	if (Mflag && pnode != &my_root) {
    584   1.75    atatat 		if (nflag)
    585   1.75    atatat 			printf("%s: ", gdname);
    586   1.75    atatat 		else
    587   1.75    atatat 			printf("%s (%s): ", gsname, gdname);
    588   1.75    atatat 		printf("CTLTYPE_%s", st(type));
    589   1.75    atatat 		if (type == CTLTYPE_NODE) {
    590   1.83    atatat 			if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS)
    591   1.75    atatat 				printf(", alias %d",
    592   1.75    atatat 				       pnode->sysctl_alias);
    593   1.75    atatat 			else
    594   1.75    atatat 				printf(", children %d/%d",
    595   1.75    atatat 				       pnode->sysctl_clen,
    596   1.75    atatat 				       pnode->sysctl_csize);
    597   1.75    atatat 		}
    598   1.75    atatat 		printf(", size %zu", pnode->sysctl_size);
    599   1.75    atatat 		printf(", flags 0x%x<%s>",
    600   1.75    atatat 		       SYSCTL_FLAGS(pnode->sysctl_flags),
    601   1.75    atatat 		       sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
    602   1.75    atatat 		if (pnode->sysctl_func)
    603   1.75    atatat 			printf(", func=%p", pnode->sysctl_func);
    604   1.75    atatat 		printf(", ver=%d", pnode->sysctl_ver);
    605   1.75    atatat 		printf("\n");
    606   1.75    atatat 		if (type != CTLTYPE_NODE) {
    607   1.75    atatat 			*sp = *dp = '\0';
    608    1.1       cgd 			return;
    609    1.1       cgd 		}
    610   1.75    atatat 	}
    611   1.75    atatat 
    612   1.84    atatat 	if (dflag && pnode != &my_root) {
    613   1.84    atatat 		if (Aflag || type != CTLTYPE_NODE) {
    614   1.84    atatat 			if (pnode->sysctl_desc == NULL)
    615   1.84    atatat 				getdesc1(name, namelen, pnode);
    616   1.91    atatat 			if (Aflag || !add ||
    617   1.84    atatat 			    (pnode->sysctl_desc != NULL &&
    618   1.84    atatat 			     pnode->sysctl_desc != (const char*)-1)) {
    619   1.84    atatat 				if (!nflag)
    620   1.84    atatat 					printf("%s: ", gsname);
    621   1.84    atatat 				if (pnode->sysctl_desc == NULL ||
    622   1.84    atatat 				    pnode->sysctl_desc == (const char*)-1)
    623   1.84    atatat 					printf("(no description)\n");
    624   1.84    atatat 				else
    625   1.84    atatat 					printf("%s\n", pnode->sysctl_desc);
    626   1.84    atatat 			}
    627   1.84    atatat 		}
    628   1.84    atatat 
    629   1.84    atatat 		if (type != CTLTYPE_NODE) {
    630   1.84    atatat 			*sp = *dp = '\0';
    631   1.84    atatat 			return;
    632   1.84    atatat 		}
    633   1.84    atatat 	}
    634   1.84    atatat 
    635   1.75    atatat 	/*
    636   1.75    atatat 	 * if this is an alias and we added our name, that means we
    637   1.75    atatat 	 * got here by recursing down into the tree, so skip it.  The
    638   1.75    atatat 	 * only way to print an aliased node is with either -M or by
    639   1.75    atatat 	 * name specifically.
    640   1.75    atatat 	 */
    641   1.83    atatat 	if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) {
    642   1.75    atatat 		*sp = *dp = '\0';
    643    1.1       cgd 		return;
    644   1.75    atatat 	}
    645    1.1       cgd 
    646   1.98    atatat 	canonicalize(gsname, canonname);
    647   1.98    atatat 	p = findhandler(canonname, 0);
    648   1.75    atatat 	if (type != CTLTYPE_NODE && p != NULL) {
    649   1.75    atatat 		(*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
    650  1.104  christos 			   __UNCONST(p->ps_d));
    651   1.75    atatat 		*sp = *dp = '\0';
    652   1.75    atatat 		return;
    653   1.75    atatat 	}
    654    1.1       cgd 
    655   1.75    atatat 	if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
    656   1.75    atatat 		rc = sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
    657   1.75    atatat 		if (rc == -1) {
    658   1.75    atatat 			sysctlerror(1);
    659   1.75    atatat 			*sp = *dp = '\0';
    660   1.18   thorpej 			return;
    661   1.75    atatat 		}
    662   1.75    atatat 		if (sz == 0) {
    663   1.75    atatat 			if ((Aflag || req) && !Mflag)
    664   1.75    atatat 				printf("%s: node contains no data\n", gsname);
    665   1.75    atatat 			*sp = *dp = '\0';
    666   1.18   thorpej 			return;
    667   1.18   thorpej 		}
    668   1.75    atatat 	}
    669   1.75    atatat 	else
    670   1.75    atatat 		sz = pnode->sysctl_size;
    671   1.17   thorpej 
    672   1.75    atatat 	switch (type) {
    673   1.75    atatat 	case CTLTYPE_NODE: {
    674   1.85    atatat 		__learn_tree(name, namelen, pnode);
    675   1.75    atatat 		node = pnode->sysctl_child;
    676   1.75    atatat 		if (node == NULL) {
    677   1.88    atatat 			if (dflag)
    678   1.88    atatat 				/* do nothing */;
    679   1.88    atatat 			else if (p != NULL)
    680   1.75    atatat 				(*p->ps_p)(gsname, gdname, NULL, name, namelen,
    681  1.104  christos 					   pnode, type, __UNCONST(p->ps_d));
    682   1.88    atatat 			else if ((Aflag || req) && !Mflag)
    683   1.75    atatat 				printf("%s: no children\n", gsname);
    684   1.75    atatat 		}
    685   1.75    atatat 		else {
    686   1.84    atatat 			if (dflag)
    687   1.84    atatat 				/*
    688   1.84    atatat 				 * get all descriptions for next level
    689   1.84    atatat 				 * in one chunk
    690   1.84    atatat 				 */
    691   1.84    atatat 				getdesc(name, namelen, pnode);
    692   1.75    atatat 			req = 0;
    693   1.75    atatat 			for (ni = 0; ni < pnode->sysctl_clen; ni++) {
    694   1.75    atatat 				name[namelen] = node[ni].sysctl_num;
    695   1.83    atatat 				if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) &&
    696   1.75    atatat 				    !(Aflag || req))
    697   1.75    atatat 					continue;
    698   1.75    atatat 				print_tree(name, namelen + 1, &node[ni],
    699   1.75    atatat 					   SYSCTL_TYPE(node[ni].sysctl_flags),
    700   1.75    atatat 					   1);
    701   1.75    atatat 			}
    702   1.75    atatat 		}
    703    1.1       cgd 		break;
    704   1.75    atatat 	}
    705   1.75    atatat 	case CTLTYPE_INT: {
    706   1.75    atatat 		int i;
    707   1.75    atatat 		rc = sysctl(name, namelen, &i, &sz, NULL, 0);
    708   1.75    atatat 		if (rc == -1) {
    709   1.75    atatat 			sysctlerror(1);
    710   1.75    atatat 			break;
    711   1.75    atatat 		}
    712   1.75    atatat 		display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
    713   1.22    bouyer 		break;
    714   1.75    atatat 	}
    715   1.75    atatat 	case CTLTYPE_STRING: {
    716   1.75    atatat 		unsigned char buf[1024], *tbuf;
    717   1.75    atatat 		tbuf = buf;
    718   1.75    atatat 		sz = sizeof(buf);
    719   1.75    atatat 		rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
    720   1.75    atatat 		if (rc == -1 && errno == ENOMEM) {
    721   1.75    atatat 			tbuf = malloc(sz);
    722   1.75    atatat 			if (tbuf == NULL) {
    723   1.75    atatat 				sysctlerror(1);
    724   1.75    atatat 				break;
    725   1.75    atatat 			}
    726   1.75    atatat 			rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
    727   1.56  christos 		}
    728   1.75    atatat 		if (rc == -1)
    729   1.75    atatat 			sysctlerror(1);
    730   1.75    atatat 		else
    731   1.96    atatat 			display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE);
    732   1.75    atatat 		if (tbuf != buf)
    733   1.75    atatat 			free(tbuf);
    734   1.56  christos 		break;
    735    1.1       cgd 	}
    736   1.75    atatat 	case CTLTYPE_QUAD: {
    737   1.75    atatat 		u_quad_t q;
    738   1.75    atatat 		sz = sizeof(q);
    739   1.75    atatat 		rc = sysctl(&name[0], namelen, &q, &sz, NULL, 0);
    740   1.75    atatat 		if (rc == -1) {
    741   1.75    atatat 			sysctlerror(1);
    742   1.75    atatat 			break;
    743   1.75    atatat 		}
    744   1.75    atatat 		display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
    745   1.75    atatat 		break;
    746    1.1       cgd 	}
    747   1.75    atatat 	case CTLTYPE_STRUCT: {
    748   1.75    atatat 		/*
    749   1.75    atatat 		 * we shouldn't actually get here, but if we
    750   1.75    atatat 		 * do, would it be nice to have *something* to
    751   1.75    atatat 		 * do other than completely ignore the
    752   1.75    atatat 		 * request.
    753   1.75    atatat 		 */
    754   1.75    atatat 		unsigned char *d;
    755   1.75    atatat 		if ((d = malloc(sz)) == NULL) {
    756   1.75    atatat 			fprintf(warnfp, "%s: !malloc failed!\n", gsname);
    757    1.1       cgd 			break;
    758   1.75    atatat 		}
    759   1.75    atatat 		rc = sysctl(&name[0], namelen, d, &sz, NULL, 0);
    760   1.75    atatat 		if (rc == -1) {
    761   1.75    atatat 			sysctlerror(1);
    762    1.1       cgd 			break;
    763    1.1       cgd 		}
    764   1.75    atatat 		display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
    765   1.75    atatat 		free(d);
    766   1.75    atatat 		break;
    767    1.1       cgd 	}
    768   1.75    atatat 	default:
    769   1.75    atatat 		/* should i print an error here? */
    770   1.75    atatat 		break;
    771   1.75    atatat 	}
    772   1.75    atatat 
    773   1.75    atatat 	*sp = *dp = '\0';
    774   1.75    atatat }
    775   1.75    atatat 
    776   1.75    atatat /*
    777   1.75    atatat  * ********************************************************************
    778   1.75    atatat  * parse a request, possibly determining that it's a create or destroy
    779   1.75    atatat  * request
    780   1.75    atatat  * ********************************************************************
    781   1.75    atatat  */
    782   1.75    atatat static void
    783   1.75    atatat parse(char *l)
    784   1.75    atatat {
    785   1.75    atatat 	struct sysctlnode *node;
    786   1.95  jdolecek 	const struct handlespec *w;
    787   1.84    atatat 	int name[CTL_MAXNAME], dodesc = 0;
    788   1.75    atatat 	u_int namelen, type;
    789   1.75    atatat 	char *key, *value, *dot;
    790   1.75    atatat 	size_t sz;
    791  1.129  christos 	bool optional = false;
    792   1.75    atatat 
    793   1.75    atatat 	req = 1;
    794   1.75    atatat 	key = l;
    795  1.129  christos 
    796  1.129  christos 	if ((value = strchr(l, '=')) != NULL) {
    797  1.129  christos 		if (value > l && value[-1] == '?') {
    798  1.129  christos 			value[-1] = '\0';
    799  1.129  christos 			optional = true;
    800  1.129  christos 		}
    801   1.75    atatat 		*value++ = '\0';
    802  1.129  christos 	}
    803    1.1       cgd 
    804   1.75    atatat 	if ((dot = strpbrk(key, "./")) == NULL)
    805   1.75    atatat 		sep[0] = '.';
    806   1.75    atatat 	else
    807   1.75    atatat 		sep[0] = dot[0];
    808   1.75    atatat 	sep[1] = '\0';
    809    1.1       cgd 
    810   1.82    atatat 	while (key[0] == sep[0] && key[1] == sep[0]) {
    811   1.75    atatat 		if (value != NULL)
    812   1.75    atatat 			value[-1] = '=';
    813   1.82    atatat 		if (strncmp(key + 2, "create", 6) == 0 &&
    814   1.82    atatat 		    (key[8] == '=' || key[8] == sep[0]))
    815   1.92    atatat 			parse_create(key + 8 + (key[8] == '=' ? 1 : 0));
    816   1.82    atatat 		else if (strncmp(key + 2, "destroy", 7) == 0 &&
    817   1.82    atatat 			 (key[9] == '=' || key[9] == sep[0]))
    818   1.92    atatat 			parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0));
    819   1.84    atatat 		else if (strncmp(key + 2, "describe", 8) == 0 &&
    820   1.84    atatat 			 (key[10] == '=' || key[10] == sep[0])) {
    821   1.84    atatat 			key += 10 + (key[10] == '=');
    822   1.84    atatat 			if ((value = strchr(key, '=')) != NULL)
    823   1.84    atatat 				parse_describe(key);
    824   1.84    atatat 			else {
    825   1.84    atatat 				if (!dflag)
    826   1.84    atatat 					dodesc = 1;
    827   1.84    atatat 				break;
    828   1.84    atatat 			}
    829   1.84    atatat 		}
    830    1.1       cgd 		else
    831   1.92    atatat 			sysctlperror("unable to parse '%s'\n", key);
    832   1.32    simonb 		return;
    833   1.32    simonb 	}
    834   1.32    simonb 
    835  1.100    atatat 	if (stale) {
    836  1.100    atatat 		purge_tree(&my_root);
    837  1.100    atatat 		stale = 0;
    838  1.100    atatat 	}
    839   1.75    atatat 	node = &my_root;
    840   1.75    atatat 	namelen = CTL_MAXNAME;
    841   1.75    atatat 	sz = sizeof(gsname);
    842   1.75    atatat 
    843   1.83    atatat 	if (sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node,
    844   1.83    atatat 			     SYSCTL_VERSION) == -1) {
    845  1.129  christos 		if (optional)
    846  1.129  christos 			return;
    847   1.92    atatat 		sysctlparseerror(namelen, l);
    848   1.92    atatat 		EXIT(1);
    849   1.75    atatat 	}
    850   1.75    atatat 
    851   1.75    atatat 	type = SYSCTL_TYPE(node->sysctl_flags);
    852   1.75    atatat 
    853   1.75    atatat 	if (value == NULL) {
    854   1.84    atatat 		if (dodesc)
    855   1.84    atatat 			dflag = 1;
    856   1.75    atatat 		print_tree(&name[0], namelen, node, type, 0);
    857   1.84    atatat 		if (dodesc)
    858   1.84    atatat 			dflag = 0;
    859   1.75    atatat 		gsname[0] = '\0';
    860   1.69       dsl 		return;
    861   1.69       dsl 	}
    862   1.69       dsl 
    863   1.92    atatat 	if (fn)
    864   1.92    atatat 		trim_whitespace(value, 1);
    865   1.92    atatat 
    866   1.82    atatat 	if (!wflag) {
    867   1.92    atatat 		sysctlperror("Must specify -w to set variables\n");
    868   1.82    atatat 		exit(1);
    869   1.82    atatat 	}
    870   1.82    atatat 
    871   1.98    atatat 	canonicalize(gsname, canonname);
    872   1.98    atatat 	if (type != CTLTYPE_NODE && (w = findhandler(canonname, 1)) != NULL) {
    873   1.75    atatat 		(*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
    874  1.104  christos 			   __UNCONST(w->ps_d));
    875   1.75    atatat 		gsname[0] = '\0';
    876   1.26      fvdl 		return;
    877   1.26      fvdl 	}
    878   1.58  sommerfe 
    879    1.1       cgd 	switch (type) {
    880   1.75    atatat 	case CTLTYPE_NODE:
    881   1.75    atatat 		/*
    882   1.75    atatat 		 * XXX old behavior is to print.  should we error instead?
    883   1.75    atatat 		 */
    884   1.75    atatat 		print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1);
    885   1.75    atatat 		break;
    886    1.1       cgd 	case CTLTYPE_INT:
    887   1.75    atatat 		write_number(&name[0], namelen, node, value);
    888   1.75    atatat 		break;
    889    1.1       cgd 	case CTLTYPE_STRING:
    890   1.75    atatat 		write_string(&name[0], namelen, node, value);
    891   1.75    atatat 		break;
    892   1.75    atatat 	case CTLTYPE_QUAD:
    893   1.75    atatat 		write_number(&name[0], namelen, node, value);
    894   1.75    atatat 		break;
    895   1.75    atatat 	case CTLTYPE_STRUCT:
    896   1.75    atatat 		/*
    897   1.75    atatat 		 * XXX old behavior is to print.  should we error instead?
    898   1.75    atatat 		 */
    899   1.75    atatat 		/* fprintf(warnfp, "you can't write to %s\n", gsname); */
    900   1.75    atatat 		print_tree(&name[0], namelen, node, type, 0);
    901   1.75    atatat 		break;
    902   1.75    atatat 	}
    903   1.75    atatat }
    904   1.75    atatat 
    905   1.75    atatat /*
    906   1.75    atatat 
    907   1.75    atatat   //create=foo.bar.whatever...,
    908   1.75    atatat   [type=(int|quad|string|struct|node),]
    909   1.75    atatat   [size=###,]
    910   1.75    atatat   [n=###,]
    911   1.82    atatat   [flags=(iohxparw12),]
    912   1.75    atatat   [addr=0x####,|symbol=...|value=...]
    913   1.75    atatat 
    914   1.75    atatat   size is optional for some types.  type must be set before anything
    915   1.75    atatat   else.  nodes can have [r12whp], but nothing else applies.  if no
    916   1.75    atatat   size or type is given, node is asserted.  writeable is the default,
    917   1.75    atatat   with [r12w] being read-only, writeable below securelevel 1,
    918   1.75    atatat   writeable below securelevel 2, and unconditionally writeable
    919   1.75    atatat   respectively.  if you specify addr, it is assumed to be the name of
    920   1.83    atatat   a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
    921   1.83    atatat   strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts.  you cannot
    922   1.75    atatat   specify both value and addr.
    923   1.75    atatat 
    924   1.75    atatat */
    925   1.75    atatat 
    926   1.75    atatat static void
    927   1.82    atatat parse_create(char *l)
    928   1.75    atatat {
    929   1.75    atatat 	struct sysctlnode node;
    930   1.75    atatat 	size_t sz;
    931   1.75    atatat 	char *nname, *key, *value, *data, *addr, *c, *t;
    932   1.75    atatat 	int name[CTL_MAXNAME], i, rc, method, flags, rw;
    933   1.75    atatat 	u_int namelen, type;
    934   1.92    atatat 	u_quad_t uq;
    935   1.92    atatat 	quad_t q;
    936   1.75    atatat 
    937   1.82    atatat 	if (!wflag) {
    938   1.92    atatat 		sysctlperror("Must specify -w to create nodes\n");
    939   1.82    atatat 		exit(1);
    940   1.82    atatat 	}
    941   1.82    atatat 
    942   1.75    atatat 	/*
    943   1.75    atatat 	 * these are the pieces that make up the description of a new
    944   1.75    atatat 	 * node
    945   1.75    atatat 	 */
    946   1.75    atatat 	memset(&node, 0, sizeof(node));
    947   1.75    atatat 	node.sysctl_num = CTL_CREATE;  /* any number is fine */
    948   1.75    atatat 	flags = 0;
    949   1.75    atatat 	rw = -1;
    950   1.75    atatat 	type = 0;
    951   1.75    atatat 	sz = 0;
    952   1.75    atatat 	data = addr = NULL;
    953   1.75    atatat 	memset(name, 0, sizeof(name));
    954   1.75    atatat 	namelen = 0;
    955   1.75    atatat 	method = 0;
    956   1.75    atatat 
    957   1.75    atatat 	/*
    958   1.75    atatat 	 * misc stuff used when constructing
    959   1.75    atatat 	 */
    960   1.75    atatat 	i = 0;
    961   1.92    atatat 	uq = 0;
    962   1.75    atatat 	key = NULL;
    963   1.75    atatat 	value = NULL;
    964   1.75    atatat 
    965   1.75    atatat 	/*
    966   1.75    atatat 	 * the name of the thing we're trying to create is first, so
    967   1.75    atatat 	 * pick it off.
    968   1.75    atatat 	 */
    969   1.75    atatat 	nname = l;
    970   1.75    atatat 	if ((c = strchr(nname, ',')) != NULL)
    971   1.75    atatat 		*c++ = '\0';
    972   1.75    atatat 
    973   1.75    atatat 	while (c != NULL) {
    974   1.75    atatat 
    975   1.75    atatat 		/*
    976   1.75    atatat 		 * pull off the next "key=value" pair
    977   1.75    atatat 		 */
    978   1.75    atatat 		key = c;
    979   1.75    atatat 		if ((t = strchr(key, '=')) != NULL) {
    980   1.75    atatat 			*t++ = '\0';
    981   1.75    atatat 			value = t;
    982   1.75    atatat 		}
    983   1.75    atatat 		else
    984   1.75    atatat 			value = NULL;
    985   1.75    atatat 
    986   1.75    atatat 		/*
    987   1.75    atatat 		 * if the "key" is "value", then that eats the rest of
    988   1.75    atatat 		 * the string, so we're done, otherwise bite it off at
    989   1.75    atatat 		 * the next comma.
    990   1.75    atatat 		 */
    991   1.75    atatat 		if (strcmp(key, "value") == 0) {
    992   1.75    atatat 			c = NULL;
    993   1.75    atatat 			data = value;
    994   1.75    atatat 			break;
    995   1.75    atatat 		}
    996  1.112  christos 		else if (value) {
    997   1.75    atatat 			if ((c = strchr(value, ',')) != NULL)
    998   1.75    atatat 				*c++ = '\0';
    999   1.75    atatat 		}
   1000   1.75    atatat 
   1001   1.75    atatat 		/*
   1002   1.75    atatat 		 * note that we (mostly) let the invoker of sysctl(8)
   1003   1.75    atatat 		 * play rampant here and depend on the kernel to tell
   1004   1.75    atatat 		 * them that they were wrong.  well...within reason.
   1005   1.75    atatat 		 * we later check the various parameters against each
   1006   1.75    atatat 		 * other to make sure it makes some sort of sense.
   1007   1.75    atatat 		 */
   1008   1.75    atatat 		if (strcmp(key, "addr") == 0) {
   1009   1.75    atatat 			/*
   1010   1.75    atatat 			 * we can't check these two.  only the kernel
   1011   1.75    atatat 			 * can tell us when it fails to find the name
   1012   1.75    atatat 			 * (or if the address is invalid).
   1013   1.75    atatat 			 */
   1014   1.75    atatat 			if (method != 0) {
   1015   1.92    atatat 				sysctlperror(
   1016   1.92    atatat 				    "%s: already have %s for new node\n",
   1017   1.92    atatat 				    nname,
   1018   1.75    atatat 				    method == CTL_CREATE ? "addr" : "symbol");
   1019   1.92    atatat 				EXIT(1);
   1020   1.75    atatat 			}
   1021  1.113  christos 			if (value == NULL) {
   1022  1.113  christos 				sysctlperror("%s: missing value\n", nname);
   1023  1.113  christos 				EXIT(1);
   1024  1.113  christos 			}
   1025  1.114  christos 			errno = 0;
   1026   1.75    atatat 			addr = (void*)strtoul(value, &t, 0);
   1027   1.94    atatat 			if (t == value || *t != '\0' || errno != 0) {
   1028   1.92    atatat 				sysctlperror(
   1029   1.92    atatat 				    "%s: '%s' is not a valid address\n",
   1030   1.92    atatat 				    nname, value);
   1031   1.92    atatat 				EXIT(1);
   1032   1.75    atatat 			}
   1033   1.75    atatat 			method = CTL_CREATE;
   1034   1.75    atatat 		}
   1035   1.75    atatat 		else if (strcmp(key, "symbol") == 0) {
   1036   1.75    atatat 			if (method != 0) {
   1037   1.92    atatat 				sysctlperror(
   1038   1.92    atatat 				    "%s: already have %s for new node\n",
   1039   1.92    atatat 				    nname,
   1040   1.75    atatat 				    method == CTL_CREATE ? "addr" : "symbol");
   1041   1.92    atatat 				EXIT(1);
   1042   1.75    atatat 			}
   1043   1.75    atatat 			addr = value;
   1044   1.75    atatat 			method = CTL_CREATESYM;
   1045   1.75    atatat 		}
   1046   1.75    atatat 		else if (strcmp(key, "type") == 0) {
   1047  1.114  christos 			if (value == NULL) {
   1048  1.114  christos 				sysctlperror("%s: missing value\n", nname);
   1049  1.114  christos 				EXIT(1);
   1050  1.114  christos 			}
   1051   1.75    atatat 			if (strcmp(value, "node") == 0)
   1052   1.75    atatat 				type = CTLTYPE_NODE;
   1053   1.75    atatat 			else if (strcmp(value, "int") == 0) {
   1054   1.75    atatat 				sz = sizeof(int);
   1055   1.75    atatat 				type = CTLTYPE_INT;
   1056   1.75    atatat 			}
   1057   1.75    atatat 			else if (strcmp(value, "string") == 0)
   1058   1.75    atatat 				type = CTLTYPE_STRING;
   1059   1.75    atatat 			else if (strcmp(value, "quad") == 0) {
   1060   1.75    atatat 				sz = sizeof(u_quad_t);
   1061   1.75    atatat 				type = CTLTYPE_QUAD;
   1062   1.75    atatat 			}
   1063   1.75    atatat 			else if (strcmp(value, "struct") == 0)
   1064   1.75    atatat 				type = CTLTYPE_STRUCT;
   1065   1.75    atatat 			else {
   1066   1.92    atatat 				sysctlperror(
   1067   1.92    atatat 					"%s: '%s' is not a valid type\n",
   1068   1.92    atatat 					nname, value);
   1069   1.92    atatat 				EXIT(1);
   1070   1.75    atatat 			}
   1071   1.75    atatat 		}
   1072   1.75    atatat 		else if (strcmp(key, "size") == 0) {
   1073  1.115   jnemeth 			if (value == NULL) {
   1074  1.115   jnemeth 				sysctlperror("%s: missing value\n", nname);
   1075  1.115   jnemeth 				EXIT(1);
   1076  1.115   jnemeth 			}
   1077   1.75    atatat 			errno = 0;
   1078   1.75    atatat 			/*
   1079   1.75    atatat 			 * yes, i know size_t is not an unsigned long,
   1080   1.75    atatat 			 * but we can all agree that it ought to be,
   1081   1.75    atatat 			 * right?
   1082   1.75    atatat 			 */
   1083   1.75    atatat 			sz = strtoul(value, &t, 0);
   1084   1.94    atatat 			if (t == value || *t != '\0' || errno != 0) {
   1085   1.92    atatat 				sysctlperror(
   1086   1.92    atatat 					"%s: '%s' is not a valid size\n",
   1087   1.92    atatat 					nname, value);
   1088   1.92    atatat 				EXIT(1);
   1089   1.75    atatat 			}
   1090   1.75    atatat 		}
   1091   1.75    atatat 		else if (strcmp(key, "n") == 0) {
   1092  1.114  christos 			if (value == NULL) {
   1093  1.114  christos 				sysctlperror("%s: missing value\n", nname);
   1094  1.114  christos 				EXIT(1);
   1095  1.114  christos 			}
   1096   1.75    atatat 			errno = 0;
   1097  1.110  christos 			q = strtoll(value, &t, 0);
   1098   1.94    atatat 			if (t == value || *t != '\0' || errno != 0 ||
   1099   1.92    atatat 			    q < INT_MIN || q > UINT_MAX) {
   1100   1.92    atatat 				sysctlperror(
   1101   1.92    atatat 				    "%s: '%s' is not a valid mib number\n",
   1102   1.92    atatat 				    nname, value);
   1103   1.92    atatat 				EXIT(1);
   1104   1.75    atatat 			}
   1105   1.92    atatat 			node.sysctl_num = (int)q;
   1106   1.75    atatat 		}
   1107   1.75    atatat 		else if (strcmp(key, "flags") == 0) {
   1108  1.114  christos 			if (value == NULL) {
   1109  1.114  christos 				sysctlperror("%s: missing value\n", nname);
   1110  1.114  christos 				EXIT(1);
   1111  1.114  christos 			}
   1112   1.75    atatat 			t = value;
   1113   1.75    atatat 			while (*t != '\0') {
   1114   1.75    atatat 				switch (*t) {
   1115   1.75    atatat 				case 'a':
   1116   1.83    atatat 					flags |= CTLFLAG_ANYWRITE;
   1117   1.75    atatat 					break;
   1118   1.75    atatat 				case 'h':
   1119   1.83    atatat 					flags |= CTLFLAG_HIDDEN;
   1120   1.75    atatat 					break;
   1121   1.75    atatat 				case 'i':
   1122   1.83    atatat 					flags |= CTLFLAG_IMMEDIATE;
   1123   1.75    atatat 					break;
   1124   1.75    atatat 				case 'o':
   1125   1.83    atatat 					flags |= CTLFLAG_OWNDATA;
   1126   1.75    atatat 					break;
   1127   1.75    atatat 				case 'p':
   1128   1.83    atatat 					flags |= CTLFLAG_PRIVATE;
   1129   1.75    atatat 					break;
   1130   1.75    atatat 				case 'x':
   1131   1.83    atatat 					flags |= CTLFLAG_HEX;
   1132   1.75    atatat 					break;
   1133   1.75    atatat 
   1134   1.75    atatat 				case 'r':
   1135   1.83    atatat 					rw = CTLFLAG_READONLY;
   1136   1.75    atatat 					break;
   1137   1.75    atatat 				case 'w':
   1138   1.83    atatat 					rw = CTLFLAG_READWRITE;
   1139   1.75    atatat 					break;
   1140   1.75    atatat 				default:
   1141   1.92    atatat 					sysctlperror(
   1142   1.92    atatat 					   "%s: '%c' is not a valid flag\n",
   1143   1.92    atatat 					    nname, *t);
   1144   1.92    atatat 					EXIT(1);
   1145   1.75    atatat 				}
   1146   1.75    atatat 				t++;
   1147   1.75    atatat 			}
   1148   1.75    atatat 		}
   1149   1.75    atatat 		else {
   1150   1.92    atatat 			sysctlperror("%s: unrecognized keyword '%s'\n",
   1151   1.92    atatat 				     nname, key);
   1152   1.92    atatat 			EXIT(1);
   1153   1.75    atatat 		}
   1154   1.75    atatat 	}
   1155   1.75    atatat 
   1156   1.75    atatat 	/*
   1157   1.75    atatat 	 * now that we've finished parsing the given string, fill in
   1158   1.75    atatat 	 * anything they didn't specify
   1159   1.75    atatat 	 */
   1160   1.75    atatat 	if (type == 0)
   1161   1.75    atatat 		type = CTLTYPE_NODE;
   1162   1.75    atatat 
   1163   1.75    atatat 	/*
   1164   1.75    atatat 	 * the "data" can be interpreted various ways depending on the
   1165   1.75    atatat 	 * type of node we're creating, as can the size
   1166   1.75    atatat 	 */
   1167   1.75    atatat 	if (data != NULL) {
   1168   1.75    atatat 		if (addr != NULL) {
   1169   1.92    atatat 			sysctlperror(
   1170   1.92    atatat 				"%s: cannot specify both value and "
   1171   1.92    atatat 				"address\n", nname);
   1172   1.92    atatat 			EXIT(1);
   1173   1.75    atatat 		}
   1174   1.75    atatat 
   1175   1.75    atatat 		switch (type) {
   1176   1.75    atatat 		case CTLTYPE_INT:
   1177   1.75    atatat 			errno = 0;
   1178  1.110  christos 			q = strtoll(data, &t, 0);
   1179   1.94    atatat 			if (t == data || *t != '\0' || errno != 0 ||
   1180   1.92    atatat 				q < INT_MIN || q > UINT_MAX) {
   1181   1.92    atatat 				sysctlperror(
   1182   1.92    atatat 				    "%s: '%s' is not a valid integer\n",
   1183   1.92    atatat 				    nname, value);
   1184   1.92    atatat 				EXIT(1);
   1185   1.75    atatat 			}
   1186   1.92    atatat 			i = (int)q;
   1187   1.83    atatat 			if (!(flags & CTLFLAG_OWNDATA)) {
   1188   1.83    atatat 				flags |= CTLFLAG_IMMEDIATE;
   1189   1.75    atatat 				node.sysctl_idata = i;
   1190   1.75    atatat 			}
   1191   1.75    atatat 			else
   1192   1.75    atatat 				node.sysctl_data = &i;
   1193   1.75    atatat 			if (sz == 0)
   1194   1.75    atatat 				sz = sizeof(int);
   1195   1.75    atatat 			break;
   1196   1.75    atatat 		case CTLTYPE_STRING:
   1197   1.83    atatat 			flags |= CTLFLAG_OWNDATA;
   1198   1.75    atatat 			node.sysctl_data = data;
   1199   1.75    atatat 			if (sz == 0)
   1200   1.75    atatat 				sz = strlen(data) + 1;
   1201   1.75    atatat 			else if (sz < strlen(data) + 1) {
   1202   1.92    atatat 				sysctlperror("%s: ignoring size=%zu for "
   1203   1.75    atatat 					"string node, too small for given "
   1204   1.92    atatat 					"value\n", nname, sz);
   1205   1.75    atatat 				sz = strlen(data) + 1;
   1206   1.75    atatat 			}
   1207   1.75    atatat 			break;
   1208   1.75    atatat 		case CTLTYPE_QUAD:
   1209   1.75    atatat 			errno = 0;
   1210   1.92    atatat 			uq = strtouq(data, &t, 0);
   1211   1.94    atatat 			if (t == data || *t != '\0' || errno != 0) {
   1212   1.92    atatat 				sysctlperror(
   1213   1.92    atatat 					"%s: '%s' is not a valid quad\n",
   1214   1.92    atatat 					nname, value);
   1215   1.92    atatat 				EXIT(1);
   1216   1.75    atatat 			}
   1217   1.83    atatat 			if (!(flags & CTLFLAG_OWNDATA)) {
   1218   1.83    atatat 				flags |= CTLFLAG_IMMEDIATE;
   1219   1.92    atatat 				node.sysctl_qdata = uq;
   1220   1.75    atatat 			}
   1221   1.75    atatat 			else
   1222   1.92    atatat 				node.sysctl_data = &uq;
   1223   1.75    atatat 			if (sz == 0)
   1224   1.75    atatat 				sz = sizeof(u_quad_t);
   1225   1.75    atatat 			break;
   1226   1.75    atatat 		case CTLTYPE_STRUCT:
   1227   1.92    atatat 			sysctlperror("%s: struct not initializable\n",
   1228   1.92    atatat 				     nname);
   1229   1.92    atatat 			EXIT(1);
   1230   1.75    atatat 		}
   1231   1.75    atatat 
   1232   1.75    atatat 		/*
   1233   1.75    atatat 		 * these methods have all provided local starting
   1234   1.75    atatat 		 * values that the kernel must copy in
   1235   1.75    atatat 		 */
   1236   1.75    atatat 	}
   1237   1.75    atatat 
   1238   1.75    atatat 	/*
   1239   1.75    atatat 	 * hmm...no data, but we have an address of data.  that's
   1240   1.75    atatat 	 * fine.
   1241   1.75    atatat 	 */
   1242   1.75    atatat 	else if (addr != 0)
   1243   1.75    atatat 		node.sysctl_data = (void*)addr;
   1244   1.75    atatat 
   1245   1.75    atatat 	/*
   1246   1.75    atatat 	 * no data and no address?  well...okay.  we might be able to
   1247   1.75    atatat 	 * manage that.
   1248   1.75    atatat 	 */
   1249   1.75    atatat 	else if (type != CTLTYPE_NODE) {
   1250   1.75    atatat 		if (sz == 0) {
   1251   1.92    atatat 			sysctlperror(
   1252   1.92    atatat 			    "%s: need a size or a starting value\n",
   1253   1.92    atatat 			    nname);
   1254   1.92    atatat                         EXIT(1);
   1255   1.75    atatat                 }
   1256   1.83    atatat 		if (!(flags & CTLFLAG_IMMEDIATE))
   1257   1.83    atatat 			flags |= CTLFLAG_OWNDATA;
   1258   1.75    atatat 	}
   1259   1.75    atatat 
   1260   1.75    atatat 	/*
   1261   1.75    atatat 	 * now we do a few sanity checks on the description we've
   1262   1.75    atatat 	 * assembled
   1263   1.75    atatat 	 */
   1264   1.83    atatat 	if ((flags & CTLFLAG_IMMEDIATE) &&
   1265   1.75    atatat 	    (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
   1266   1.92    atatat 		sysctlperror("%s: cannot make an immediate %s\n",
   1267   1.92    atatat 			     nname,
   1268   1.92    atatat 			     (type == CTLTYPE_STRING) ? "string" : "struct");
   1269   1.92    atatat 		EXIT(1);
   1270   1.75    atatat 	}
   1271   1.75    atatat 	if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
   1272   1.92    atatat 		sysctlperror("%s: nodes do not have data\n", nname);
   1273   1.92    atatat 		EXIT(1);
   1274   1.75    atatat 	}
   1275   1.75    atatat 
   1276   1.75    atatat 	/*
   1277   1.75    atatat 	 * some types must have a particular size
   1278   1.75    atatat 	 */
   1279   1.75    atatat 	if (sz != 0) {
   1280   1.75    atatat 		if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
   1281   1.75    atatat 		    (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
   1282   1.75    atatat 		    (type == CTLTYPE_NODE && sz != 0)) {
   1283   1.92    atatat 			sysctlperror("%s: wrong size for type\n", nname);
   1284   1.92    atatat 			EXIT(1);
   1285   1.75    atatat 		}
   1286   1.75    atatat 	}
   1287   1.75    atatat 	else if (type == CTLTYPE_STRUCT) {
   1288   1.92    atatat 		sysctlperror("%s: struct must have size\n", nname);
   1289   1.92    atatat 		EXIT(1);
   1290   1.75    atatat 	}
   1291   1.75    atatat 
   1292   1.75    atatat 	/*
   1293   1.75    atatat 	 * now...if no one said anything yet, we default nodes or
   1294   1.75    atatat 	 * any type that owns data being writeable, and everything
   1295   1.75    atatat 	 * else being readonly.
   1296   1.75    atatat 	 */
   1297   1.75    atatat 	if (rw == -1) {
   1298   1.75    atatat 		if (type == CTLTYPE_NODE ||
   1299   1.83    atatat 		    (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE)))
   1300   1.83    atatat 			rw = CTLFLAG_READWRITE;
   1301   1.75    atatat 		else
   1302   1.83    atatat 			rw = CTLFLAG_READONLY;
   1303   1.75    atatat 	}
   1304   1.75    atatat 
   1305   1.75    atatat 	/*
   1306   1.75    atatat 	 * if a kernel address was specified, that can't be made
   1307   1.75    atatat 	 * writeable by us.
   1308   1.83    atatat 	if (rw != CTLFLAG_READONLY && addr) {
   1309   1.92    atatat 		sysctlperror("%s: kernel data can only be readable\n", nname);
   1310   1.92    atatat 		EXIT(1);
   1311   1.75    atatat 	}
   1312   1.75    atatat 	 */
   1313   1.75    atatat 
   1314   1.75    atatat 	/*
   1315   1.75    atatat 	 * what separator were they using in the full name of the new
   1316   1.75    atatat 	 * node?
   1317   1.75    atatat 	 */
   1318   1.75    atatat 	if ((t = strpbrk(nname, "./")) == NULL)
   1319   1.75    atatat 		sep[0] = '.';
   1320   1.75    atatat 	else
   1321   1.75    atatat 		sep[0] = t[0];
   1322   1.75    atatat 	sep[1] = '\0';
   1323   1.75    atatat 
   1324   1.75    atatat 	/*
   1325   1.75    atatat 	 * put it all together, now.  t'ain't much, is it?
   1326   1.75    atatat 	 */
   1327   1.83    atatat 	node.sysctl_flags = SYSCTL_VERSION|flags|rw|type;
   1328   1.75    atatat 	node.sysctl_size = sz;
   1329   1.75    atatat 	t = strrchr(nname, sep[0]);
   1330   1.75    atatat 	if (t != NULL)
   1331   1.75    atatat 		strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
   1332   1.75    atatat 	else
   1333   1.75    atatat 		strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
   1334   1.82    atatat 	if (t == nname)
   1335   1.82    atatat 		t = NULL;
   1336   1.75    atatat 
   1337   1.75    atatat 	/*
   1338   1.75    atatat 	 * if this is a new top-level node, then we don't need to find
   1339   1.75    atatat 	 * the mib for its parent
   1340   1.75    atatat 	 */
   1341   1.75    atatat 	if (t == NULL) {
   1342   1.75    atatat 		namelen = 0;
   1343   1.75    atatat 		gsname[0] = '\0';
   1344   1.75    atatat 	}
   1345   1.75    atatat 
   1346   1.75    atatat 	/*
   1347   1.75    atatat 	 * on the other hand, if it's not a top-level node...
   1348   1.75    atatat 	 */
   1349   1.75    atatat 	else {
   1350   1.75    atatat 		namelen = sizeof(name) / sizeof(name[0]);
   1351   1.75    atatat 		sz = sizeof(gsname);
   1352   1.75    atatat 		*t = '\0';
   1353   1.78    atatat 		rc = sysctlgetmibinfo(nname, &name[0], &namelen,
   1354   1.83    atatat 				      gsname, &sz, NULL, SYSCTL_VERSION);
   1355   1.75    atatat 		*t = sep[0];
   1356   1.75    atatat 		if (rc == -1) {
   1357   1.92    atatat 			sysctlparseerror(namelen, nname);
   1358   1.92    atatat 			EXIT(1);
   1359    1.1       cgd 		}
   1360   1.75    atatat 	}
   1361   1.75    atatat 
   1362   1.75    atatat 	/*
   1363   1.75    atatat 	 * yes, a new node is being created
   1364   1.75    atatat 	 */
   1365   1.75    atatat 	if (method != 0)
   1366   1.75    atatat 		name[namelen++] = method;
   1367   1.75    atatat 	else
   1368   1.75    atatat 		name[namelen++] = CTL_CREATE;
   1369   1.75    atatat 
   1370   1.75    atatat 	sz = sizeof(node);
   1371   1.75    atatat 	rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
   1372   1.75    atatat 
   1373   1.75    atatat 	if (rc == -1) {
   1374   1.92    atatat 		sysctlperror("%s: CTL_CREATE failed: %s\n",
   1375   1.92    atatat 			     nname, strerror(errno));
   1376   1.92    atatat 		EXIT(1);
   1377   1.75    atatat 	}
   1378  1.100    atatat 	else {
   1379  1.100    atatat 		if (!qflag && !nflag)
   1380  1.100    atatat 			printf("%s(%s): (created)\n", nname, st(type));
   1381  1.100    atatat 		stale = 1;
   1382  1.100    atatat 	}
   1383   1.75    atatat }
   1384   1.75    atatat 
   1385   1.75    atatat static void
   1386   1.82    atatat parse_destroy(char *l)
   1387   1.75    atatat {
   1388   1.75    atatat 	struct sysctlnode node;
   1389   1.75    atatat 	size_t sz;
   1390   1.75    atatat 	int name[CTL_MAXNAME], rc;
   1391   1.75    atatat 	u_int namelen;
   1392   1.75    atatat 
   1393   1.82    atatat 	if (!wflag) {
   1394   1.92    atatat 		sysctlperror("Must specify -w to destroy nodes\n");
   1395   1.82    atatat 		exit(1);
   1396   1.82    atatat 	}
   1397   1.82    atatat 
   1398   1.75    atatat 	memset(name, 0, sizeof(name));
   1399   1.75    atatat 	namelen = sizeof(name) / sizeof(name[0]);
   1400   1.75    atatat 	sz = sizeof(gsname);
   1401   1.83    atatat 	rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
   1402   1.83    atatat 			      SYSCTL_VERSION);
   1403   1.75    atatat 	if (rc == -1) {
   1404   1.92    atatat 		sysctlparseerror(namelen, l);
   1405   1.92    atatat 		EXIT(1);
   1406   1.75    atatat 	}
   1407   1.75    atatat 
   1408   1.75    atatat 	memset(&node, 0, sizeof(node));
   1409   1.83    atatat 	node.sysctl_flags = SYSCTL_VERSION;
   1410   1.75    atatat 	node.sysctl_num = name[namelen - 1];
   1411   1.75    atatat 	name[namelen - 1] = CTL_DESTROY;
   1412   1.75    atatat 
   1413   1.75    atatat 	sz = sizeof(node);
   1414   1.75    atatat 	rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
   1415   1.75    atatat 
   1416   1.75    atatat 	if (rc == -1) {
   1417   1.92    atatat 		sysctlperror("%s: CTL_DESTROY failed: %s\n",
   1418   1.92    atatat 			     l, strerror(errno));
   1419   1.92    atatat 		EXIT(1);
   1420   1.75    atatat 	}
   1421  1.100    atatat 	else {
   1422  1.100    atatat 		if (!qflag && !nflag)
   1423  1.100    atatat 			printf("%s(%s): (destroyed)\n", gsname,
   1424  1.100    atatat 			       st(SYSCTL_TYPE(node.sysctl_flags)));
   1425  1.100    atatat 		stale = 1;
   1426  1.100    atatat 	}
   1427   1.75    atatat }
   1428   1.75    atatat 
   1429   1.84    atatat static void
   1430   1.84    atatat parse_describe(char *l)
   1431   1.84    atatat {
   1432   1.84    atatat 	struct sysctlnode newdesc;
   1433   1.84    atatat 	char buf[1024], *value;
   1434   1.84    atatat 	struct sysctldesc *d = (void*)&buf[0];
   1435   1.84    atatat 	int name[CTL_MAXNAME], rc;
   1436   1.84    atatat 	u_int namelen;
   1437   1.84    atatat 	size_t sz;
   1438   1.84    atatat 
   1439   1.84    atatat 	if (!wflag) {
   1440   1.92    atatat 		sysctlperror("Must specify -w to set descriptions\n");
   1441   1.84    atatat 		exit(1);
   1442   1.84    atatat 	}
   1443   1.84    atatat 
   1444   1.84    atatat 	value = strchr(l, '=');
   1445   1.84    atatat 	*value++ = '\0';
   1446   1.84    atatat 
   1447   1.84    atatat 	memset(name, 0, sizeof(name));
   1448   1.84    atatat 	namelen = sizeof(name) / sizeof(name[0]);
   1449   1.84    atatat 	sz = sizeof(gsname);
   1450   1.84    atatat 	rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
   1451   1.84    atatat 			      SYSCTL_VERSION);
   1452   1.84    atatat 	if (rc == -1) {
   1453   1.92    atatat 		sysctlparseerror(namelen, l);
   1454   1.92    atatat 		EXIT(1);
   1455   1.84    atatat 	}
   1456   1.84    atatat 
   1457   1.84    atatat 	sz = sizeof(buf);
   1458   1.84    atatat 	memset(&newdesc, 0, sizeof(newdesc));
   1459   1.84    atatat 	newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC;
   1460   1.84    atatat 	newdesc.sysctl_num = name[namelen - 1];
   1461   1.84    atatat 	newdesc.sysctl_desc = value;
   1462   1.84    atatat 	name[namelen - 1] = CTL_DESCRIBE;
   1463   1.84    atatat 	rc = sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc));
   1464   1.84    atatat 	if (rc == -1)
   1465   1.92    atatat 		sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
   1466   1.92    atatat 			     gsname, strerror(errno));
   1467   1.84    atatat 	else if (d->descr_len == 1)
   1468   1.92    atatat 		sysctlperror("%s: description not set\n", gsname);
   1469   1.84    atatat 	else if (!qflag && !nflag)
   1470   1.84    atatat 		printf("%s: %s\n", gsname, d->descr_str);
   1471   1.84    atatat }
   1472   1.84    atatat 
   1473   1.75    atatat /*
   1474   1.75    atatat  * ********************************************************************
   1475   1.75    atatat  * when things go wrong...
   1476   1.75    atatat  * ********************************************************************
   1477   1.75    atatat  */
   1478   1.75    atatat static void
   1479   1.75    atatat usage(void)
   1480   1.75    atatat {
   1481   1.75    atatat 	const char *progname = getprogname();
   1482    1.1       cgd 
   1483   1.75    atatat 	(void)fprintf(stderr,
   1484   1.77      jmmv 		      "usage:\t%s %s\n"
   1485   1.75    atatat 		      "\t%s %s\n"
   1486   1.75    atatat 		      "\t%s %s\n"
   1487   1.75    atatat 		      "\t%s %s\n"
   1488   1.75    atatat 		      "\t%s %s\n"
   1489   1.75    atatat 		      "\t%s %s\n",
   1490   1.87    atatat 		      progname, "[-dne] [-x[x]|-r] variable ...",
   1491   1.75    atatat 		      progname, "[-ne] [-q] -w variable=value ...",
   1492   1.87    atatat 		      progname, "[-dne] -a",
   1493   1.87    atatat 		      progname, "[-dne] -A",
   1494   1.75    atatat 		      progname, "[-ne] -M",
   1495   1.87    atatat 		      progname, "[-dne] [-q] -f file");
   1496   1.75    atatat 	exit(1);
   1497   1.22    bouyer }
   1498   1.22    bouyer 
   1499   1.84    atatat static void
   1500   1.84    atatat getdesc1(int *name, u_int namelen, struct sysctlnode *pnode)
   1501   1.84    atatat {
   1502   1.84    atatat 	struct sysctlnode node;
   1503   1.84    atatat 	char buf[1024], *desc;
   1504   1.84    atatat 	struct sysctldesc *d = (void*)buf;
   1505   1.84    atatat 	size_t sz = sizeof(buf);
   1506   1.84    atatat 	int rc;
   1507   1.84    atatat 
   1508   1.84    atatat 	memset(&node, 0, sizeof(node));
   1509   1.84    atatat 	node.sysctl_flags = SYSCTL_VERSION;
   1510   1.84    atatat 	node.sysctl_num = name[namelen - 1];
   1511   1.84    atatat 	name[namelen - 1] = CTL_DESCRIBE;
   1512   1.84    atatat 	rc = sysctl(name, namelen, d, &sz, &node, sizeof(node));
   1513   1.84    atatat 
   1514   1.84    atatat 	if (rc == -1 ||
   1515   1.84    atatat 	    d->descr_len == 1 ||
   1516   1.84    atatat 	    d->descr_num != pnode->sysctl_num ||
   1517   1.84    atatat 	    d->descr_ver != pnode->sysctl_ver)
   1518   1.84    atatat 		desc = (char *)-1;
   1519   1.84    atatat 	else
   1520   1.84    atatat 		desc = malloc(d->descr_len);
   1521   1.84    atatat 
   1522   1.84    atatat 	if (desc == NULL)
   1523   1.84    atatat 		desc = (char *)-1;
   1524   1.84    atatat 	if (desc != (char *)-1)
   1525   1.89    atatat 		memcpy(desc, &d->descr_str[0], d->descr_len);
   1526   1.84    atatat 	name[namelen - 1] = node.sysctl_num;
   1527   1.84    atatat 	if (pnode->sysctl_desc != NULL &&
   1528   1.84    atatat 	    pnode->sysctl_desc != (const char *)-1)
   1529  1.104  christos 		free(__UNCONST(pnode->sysctl_desc));
   1530   1.84    atatat 	pnode->sysctl_desc = desc;
   1531   1.84    atatat }
   1532   1.84    atatat 
   1533   1.84    atatat static void
   1534   1.84    atatat getdesc(int *name, u_int namelen, struct sysctlnode *pnode)
   1535   1.84    atatat {
   1536   1.84    atatat 	struct sysctlnode *node = pnode->sysctl_child;
   1537   1.92    atatat 	struct sysctldesc *d, *p, *plim;
   1538   1.84    atatat 	char *desc;
   1539  1.128     lukem 	size_t i, sz;
   1540  1.128     lukem 	int rc;
   1541   1.84    atatat 
   1542   1.84    atatat 	sz = 128 * pnode->sysctl_clen;
   1543   1.84    atatat 	name[namelen] = CTL_DESCRIBE;
   1544   1.84    atatat 
   1545   1.84    atatat 	/*
   1546   1.84    atatat 	 * attempt *twice* to get the description chunk.  if two tries
   1547   1.84    atatat 	 * doesn't work, give up.
   1548   1.84    atatat 	 */
   1549   1.84    atatat 	i = 0;
   1550   1.84    atatat 	do {
   1551   1.93    atatat 		d = malloc(sz);
   1552   1.84    atatat 		if (d == NULL)
   1553   1.84    atatat 			return;
   1554   1.84    atatat 		rc = sysctl(name, namelen + 1, d, &sz, NULL, 0);
   1555   1.84    atatat 		if (rc == -1) {
   1556   1.84    atatat 			free(d);
   1557   1.84    atatat 			d = NULL;
   1558   1.84    atatat 			if (i == 0 && errno == ENOMEM)
   1559   1.84    atatat 				i = 1;
   1560   1.84    atatat 			else
   1561   1.84    atatat 				return;
   1562   1.84    atatat 		}
   1563   1.84    atatat 	} while (d == NULL);
   1564   1.84    atatat 
   1565   1.84    atatat 	/*
   1566   1.84    atatat 	 * hokey nested loop here, giving O(n**2) behavior, but should
   1567   1.84    atatat 	 * suffice for now
   1568   1.84    atatat 	 */
   1569   1.92    atatat 	plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz);
   1570   1.84    atatat 	for (i = 0; i < pnode->sysctl_clen; i++) {
   1571   1.84    atatat 		node = &pnode->sysctl_child[i];
   1572   1.92    atatat 		for (p = d; p < plim; p = NEXT_DESCR(p))
   1573   1.84    atatat 			if (node->sysctl_num == p->descr_num)
   1574   1.84    atatat 				break;
   1575   1.99    atatat 		if (p < plim && node->sysctl_ver == p->descr_ver) {
   1576   1.84    atatat 			/*
   1577   1.84    atatat 			 * match found, attempt to attach description
   1578   1.84    atatat 			 */
   1579   1.84    atatat 			if (p->descr_len == 1)
   1580   1.84    atatat 				desc = NULL;
   1581   1.84    atatat 			else
   1582   1.84    atatat 				desc = malloc(p->descr_len);
   1583   1.84    atatat 			if (desc == NULL)
   1584   1.84    atatat 				desc = (char *)-1;
   1585   1.84    atatat 			else
   1586   1.90    atatat 				memcpy(desc, &p->descr_str[0], p->descr_len);
   1587   1.84    atatat 			node->sysctl_desc = desc;
   1588   1.84    atatat 		}
   1589   1.84    atatat 	}
   1590   1.84    atatat 
   1591   1.84    atatat 	free(d);
   1592   1.84    atatat }
   1593   1.84    atatat 
   1594   1.92    atatat static void
   1595   1.92    atatat trim_whitespace(char *s, int dir)
   1596   1.92    atatat {
   1597   1.92    atatat 	char *i, *o;
   1598   1.92    atatat 
   1599   1.92    atatat 	i = o = s;
   1600   1.92    atatat 	if (dir & 1)
   1601   1.92    atatat 		while (isspace((unsigned char)*i))
   1602   1.92    atatat 			i++;
   1603   1.92    atatat 	while ((*o++ = *i++) != '\0');
   1604   1.92    atatat 	o -= 2; /* already past nul, skip back to before it */
   1605   1.92    atatat 	if (dir & 2)
   1606   1.92    atatat 		while (o > s && isspace((unsigned char)*o))
   1607   1.92    atatat 			*o-- = '\0';
   1608   1.92    atatat }
   1609   1.92    atatat 
   1610   1.75    atatat void
   1611   1.75    atatat sysctlerror(int soft)
   1612   1.75    atatat {
   1613   1.75    atatat 	if (soft) {
   1614   1.75    atatat 		switch (errno) {
   1615   1.75    atatat 		case ENOENT:
   1616   1.75    atatat 		case ENOPROTOOPT:
   1617   1.75    atatat 		case ENOTDIR:
   1618   1.97    atatat 		case EINVAL:
   1619   1.75    atatat 		case EOPNOTSUPP:
   1620   1.75    atatat 		case EPROTONOSUPPORT:
   1621   1.75    atatat 			if (Aflag || req)
   1622   1.92    atatat 				sysctlperror("%s: the value is not available\n",
   1623   1.92    atatat 					     gsname);
   1624   1.75    atatat 			return;
   1625   1.22    bouyer 		}
   1626   1.75    atatat 	}
   1627   1.75    atatat 
   1628   1.92    atatat 	sysctlperror("%s: sysctl() failed with %s\n",
   1629   1.92    atatat 		     gsname, strerror(errno));
   1630   1.75    atatat 	if (!soft)
   1631   1.92    atatat 		EXIT(1);
   1632   1.92    atatat }
   1633   1.92    atatat 
   1634   1.92    atatat void
   1635   1.92    atatat sysctlparseerror(u_int namelen, const char *pname)
   1636   1.92    atatat {
   1637   1.92    atatat 
   1638   1.92    atatat 	sysctlperror("%s level name '%s' in '%s' is invalid\n",
   1639   1.92    atatat 		     lname[namelen], gsname, pname);
   1640   1.92    atatat }
   1641   1.92    atatat 
   1642   1.92    atatat static void
   1643   1.92    atatat sysctlperror(const char *fmt, ...)
   1644   1.92    atatat {
   1645   1.92    atatat 	va_list ap;
   1646   1.92    atatat 
   1647   1.92    atatat 	(void)fprintf(warnfp, "%s: ", getprogname());
   1648   1.92    atatat 	if (fn)
   1649   1.92    atatat 		(void)fprintf(warnfp, "%s#%zu: ", fn, nr);
   1650   1.92    atatat 	va_start(ap, fmt);
   1651   1.92    atatat 	(void)vfprintf(warnfp, fmt, ap);
   1652   1.92    atatat 	va_end(ap);
   1653  1.121  christos 	errs++;
   1654   1.75    atatat }
   1655   1.75    atatat 
   1656   1.92    atatat 
   1657   1.75    atatat /*
   1658   1.75    atatat  * ********************************************************************
   1659   1.75    atatat  * how to write to a "simple" node
   1660   1.75    atatat  * ********************************************************************
   1661   1.75    atatat  */
   1662   1.75    atatat static void
   1663   1.75    atatat write_number(int *name, u_int namelen, struct sysctlnode *node, char *value)
   1664   1.75    atatat {
   1665  1.110  christos 	u_int ii, io;
   1666   1.75    atatat 	u_quad_t qi, qo;
   1667   1.75    atatat 	size_t si, so;
   1668   1.75    atatat 	int rc;
   1669   1.75    atatat 	void *i, *o;
   1670   1.75    atatat 	char *t;
   1671   1.75    atatat 
   1672   1.92    atatat 	if (fn)
   1673   1.92    atatat 		trim_whitespace(value, 3);
   1674   1.92    atatat 
   1675   1.75    atatat 	si = so = 0;
   1676   1.75    atatat 	i = o = NULL;
   1677   1.75    atatat 	errno = 0;
   1678   1.75    atatat 	qi = strtouq(value, &t, 0);
   1679  1.110  christos 	if (qi == UQUAD_MAX && errno == ERANGE) {
   1680  1.110  christos 		sysctlperror("%s: %s\n", value, strerror(errno));
   1681   1.92    atatat 		EXIT(1);
   1682   1.75    atatat 	}
   1683   1.94    atatat 	if (t == value || *t != '\0') {
   1684   1.92    atatat 		sysctlperror("%s: not a number\n", value);
   1685   1.92    atatat 		EXIT(1);
   1686   1.75    atatat 	}
   1687   1.75    atatat 
   1688   1.75    atatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
   1689  1.110  christos 	case CTLTYPE_INT:
   1690  1.110  christos 		ii = (u_int)qi;
   1691  1.111  christos 		io = (u_int)(qi >> 32);
   1692  1.111  christos 		if (io != (u_int)-1 && io != 0) {
   1693  1.110  christos 			sysctlperror("%s: %s\n", value, strerror(ERANGE));
   1694   1.92    atatat 			EXIT(1);
   1695   1.75    atatat 		}
   1696   1.75    atatat 		o = &io;
   1697   1.75    atatat 		so = sizeof(io);
   1698   1.75    atatat 		i = &ii;
   1699   1.75    atatat 		si = sizeof(ii);
   1700   1.75    atatat 		break;
   1701   1.75    atatat 	case CTLTYPE_QUAD:
   1702   1.75    atatat 		o = &qo;
   1703   1.75    atatat 		so = sizeof(qo);
   1704   1.75    atatat 		i = &qi;
   1705   1.75    atatat 		si = sizeof(qi);
   1706   1.75    atatat 		break;
   1707   1.75    atatat 	}
   1708   1.75    atatat 
   1709   1.75    atatat 	rc = sysctl(name, namelen, o, &so, i, si);
   1710   1.92    atatat 	if (rc == -1) {
   1711   1.75    atatat 		sysctlerror(0);
   1712   1.92    atatat 		return;
   1713   1.92    atatat 	}
   1714   1.75    atatat 
   1715   1.75    atatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
   1716   1.75    atatat 	case CTLTYPE_INT:
   1717   1.75    atatat 		display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
   1718   1.75    atatat 		display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
   1719   1.75    atatat 		break;
   1720   1.75    atatat 	case CTLTYPE_QUAD:
   1721   1.75    atatat 		display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
   1722   1.75    atatat 		display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
   1723   1.75    atatat 		break;
   1724   1.75    atatat 	}
   1725   1.75    atatat }
   1726   1.75    atatat 
   1727   1.75    atatat static void
   1728   1.75    atatat write_string(int *name, u_int namelen, struct sysctlnode *node, char *value)
   1729   1.75    atatat {
   1730   1.75    atatat 	char *i, *o;
   1731   1.75    atatat 	size_t si, so;
   1732   1.75    atatat 	int rc;
   1733   1.75    atatat 
   1734   1.75    atatat 	i = value;
   1735   1.75    atatat 	si = strlen(i) + 1;
   1736   1.75    atatat 	so = node->sysctl_size;
   1737   1.75    atatat 	if (si > so && so != 0) {
   1738   1.92    atatat 		sysctlperror("%s: string too long\n", value);
   1739   1.92    atatat 		EXIT(1);
   1740   1.75    atatat 	}
   1741   1.75    atatat 	o = malloc(so);
   1742   1.75    atatat 	if (o == NULL) {
   1743   1.92    atatat 		sysctlperror("%s: !malloc failed!\n", gsname);
   1744   1.75    atatat 		exit(1);
   1745   1.75    atatat 	}
   1746   1.75    atatat 
   1747   1.75    atatat 	rc = sysctl(name, namelen, o, &so, i, si);
   1748   1.92    atatat 	if (rc == -1) {
   1749   1.75    atatat 		sysctlerror(0);
   1750   1.92    atatat 		return;
   1751   1.92    atatat 	}
   1752   1.75    atatat 
   1753   1.75    atatat 	display_string(node, gsname, o, so, DISPLAY_OLD);
   1754   1.75    atatat 	display_string(node, gsname, i, si, DISPLAY_NEW);
   1755   1.75    atatat 	free(o);
   1756   1.75    atatat }
   1757   1.75    atatat 
   1758   1.75    atatat /*
   1759   1.75    atatat  * ********************************************************************
   1760   1.75    atatat  * simple ways to print stuff consistently
   1761   1.75    atatat  * ********************************************************************
   1762   1.75    atatat  */
   1763   1.75    atatat static void
   1764   1.75    atatat display_number(const struct sysctlnode *node, const char *name,
   1765   1.75    atatat 	       const void *data, size_t sz, int n)
   1766   1.75    atatat {
   1767   1.75    atatat 	u_quad_t q;
   1768   1.75    atatat 	int i;
   1769   1.75    atatat 
   1770   1.75    atatat 	if (qflag)
   1771   1.75    atatat 		return;
   1772   1.75    atatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
   1773   1.75    atatat 		return;
   1774   1.75    atatat 
   1775   1.75    atatat 	if (rflag && n != DISPLAY_OLD) {
   1776   1.75    atatat 		fwrite(data, sz, 1, stdout);
   1777   1.75    atatat 		return;
   1778   1.75    atatat 	}
   1779   1.75    atatat 
   1780   1.75    atatat 	if (!nflag) {
   1781   1.75    atatat 		if (n == DISPLAY_VALUE)
   1782   1.75    atatat 			printf("%s%s", name, eq);
   1783   1.75    atatat 		else if (n == DISPLAY_OLD)
   1784   1.75    atatat 			printf("%s: ", name);
   1785   1.75    atatat 	}
   1786   1.75    atatat 
   1787   1.75    atatat 	if (xflag > 1) {
   1788   1.79    atatat 		if (n != DISPLAY_NEW)
   1789   1.79    atatat 			printf("\n");
   1790   1.75    atatat 		hex_dump(data, sz);
   1791   1.22    bouyer 		return;
   1792   1.75    atatat 	}
   1793   1.22    bouyer 
   1794   1.75    atatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
   1795   1.75    atatat 	case CTLTYPE_INT:
   1796   1.75    atatat 		memcpy(&i, data, sz);
   1797   1.75    atatat 		if (xflag)
   1798   1.75    atatat 			printf("0x%0*x", (int)sz * 2, i);
   1799   1.83    atatat 		else if (node->sysctl_flags & CTLFLAG_HEX)
   1800   1.75    atatat 			printf("%#x", i);
   1801   1.75    atatat 		else
   1802   1.75    atatat 			printf("%d", i);
   1803   1.75    atatat 		break;
   1804    1.1       cgd 	case CTLTYPE_QUAD:
   1805   1.75    atatat 		memcpy(&q, data, sz);
   1806   1.75    atatat 		if (xflag)
   1807   1.75    atatat 			printf("0x%0*" PRIx64, (int)sz * 2, q);
   1808   1.83    atatat 		else if (node->sysctl_flags & CTLFLAG_HEX)
   1809   1.75    atatat 			printf("%#" PRIx64, q);
   1810   1.75    atatat 		else
   1811   1.75    atatat 			printf("%" PRIu64, q);
   1812   1.75    atatat 		break;
   1813   1.75    atatat 	}
   1814   1.75    atatat 
   1815   1.75    atatat 	if (n == DISPLAY_OLD)
   1816   1.75    atatat 		printf(" -> ");
   1817   1.75    atatat 	else
   1818   1.75    atatat 		printf("\n");
   1819   1.75    atatat }
   1820   1.75    atatat 
   1821   1.75    atatat static void
   1822   1.75    atatat display_string(const struct sysctlnode *node, const char *name,
   1823   1.75    atatat 	       const void *data, size_t sz, int n)
   1824   1.75    atatat {
   1825   1.75    atatat 	const unsigned char *buf = data;
   1826   1.75    atatat 	int ni;
   1827   1.75    atatat 
   1828   1.75    atatat 	if (qflag)
   1829   1.75    atatat 		return;
   1830   1.75    atatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
   1831   1.75    atatat 		return;
   1832   1.75    atatat 
   1833   1.75    atatat 	if (rflag && n != DISPLAY_OLD) {
   1834   1.75    atatat 		fwrite(data, sz, 1, stdout);
   1835   1.75    atatat 		return;
   1836   1.75    atatat 	}
   1837   1.75    atatat 
   1838   1.75    atatat 	if (!nflag) {
   1839   1.75    atatat 		if (n == DISPLAY_VALUE)
   1840   1.75    atatat 			printf("%s%s", name, eq);
   1841   1.75    atatat 		else if (n == DISPLAY_OLD)
   1842   1.75    atatat 			printf("%s: ", name);
   1843   1.75    atatat 	}
   1844   1.75    atatat 
   1845   1.75    atatat 	if (xflag > 1) {
   1846   1.79    atatat 		if (n != DISPLAY_NEW)
   1847   1.79    atatat 			printf("\n");
   1848   1.75    atatat 		hex_dump(data, sz);
   1849   1.75    atatat 		return;
   1850   1.75    atatat 	}
   1851   1.75    atatat 
   1852   1.83    atatat 	if (xflag || node->sysctl_flags & CTLFLAG_HEX) {
   1853   1.75    atatat 		for (ni = 0; ni < (int)sz; ni++) {
   1854   1.75    atatat 			if (xflag)
   1855   1.75    atatat 				printf("%02x", buf[ni]);
   1856   1.75    atatat 			if (buf[ni] == '\0')
   1857   1.75    atatat 				break;
   1858   1.75    atatat 			if (!xflag)
   1859   1.75    atatat 				printf("\\x%2.2x", buf[ni]);
   1860    1.1       cgd 		}
   1861   1.75    atatat 	}
   1862   1.75    atatat 	else
   1863   1.75    atatat 		printf("%.*s", (int)sz, buf);
   1864   1.75    atatat 
   1865   1.75    atatat 	if (n == DISPLAY_OLD)
   1866   1.75    atatat 		printf(" -> ");
   1867   1.75    atatat 	else
   1868   1.75    atatat 		printf("\n");
   1869   1.75    atatat }
   1870   1.75    atatat 
   1871   1.75    atatat /*ARGSUSED*/
   1872   1.75    atatat static void
   1873   1.75    atatat display_struct(const struct sysctlnode *node, const char *name,
   1874   1.75    atatat 	       const void *data, size_t sz, int n)
   1875   1.75    atatat {
   1876   1.75    atatat 	const unsigned char *buf = data;
   1877   1.75    atatat 	int ni;
   1878   1.75    atatat 	size_t more;
   1879   1.75    atatat 
   1880   1.75    atatat 	if (qflag)
   1881   1.75    atatat 		return;
   1882   1.75    atatat 	if (!(xflag || rflag)) {
   1883   1.75    atatat 		if (Aflag || req)
   1884   1.92    atatat 			sysctlperror(
   1885   1.92    atatat 			    "%s: this type is unknown to this program\n",
   1886   1.92    atatat 			    gsname);
   1887   1.75    atatat 		return;
   1888   1.75    atatat 	}
   1889   1.75    atatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
   1890    1.1       cgd 		return;
   1891    1.1       cgd 
   1892   1.75    atatat 	if (rflag && n != DISPLAY_OLD) {
   1893   1.75    atatat 		fwrite(data, sz, 1, stdout);
   1894    1.1       cgd 		return;
   1895   1.75    atatat 	}
   1896    1.1       cgd 
   1897   1.75    atatat         if (!nflag) {
   1898   1.75    atatat                 if (n == DISPLAY_VALUE)
   1899   1.75    atatat                         printf("%s%s", name, eq);
   1900   1.75    atatat                 else if (n == DISPLAY_OLD)
   1901   1.75    atatat                         printf("%s: ", name);
   1902   1.75    atatat         }
   1903   1.75    atatat 
   1904   1.75    atatat 	if (xflag > 1) {
   1905   1.79    atatat 		if (n != DISPLAY_NEW)
   1906   1.79    atatat 			printf("\n");
   1907   1.75    atatat 		hex_dump(data, sz);
   1908    1.1       cgd 		return;
   1909    1.1       cgd 	}
   1910   1.75    atatat 
   1911   1.75    atatat 	if (sz > 16) {
   1912   1.75    atatat 		more = sz - 16;
   1913   1.75    atatat 		sz = 16;
   1914   1.75    atatat 	}
   1915   1.75    atatat 	else
   1916   1.75    atatat 		more = 0;
   1917   1.75    atatat 	for (ni = 0; ni < (int)sz; ni++)
   1918   1.75    atatat 		printf("%02x", buf[ni]);
   1919   1.75    atatat 	if (more)
   1920   1.75    atatat 		printf("...(%zu more bytes)", more);
   1921   1.75    atatat 	printf("\n");
   1922   1.75    atatat }
   1923   1.75    atatat 
   1924   1.75    atatat static void
   1925   1.75    atatat hex_dump(const unsigned char *buf, size_t len)
   1926   1.75    atatat {
   1927  1.128     lukem 	unsigned int i;
   1928  1.128     lukem 	int j;
   1929   1.75    atatat 	char line[80], tmp[12];
   1930   1.75    atatat 
   1931   1.75    atatat 	memset(line, ' ', sizeof(line));
   1932   1.75    atatat 	for (i = 0, j = 15; i < len; i++) {
   1933   1.75    atatat 		j = i % 16;
   1934   1.75    atatat 		/* reset line */
   1935   1.75    atatat 		if (j == 0) {
   1936   1.75    atatat 			line[58] = '|';
   1937   1.75    atatat 			line[77] = '|';
   1938   1.75    atatat 			line[78] = 0;
   1939  1.127  pgoyette 			snprintf(tmp, sizeof(tmp), "%07x", i);
   1940   1.75    atatat 			memcpy(&line[0], tmp, 7);
   1941   1.75    atatat 		}
   1942   1.75    atatat 		/* copy out hex version of byte */
   1943   1.75    atatat 		snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
   1944   1.75    atatat 		memcpy(&line[9 + j * 3], tmp, 2);
   1945   1.75    atatat 		/* copy out plain version of byte */
   1946   1.75    atatat 		line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
   1947   1.75    atatat 		/* print a full line and erase it */
   1948   1.75    atatat 		if (j == 15) {
   1949   1.75    atatat 			printf("%s\n", line);
   1950   1.75    atatat 			memset(line, ' ', sizeof(line));
   1951   1.75    atatat 		}
   1952   1.75    atatat 	}
   1953   1.75    atatat 	if (line[0] != ' ')
   1954   1.75    atatat 		printf("%s\n", line);
   1955   1.75    atatat 	printf("%07zu bytes\n", len);
   1956    1.1       cgd }
   1957    1.1       cgd 
   1958    1.1       cgd /*
   1959   1.75    atatat  * ********************************************************************
   1960   1.75    atatat  * functions that handle particular nodes
   1961   1.75    atatat  * ********************************************************************
   1962    1.1       cgd  */
   1963   1.75    atatat /*ARGSUSED*/
   1964   1.14  christos static void
   1965   1.75    atatat printother(HANDLER_ARGS)
   1966    1.1       cgd {
   1967   1.75    atatat 	int rc;
   1968   1.75    atatat 	void *p;
   1969   1.75    atatat 	size_t sz1, sz2;
   1970    1.1       cgd 
   1971   1.75    atatat 	if (!(Aflag || req) || Mflag)
   1972    1.1       cgd 		return;
   1973   1.75    atatat 
   1974   1.75    atatat 	/*
   1975   1.75    atatat 	 * okay...you asked for it, so let's give it a go
   1976   1.75    atatat 	 */
   1977   1.75    atatat 	while (type != CTLTYPE_NODE && (xflag || rflag)) {
   1978   1.75    atatat 		rc = sysctl(name, namelen, NULL, &sz1, NULL, 0);
   1979   1.75    atatat 		if (rc == -1 || sz1 == 0)
   1980   1.75    atatat 			break;
   1981   1.75    atatat 		p = malloc(sz1);
   1982   1.75    atatat 		if (p == NULL)
   1983   1.75    atatat 			break;
   1984   1.75    atatat 		sz2 = sz1;
   1985   1.75    atatat 		rc = sysctl(name, namelen, p, &sz2, NULL, 0);
   1986   1.75    atatat 		if (rc == -1 || sz1 != sz2) {
   1987   1.75    atatat 			free(p);
   1988   1.75    atatat 			break;
   1989   1.75    atatat 		}
   1990   1.75    atatat 		display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
   1991   1.75    atatat 		free(p);
   1992   1.75    atatat 		return;
   1993   1.75    atatat 	}
   1994   1.75    atatat 
   1995   1.75    atatat 	/*
   1996   1.75    atatat 	 * that didn't work...do we have a specific message for this
   1997   1.75    atatat 	 * thing?
   1998   1.75    atatat 	 */
   1999   1.75    atatat 	if (v != NULL) {
   2000   1.92    atatat 		sysctlperror("%s: use '%s' to view this information\n",
   2001   1.92    atatat 			     gsname, (const char *)v);
   2002   1.75    atatat 		return;
   2003   1.75    atatat 	}
   2004   1.75    atatat 
   2005   1.75    atatat 	/*
   2006   1.75    atatat 	 * hmm...i wonder if we have any generic hints?
   2007   1.75    atatat 	 */
   2008   1.75    atatat 	switch (name[0]) {
   2009   1.75    atatat 	case CTL_NET:
   2010   1.92    atatat 		sysctlperror("%s: use 'netstat' to view this information\n",
   2011   1.92    atatat 			     sname);
   2012   1.75    atatat 		break;
   2013   1.75    atatat 	case CTL_DEBUG:
   2014   1.92    atatat 		sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
   2015   1.92    atatat 			     sname);
   2016   1.75    atatat 		break;
   2017   1.75    atatat 	case CTL_DDB:
   2018   1.92    atatat 		sysctlperror("%s: missing 'options DDB' from kernel?\n",
   2019   1.92    atatat 			     sname);
   2020   1.75    atatat 		break;
   2021   1.98    atatat 	case CTL_VENDOR:
   2022   1.98    atatat 		sysctlperror("%s: no vendor extensions installed\n",
   2023   1.98    atatat 			     sname);
   2024   1.98    atatat 		break;
   2025    1.1       cgd 	}
   2026    1.1       cgd }
   2027    1.1       cgd 
   2028   1.75    atatat /*ARGSUSED*/
   2029   1.75    atatat static void
   2030   1.75    atatat kern_clockrate(HANDLER_ARGS)
   2031   1.75    atatat {
   2032   1.75    atatat 	struct clockinfo clkinfo;
   2033   1.75    atatat 	size_t sz;
   2034   1.75    atatat 	int rc;
   2035   1.75    atatat 
   2036   1.75    atatat 	sz = sizeof(clkinfo);
   2037   1.75    atatat 	rc = sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
   2038   1.75    atatat 	if (rc == -1) {
   2039   1.75    atatat 		sysctlerror(1);
   2040   1.75    atatat 		return;
   2041   1.75    atatat 	}
   2042   1.75    atatat 	if (sz != sizeof(clkinfo))
   2043   1.75    atatat 		errx(1, "%s: !returned size wrong!", sname);
   2044   1.74  jonathan 
   2045   1.79    atatat 	if (xflag || rflag) {
   2046   1.75    atatat 		display_struct(pnode, sname, &clkinfo, sz,
   2047   1.75    atatat 			       DISPLAY_VALUE);
   2048   1.79    atatat 		return;
   2049   1.79    atatat 	}
   2050   1.75    atatat 	else if (!nflag)
   2051   1.75    atatat 		printf("%s: ", sname);
   2052   1.75    atatat 	printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
   2053   1.75    atatat 	       clkinfo.tick, clkinfo.tickadj,
   2054   1.75    atatat 	       clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
   2055   1.75    atatat }
   2056    1.1       cgd 
   2057   1.75    atatat /*ARGSUSED*/
   2058   1.75    atatat static void
   2059   1.75    atatat kern_boottime(HANDLER_ARGS)
   2060    1.1       cgd {
   2061   1.75    atatat 	struct timeval timeval;
   2062   1.75    atatat 	time_t boottime;
   2063   1.75    atatat 	size_t sz;
   2064   1.75    atatat 	int rc;
   2065   1.75    atatat 
   2066   1.75    atatat 	sz = sizeof(timeval);
   2067   1.75    atatat 	rc = sysctl(name, namelen, &timeval, &sz, NULL, 0);
   2068   1.75    atatat 	if (rc == -1) {
   2069   1.75    atatat 		sysctlerror(1);
   2070   1.75    atatat 		return;
   2071   1.75    atatat 	}
   2072   1.75    atatat 	if (sz != sizeof(timeval))
   2073   1.75    atatat 		errx(1, "%s: !returned size wrong!", sname);
   2074    1.1       cgd 
   2075   1.75    atatat 	boottime = timeval.tv_sec;
   2076   1.75    atatat 	if (xflag || rflag)
   2077   1.75    atatat 		display_struct(pnode, sname, &timeval, sz,
   2078   1.75    atatat 			       DISPLAY_VALUE);
   2079   1.75    atatat 	else if (!nflag)
   2080   1.75    atatat 		/* ctime() provides the \n */
   2081   1.75    atatat 		printf("%s%s%s", sname, eq, ctime(&boottime));
   2082   1.75    atatat 	else if (nflag == 1)
   2083   1.75    atatat 		printf("%ld\n", (long)boottime);
   2084   1.75    atatat 	else
   2085   1.75    atatat 		printf("%ld.%06ld\n", (long)timeval.tv_sec,
   2086   1.75    atatat 		       (long)timeval.tv_usec);
   2087   1.75    atatat }
   2088   1.20    itojun 
   2089   1.75    atatat /*ARGSUSED*/
   2090   1.75    atatat static void
   2091   1.75    atatat kern_consdev(HANDLER_ARGS)
   2092   1.20    itojun {
   2093   1.75    atatat 	dev_t cons;
   2094   1.75    atatat 	size_t sz;
   2095   1.75    atatat 	int rc;
   2096   1.75    atatat 
   2097   1.75    atatat 	sz = sizeof(cons);
   2098   1.75    atatat 	rc = sysctl(name, namelen, &cons, &sz, NULL, 0);
   2099   1.75    atatat 	if (rc == -1) {
   2100   1.75    atatat 		sysctlerror(1);
   2101   1.75    atatat 		return;
   2102   1.75    atatat 	}
   2103   1.75    atatat 	if (sz != sizeof(cons))
   2104   1.75    atatat 		errx(1, "%s: !returned size wrong!", sname);
   2105   1.20    itojun 
   2106   1.75    atatat 	if (xflag || rflag)
   2107   1.75    atatat 		display_struct(pnode, sname, &cons, sz,
   2108   1.75    atatat 			       DISPLAY_VALUE);
   2109  1.101  christos 	else {
   2110  1.101  christos 		if (!nflag)
   2111  1.101  christos 			printf("%s%s", sname, eq);
   2112  1.102  christos 		if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL)
   2113  1.102  christos 			printf("%s\n", sname);
   2114  1.101  christos 		else
   2115  1.125  christos 			printf("0x%llx\n", (unsigned long long)cons);
   2116  1.101  christos 	}
   2117   1.75    atatat }
   2118   1.17   thorpej 
   2119   1.75    atatat /*ARGSUSED*/
   2120   1.75    atatat static void
   2121   1.75    atatat kern_cp_time(HANDLER_ARGS)
   2122   1.17   thorpej {
   2123   1.80    atatat 	u_int64_t *cp_time;
   2124   1.80    atatat 	size_t sz, osz;
   2125   1.80    atatat 	int rc, i, n;
   2126   1.80    atatat 	char s[sizeof("kern.cp_time.nnnnnn")];
   2127   1.80    atatat 	const char *tname;
   2128   1.80    atatat 
   2129   1.80    atatat 	/*
   2130   1.80    atatat 	 * three things to do here.
   2131   1.80    atatat 	 * case 1: get sum (no Aflag and namelen == 2)
   2132   1.80    atatat 	 * case 2: get specific processor (namelen == 3)
   2133   1.80    atatat 	 * case 3: get all processors (Aflag and namelen == 2)
   2134   1.80    atatat 	 */
   2135   1.80    atatat 
   2136   1.80    atatat 	if (namelen == 2 && Aflag) {
   2137   1.80    atatat 		sz = sizeof(n);
   2138   1.80    atatat 		rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
   2139   1.80    atatat 		if (rc != 0)
   2140   1.80    atatat 			return; /* XXX print an error, eh? */
   2141   1.81    atatat 		n++; /* Add on space for the sum. */
   2142   1.80    atatat 		sz = n * sizeof(u_int64_t) * CPUSTATES;
   2143   1.80    atatat 	}
   2144   1.80    atatat 	else {
   2145   1.81    atatat 		n = -1; /* Just print one data set. */
   2146   1.80    atatat 		sz = sizeof(u_int64_t) * CPUSTATES;
   2147   1.80    atatat 	}
   2148   1.80    atatat 
   2149   1.80    atatat 	cp_time = malloc(sz);
   2150   1.80    atatat 	if (cp_time == NULL) {
   2151   1.80    atatat 		sysctlerror(1);
   2152   1.80    atatat 		return;
   2153   1.80    atatat 	}
   2154   1.81    atatat 
   2155   1.80    atatat 	osz = sz;
   2156   1.81    atatat 	rc = sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
   2157   1.81    atatat 		    NULL, 0);
   2158   1.75    atatat 
   2159   1.75    atatat 	if (rc == -1) {
   2160   1.75    atatat 		sysctlerror(1);
   2161   1.80    atatat 		free(cp_time);
   2162   1.75    atatat 		return;
   2163   1.75    atatat 	}
   2164   1.81    atatat 
   2165   1.81    atatat 	/*
   2166   1.81    atatat 	 * Check, but account for space we'll occupy with the sum.
   2167   1.81    atatat 	 */
   2168   1.81    atatat 	if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
   2169   1.75    atatat 		errx(1, "%s: !returned size wrong!", sname);
   2170   1.17   thorpej 
   2171   1.81    atatat 	/*
   2172   1.81    atatat 	 * Compute the actual sum.  Two calls would be easier (we
   2173   1.81    atatat 	 * could just call ourselves recursively above), but the
   2174   1.81    atatat 	 * numbers wouldn't add up.
   2175   1.81    atatat 	 */
   2176   1.81    atatat 	if (n != -1) {
   2177   1.81    atatat 		memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
   2178   1.81    atatat 		for (i = 1; i < n; i++) {
   2179   1.81    atatat 			cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
   2180   1.81    atatat                         cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
   2181   1.81    atatat                         cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
   2182   1.81    atatat                         cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
   2183   1.81    atatat                         cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
   2184   1.81    atatat 		}
   2185   1.81    atatat 	}
   2186   1.81    atatat 
   2187   1.80    atatat 	tname = sname;
   2188   1.80    atatat 	for (i = 0; n == -1 || i < n; i++) {
   2189   1.81    atatat 		if (i > 0) {
   2190   1.81    atatat 			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
   2191   1.81    atatat 				       i - 1);
   2192   1.80    atatat 			tname = s;
   2193   1.80    atatat 		}
   2194   1.80    atatat 		if (xflag || rflag)
   2195   1.80    atatat 			display_struct(pnode, tname, cp_time + (i * CPUSTATES),
   2196   1.80    atatat 				       sizeof(u_int64_t) * CPUSTATES,
   2197   1.80    atatat 				       DISPLAY_VALUE);
   2198   1.80    atatat 		else {
   2199   1.80    atatat 			if (!nflag)
   2200   1.80    atatat 				printf("%s: ", tname);
   2201   1.80    atatat 			printf("user = %" PRIu64
   2202   1.80    atatat 			       ", nice = %" PRIu64
   2203   1.80    atatat 			       ", sys = %" PRIu64
   2204   1.80    atatat 			       ", intr = %" PRIu64
   2205   1.80    atatat 			       ", idle = %" PRIu64
   2206   1.80    atatat 			       "\n",
   2207   1.80    atatat 			       cp_time[i * CPUSTATES + CP_USER],
   2208   1.80    atatat 			       cp_time[i * CPUSTATES + CP_NICE],
   2209   1.80    atatat 			       cp_time[i * CPUSTATES + CP_SYS],
   2210   1.80    atatat 			       cp_time[i * CPUSTATES + CP_INTR],
   2211   1.80    atatat 			       cp_time[i * CPUSTATES + CP_IDLE]);
   2212   1.80    atatat 		}
   2213   1.81    atatat 		/*
   2214   1.81    atatat 		 * Just printing the one node.
   2215   1.81    atatat 		 */
   2216   1.80    atatat 		if (n == -1)
   2217   1.80    atatat 			break;
   2218   1.79    atatat 	}
   2219   1.80    atatat 
   2220   1.80    atatat 	free(cp_time);
   2221   1.17   thorpej }
   2222   1.17   thorpej 
   2223   1.75    atatat /*ARGSUSED*/
   2224   1.75    atatat static void
   2225  1.118  christos kern_drivers(HANDLER_ARGS)
   2226  1.118  christos {
   2227  1.118  christos 	struct kinfo_drivers *kd;
   2228  1.118  christos 	size_t sz, i;
   2229  1.118  christos 	int rc;
   2230  1.118  christos 	const char *comma;
   2231  1.118  christos 
   2232  1.118  christos 	rc = sysctl(name, namelen, NULL, &sz, NULL, 0);
   2233  1.118  christos 	if (rc == -1) {
   2234  1.118  christos 		sysctlerror(1);
   2235  1.118  christos 		return;
   2236  1.118  christos 	}
   2237  1.118  christos 
   2238  1.118  christos 	if (sz % sizeof(*kd))
   2239  1.118  christos 		err(1, "bad size %zu for kern.drivers", sz);
   2240  1.118  christos 
   2241  1.118  christos 	kd = malloc(sz);
   2242  1.118  christos 	if (kd == NULL) {
   2243  1.118  christos 		sysctlerror(1);
   2244  1.118  christos 		return;
   2245  1.118  christos 	}
   2246  1.118  christos 
   2247  1.118  christos 	rc = sysctl(name, namelen, kd, &sz, NULL, 0);
   2248  1.118  christos 	if (rc == -1) {
   2249  1.118  christos 		sysctlerror(1);
   2250  1.118  christos 		return;
   2251  1.118  christos 	}
   2252  1.118  christos 
   2253  1.118  christos 	comma = "";
   2254  1.119  christos 	if (!nflag)
   2255  1.119  christos 		printf("%s%s", sname, eq);
   2256  1.118  christos 	for (i = 0, sz /= sizeof(*kd); i < sz; i++) {
   2257  1.118  christos 		(void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor,
   2258  1.118  christos 		    kd[i].d_bmajor, kd[i].d_name);
   2259  1.118  christos 		comma = ", ";
   2260  1.118  christos 	}
   2261  1.118  christos 	(void)printf("\n");
   2262  1.118  christos 	free(kd);
   2263  1.118  christos }
   2264  1.118  christos 
   2265  1.118  christos /*ARGSUSED*/
   2266  1.118  christos static void
   2267  1.103  christos kern_cp_id(HANDLER_ARGS)
   2268  1.103  christos {
   2269  1.103  christos 	u_int64_t *cp_id;
   2270  1.103  christos 	size_t sz, osz;
   2271  1.103  christos 	int rc, i, n;
   2272  1.103  christos 	char s[sizeof("kern.cp_id.nnnnnn")];
   2273  1.103  christos 	const char *tname;
   2274  1.103  christos 	struct sysctlnode node = *pnode;
   2275  1.103  christos 
   2276  1.103  christos 	/*
   2277  1.103  christos 	 * three things to do here.
   2278  1.103  christos 	 * case 1: print a specific cpu id (namelen == 3)
   2279  1.103  christos 	 * case 2: print all cpu ids separately (Aflag set)
   2280  1.103  christos 	 * case 3: print all cpu ids on one line
   2281  1.103  christos 	 */
   2282  1.103  christos 
   2283  1.103  christos 	if (namelen == 2) {
   2284  1.103  christos 		sz = sizeof(n);
   2285  1.103  christos 		rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
   2286  1.103  christos 		if (rc != 0)
   2287  1.103  christos 			return; /* XXX print an error, eh? */
   2288  1.103  christos 		sz = n * sizeof(u_int64_t);
   2289  1.103  christos 	}
   2290  1.103  christos 	else {
   2291  1.103  christos 		n = -1; /* Just print one cpu id. */
   2292  1.103  christos 		sz = sizeof(u_int64_t);
   2293  1.103  christos 	}
   2294  1.103  christos 
   2295  1.103  christos 	cp_id = malloc(sz);
   2296  1.103  christos 	if (cp_id == NULL) {
   2297  1.103  christos 		sysctlerror(1);
   2298  1.103  christos 		return;
   2299  1.103  christos 	}
   2300  1.103  christos 
   2301  1.103  christos 	osz = sz;
   2302  1.103  christos 	rc = sysctl(name, namelen, cp_id, &osz, NULL, 0);
   2303  1.103  christos 	if (rc == -1) {
   2304  1.103  christos 		sysctlerror(1);
   2305  1.103  christos 		free(cp_id);
   2306  1.103  christos 		return;
   2307  1.103  christos 	}
   2308  1.103  christos 
   2309  1.103  christos 	/*
   2310  1.103  christos 	 * Check that we got back what we asked for.
   2311  1.103  christos 	 */
   2312  1.103  christos 	if (osz != sz)
   2313  1.103  christos 		errx(1, "%s: !returned size wrong!", sname);
   2314  1.103  christos 
   2315  1.103  christos 	/* pretend for output purposes */
   2316  1.103  christos 	node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) |
   2317  1.103  christos 		SYSCTL_TYPE(CTLTYPE_QUAD);
   2318  1.103  christos 
   2319  1.103  christos 	tname = sname;
   2320  1.103  christos 	if (namelen == 3)
   2321  1.103  christos 		display_number(&node, tname, cp_id,
   2322  1.103  christos 			       sizeof(u_int64_t),
   2323  1.103  christos 			       DISPLAY_VALUE);
   2324  1.103  christos 	else if (Aflag) {
   2325  1.103  christos 		for (i = 0; i < n; i++)
   2326  1.103  christos 			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i);
   2327  1.103  christos 			tname = s;
   2328  1.103  christos 			display_number(&node, tname, &cp_id[i],
   2329  1.103  christos 				       sizeof(u_int64_t),
   2330  1.103  christos 				       DISPLAY_VALUE);
   2331  1.103  christos 	}
   2332  1.103  christos 	else {
   2333  1.103  christos 		if (xflag || rflag)
   2334  1.103  christos 			display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE);
   2335  1.103  christos 		else {
   2336  1.103  christos 			if (!nflag)
   2337  1.103  christos 				printf("%s: ", tname);
   2338  1.103  christos 			for (i = 0; i < n; i++) {
   2339  1.103  christos 				if (i)
   2340  1.103  christos 					printf(", ");
   2341  1.103  christos 				printf("%d = %" PRIu64, i, cp_id[i]);
   2342  1.103  christos 			}
   2343  1.103  christos 			printf("\n");
   2344  1.103  christos 		}
   2345  1.103  christos 	}
   2346  1.103  christos 
   2347  1.103  christos 	free(cp_id);
   2348  1.103  christos }
   2349  1.103  christos 
   2350  1.103  christos /*ARGSUSED*/
   2351  1.103  christos static void
   2352   1.75    atatat vm_loadavg(HANDLER_ARGS)
   2353   1.22    bouyer {
   2354   1.75    atatat 	struct loadavg loadavg;
   2355   1.75    atatat 	size_t sz;
   2356   1.75    atatat 	int rc;
   2357   1.75    atatat 
   2358   1.75    atatat 	sz = sizeof(loadavg);
   2359   1.75    atatat 	rc = sysctl(name, namelen, &loadavg, &sz, NULL, 0);
   2360   1.75    atatat 	if (rc == -1) {
   2361   1.75    atatat 		sysctlerror(1);
   2362   1.75    atatat 		return;
   2363   1.75    atatat 	}
   2364   1.75    atatat 	if (sz != sizeof(loadavg))
   2365   1.75    atatat 		errx(1, "%s: !returned size wrong!", sname);
   2366   1.75    atatat 
   2367   1.79    atatat 	if (xflag || rflag) {
   2368   1.75    atatat 		display_struct(pnode, sname, &loadavg, sz,
   2369   1.75    atatat 			       DISPLAY_VALUE);
   2370   1.79    atatat 		return;
   2371   1.79    atatat 	}
   2372   1.79    atatat 	if (!nflag)
   2373   1.75    atatat 		printf("%s: ", sname);
   2374   1.75    atatat 	printf("%.2f %.2f %.2f\n",
   2375   1.75    atatat 	       (double) loadavg.ldavg[0] / loadavg.fscale,
   2376   1.75    atatat 	       (double) loadavg.ldavg[1] / loadavg.fscale,
   2377   1.75    atatat 	       (double) loadavg.ldavg[2] / loadavg.fscale);
   2378    1.1       cgd }
   2379    1.1       cgd 
   2380   1.75    atatat /*ARGSUSED*/
   2381   1.75    atatat static void
   2382   1.75    atatat proc_limit(HANDLER_ARGS)
   2383    1.1       cgd {
   2384   1.75    atatat 	u_quad_t olim, *newp, nlim;
   2385   1.75    atatat 	size_t osz, nsz;
   2386   1.75    atatat 	char *t;
   2387   1.75    atatat 	int rc;
   2388   1.75    atatat 
   2389   1.92    atatat 	if (fn)
   2390   1.92    atatat 		trim_whitespace(value, 3);
   2391   1.92    atatat 
   2392   1.75    atatat 	osz = sizeof(olim);
   2393   1.75    atatat 	if (value != NULL) {
   2394   1.75    atatat 		nsz = sizeof(nlim);
   2395   1.75    atatat 		newp = &nlim;
   2396   1.75    atatat 		if (strcmp(value, "unlimited") == 0)
   2397   1.75    atatat 			nlim = RLIM_INFINITY;
   2398   1.75    atatat 		else {
   2399   1.75    atatat 			errno = 0;
   2400   1.75    atatat 			nlim = strtouq(value, &t, 0);
   2401   1.94    atatat 			if (t == value || *t != '\0' || errno != 0) {
   2402   1.92    atatat 				sysctlperror("%s: '%s' is not a valid limit\n",
   2403   1.92    atatat 					     sname, value);
   2404   1.92    atatat 				EXIT(1);
   2405   1.75    atatat 			}
   2406   1.75    atatat 		}
   2407   1.75    atatat 	}
   2408   1.75    atatat 	else {
   2409   1.75    atatat 		nsz = 0;
   2410   1.75    atatat 		newp = NULL;
   2411   1.75    atatat 	}
   2412   1.75    atatat 
   2413   1.75    atatat 	rc = sysctl(name, namelen, &olim, &osz, newp, nsz);
   2414   1.75    atatat 	if (rc == -1) {
   2415   1.75    atatat 		sysctlerror(newp == NULL);
   2416   1.75    atatat 		return;
   2417   1.75    atatat 	}
   2418   1.75    atatat 
   2419   1.75    atatat 	if (newp && qflag)
   2420   1.75    atatat 		return;
   2421   1.75    atatat 
   2422   1.75    atatat 	if (rflag || xflag || olim != RLIM_INFINITY)
   2423   1.75    atatat 		display_number(pnode, sname, &olim, sizeof(olim),
   2424   1.75    atatat 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
   2425   1.75    atatat 	else
   2426   1.75    atatat 		display_string(pnode, sname, "unlimited", 10,
   2427   1.75    atatat 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
   2428    1.1       cgd 
   2429   1.75    atatat 	if (newp) {
   2430   1.75    atatat 		if (rflag || xflag || nlim != RLIM_INFINITY)
   2431   1.75    atatat 			display_number(pnode, sname, &nlim, sizeof(nlim),
   2432   1.75    atatat 				       DISPLAY_NEW);
   2433   1.75    atatat 		else
   2434   1.75    atatat 			display_string(pnode, sname, "unlimited", 10,
   2435   1.75    atatat 				       DISPLAY_NEW);
   2436    1.1       cgd 	}
   2437    1.1       cgd }
   2438    1.1       cgd 
   2439   1.75    atatat #ifdef CPU_DISKINFO
   2440   1.75    atatat /*ARGSUSED*/
   2441   1.14  christos static void
   2442   1.75    atatat machdep_diskinfo(HANDLER_ARGS)
   2443    1.1       cgd {
   2444   1.75    atatat 	struct disklist *dl;
   2445   1.75    atatat 	struct biosdisk_info *bi;
   2446   1.75    atatat 	struct nativedisk_info *ni;
   2447   1.75    atatat 	int rc;
   2448   1.75    atatat 	size_t sz;
   2449   1.75    atatat 	uint i, b, lim;
   2450   1.75    atatat 
   2451   1.75    atatat 	rc = sysctl(name, namelen, NULL, &sz, NULL, 0);
   2452   1.75    atatat 	if (rc == -1) {
   2453   1.75    atatat 		sysctlerror(1);
   2454   1.75    atatat 		return;
   2455   1.75    atatat 	}
   2456   1.75    atatat 	dl = malloc(sz);
   2457   1.75    atatat 	if (dl == NULL) {
   2458   1.75    atatat 		sysctlerror(1);
   2459   1.75    atatat 		return;
   2460   1.75    atatat 	}
   2461   1.75    atatat 	rc = sysctl(name, namelen, dl, &sz, NULL, 0);
   2462   1.75    atatat 	if (rc == -1) {
   2463   1.75    atatat 		sysctlerror(1);
   2464   1.75    atatat 		return;
   2465   1.75    atatat 	}
   2466   1.45       cgd 
   2467   1.75    atatat 	if (!nflag)
   2468   1.75    atatat 		printf("%s: ", sname);
   2469   1.75    atatat 	lim = dl->dl_nbiosdisks;
   2470   1.75    atatat 	if (lim > MAX_BIOSDISKS)
   2471   1.75    atatat 		lim = MAX_BIOSDISKS;
   2472   1.75    atatat 	for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
   2473   1.75    atatat 		printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
   2474   1.75    atatat 		       bi->bi_dev, bi->bi_lbasecs,
   2475   1.75    atatat 		       bi->bi_cyl, bi->bi_head, bi->bi_sec,
   2476   1.75    atatat 		       bi->bi_flags);
   2477   1.75    atatat 	lim = dl->dl_nnativedisks;
   2478   1.75    atatat 	ni = dl->dl_nativedisks;
   2479   1.75    atatat 	bi = dl->dl_biosdisks;
   2480   1.75    atatat 	/* LINTED -- pointer casts are tedious */
   2481   1.75    atatat 	if ((char *)&ni[lim] != (char *)dl + sz) {
   2482   1.92    atatat 		sysctlperror("%s: size mismatch\n", gsname);
   2483   1.75    atatat 		return;
   2484   1.75    atatat 	}
   2485   1.75    atatat 	for (i = 0; i < lim; ni++, i++) {
   2486   1.75    atatat 		char t = ':';
   2487   1.75    atatat 		printf(" %.*s", (int)sizeof ni->ni_devname,
   2488   1.75    atatat 		       ni->ni_devname);
   2489  1.128     lukem 		for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++)
   2490   1.75    atatat 			printf("%c%x", t,
   2491   1.75    atatat 			       bi[ni->ni_biosmatches[b]].bi_dev);
   2492   1.75    atatat 	}
   2493   1.75    atatat 	printf("\n");
   2494  1.126     njoly 	free(dl);
   2495    1.1       cgd }
   2496   1.75    atatat #endif /* CPU_DISKINFO */
   2497  1.108      elad 
   2498  1.108      elad /*ARGSUSED*/
   2499  1.108      elad static void
   2500  1.108      elad mode_bits(HANDLER_ARGS)
   2501  1.108      elad {
   2502  1.122      elad 	char buf[12], outbuf[100];
   2503  1.108      elad 	int o, m, *newp, rc;
   2504  1.108      elad 	size_t osz, nsz;
   2505  1.108      elad 	mode_t om, mm;
   2506  1.108      elad 
   2507  1.108      elad 	if (fn)
   2508  1.108      elad 		trim_whitespace(value, 3);
   2509  1.108      elad 
   2510  1.108      elad 	newp = NULL;
   2511  1.108      elad 	osz = sizeof(o);
   2512  1.108      elad 	if (value != NULL) {
   2513  1.108      elad 		void *foo;
   2514  1.108      elad 		int tt;
   2515  1.108      elad 		size_t ttsz = sizeof(tt);
   2516  1.108      elad 		mode_t old_umask;
   2517  1.108      elad 
   2518  1.108      elad 		nsz = sizeof(m);
   2519  1.108      elad 		newp = &m;
   2520  1.108      elad 		errno = 0;
   2521  1.108      elad 		rc = sysctl(name, namelen, &tt, &ttsz, NULL, 0);
   2522  1.108      elad 		if (rc == -1) {
   2523  1.108      elad 			sysctlperror("%s: failed query\n", sname);
   2524  1.108      elad 			return;
   2525  1.108      elad 		}
   2526  1.108      elad 
   2527  1.108      elad 		old_umask = umask(0);
   2528  1.108      elad 		foo = setmode(value);
   2529  1.108      elad 		umask(old_umask);
   2530  1.108      elad 		if (foo == NULL) {
   2531  1.108      elad 			sysctlperror("%s: '%s' is an invalid mode\n", sname,
   2532  1.108      elad 				     value);
   2533  1.108      elad 			EXIT(1);
   2534  1.108      elad 		}
   2535  1.108      elad 		old_umask = umask(0);
   2536  1.108      elad 		m = getmode(foo, (mode_t)tt);
   2537  1.108      elad 		umask(old_umask);
   2538  1.108      elad 		if (errno) {
   2539  1.108      elad 			sysctlperror("%s: '%s' is an invalid mode\n", sname,
   2540  1.108      elad 				     value);
   2541  1.108      elad 			EXIT(1);
   2542  1.108      elad 		}
   2543  1.108      elad 	}
   2544  1.108      elad 	else {
   2545  1.108      elad 		nsz = 0;
   2546  1.108      elad 		newp = NULL;
   2547  1.108      elad 	}
   2548  1.108      elad 
   2549  1.108      elad 	rc = sysctl(name, namelen, &o, &osz, newp, nsz);
   2550  1.108      elad 	if (rc == -1) {
   2551  1.108      elad 		sysctlerror(newp == NULL);
   2552  1.108      elad 		return;
   2553  1.108      elad 	}
   2554  1.108      elad 
   2555  1.108      elad 	if (newp && qflag)
   2556  1.108      elad 		return;
   2557  1.108      elad 
   2558  1.108      elad 	om = (mode_t)o;
   2559  1.108      elad 	mm = (mode_t)m;
   2560  1.108      elad 
   2561  1.108      elad 	if (rflag || xflag)
   2562  1.108      elad 		display_number(pnode, sname, &o, sizeof(o),
   2563  1.108      elad 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
   2564  1.108      elad 	else {
   2565  1.108      elad 		memset(buf, 0, sizeof(buf));
   2566  1.108      elad 		strmode(om, buf);
   2567  1.108      elad 		rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1);
   2568  1.108      elad 		display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE);
   2569  1.108      elad 	}
   2570  1.108      elad 
   2571  1.108      elad 	if (newp) {
   2572  1.108      elad 		if (rflag || xflag)
   2573  1.108      elad 			display_number(pnode, sname, &m, sizeof(m),
   2574  1.108      elad 				       DISPLAY_NEW);
   2575  1.108      elad 		else {
   2576  1.108      elad 			memset(buf, 0, sizeof(buf));
   2577  1.108      elad 			strmode(mm, buf);
   2578  1.108      elad 			rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1);
   2579  1.108      elad 			display_string(pnode, sname, outbuf, rc, DISPLAY_NEW);
   2580  1.108      elad 		}
   2581  1.108      elad 	}
   2582  1.108      elad }
   2583