sysctl.c revision 1.55
1/*	$OpenBSD: sysctl.c,v 1.55 2000/12/22 22:47:04 deraadt Exp $	*/
2/*	$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $	*/
3
4/*
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46#else
47static char *rcsid = "$OpenBSD: sysctl.c,v 1.55 2000/12/22 22:47:04 deraadt Exp $";
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/gmon.h>
53#include <sys/mount.h>
54#include <sys/stat.h>
55#include <sys/sysctl.h>
56#include <sys/socket.h>
57#include <vm/vm_param.h>
58#include <machine/cpu.h>
59#include <net/route.h>
60
61#include <netinet/in.h>
62#include <netinet/in_systm.h>
63#include <netinet/ip.h>
64#include <netinet/in_pcb.h>
65#include <netinet/ip_icmp.h>
66#include <netinet/ip_ipip.h>
67#include <netinet/ip_ether.h>
68#include <netinet/ip_ah.h>
69#include <netinet/ip_esp.h>
70#include <netinet/icmp_var.h>
71#include <netinet/ip_var.h>
72#include <netinet/udp.h>
73#include <netinet/udp_var.h>
74#include <netinet/tcp.h>
75#include <netinet/tcp_timer.h>
76#include <netinet/tcp_var.h>
77#include <netinet/ip_gre.h>
78
79#ifdef INET6
80#include <netinet/ip6.h>
81#include <netinet/icmp6.h>
82#include <netinet6/ip6_var.h>
83#include <netinet6/pim6_var.h>
84#endif
85
86#ifdef UVM
87#include <uvm/uvm_swap_encrypt.h>
88#endif
89
90#include <ufs/ufs/quota.h>
91#include <ufs/ufs/inode.h>
92#include <ufs/ffs/fs.h>
93#include <ufs/ffs/ffs_extern.h>
94
95#include <nfs/rpcv2.h>
96#include <nfs/nfsproto.h>
97#include <nfs/nfs.h>
98
99#include <netipx/ipx.h>
100#include <netipx/ipx_var.h>
101#include <netipx/spx_var.h>
102#include <ddb/db_var.h>
103#include <dev/rndvar.h>
104
105#include <err.h>
106#include <errno.h>
107#include <stdio.h>
108#include <stdlib.h>
109#include <string.h>
110#include <ctype.h>
111
112#ifdef CPU_BIOS
113#include <machine/biosvar.h>
114#endif
115
116struct ctlname topname[] = CTL_NAMES;
117struct ctlname kernname[] = CTL_KERN_NAMES;
118struct ctlname vmname[] = CTL_VM_NAMES;
119struct ctlname fsname[] = CTL_FS_NAMES;
120struct ctlname netname[] = CTL_NET_NAMES;
121struct ctlname hwname[] = CTL_HW_NAMES;
122struct ctlname username[] = CTL_USER_NAMES;
123struct ctlname debugname[CTL_DEBUG_MAXID];
124struct ctlname *vfsname;
125#ifdef CTL_MACHDEP_NAMES
126struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
127#endif
128struct ctlname ddbname[] = CTL_DDB_NAMES;
129char names[BUFSIZ];
130int lastused;
131
132struct list {
133	struct	ctlname *list;
134	int	size;
135};
136struct list toplist = { topname, CTL_MAXID };
137struct list secondlevel[] = {
138	{ 0, 0 },			/* CTL_UNSPEC */
139	{ kernname, KERN_MAXID },	/* CTL_KERN */
140	{ vmname, VM_MAXID },		/* CTL_VM */
141	{ fsname, FS_MAXID },		/* CTL_FS */
142	{ netname, NET_MAXID },		/* CTL_NET */
143	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
144	{ hwname, HW_MAXID },		/* CTL_HW */
145#ifdef CTL_MACHDEP_NAMES
146	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
147#else
148	{ 0, 0 },			/* CTL_MACHDEP */
149#endif
150	{ username, USER_MAXID },	/* CTL_USER_NAMES */
151	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
152	{ 0, 0 },			/* CTL_VFS */
153};
154
155int	Aflag, aflag, nflag, wflag;
156
157/*
158 * Variables requiring special processing.
159 */
160#define	CLOCK		0x00000001
161#define	BOOTTIME	0x00000002
162#define	CHRDEV		0x00000004
163#define	BLKDEV		0x00000008
164#define	RNDSTATS	0x00000010
165#define	BADDYNAMIC	0x00000020
166#define	BIOSGEO		0x00000040
167#define	BIOSDEV		0x00000080
168#define	MAJ2DEV		0x00000100
169#define	UNSIGNED	0x00000200
170
171/* prototypes */
172void debuginit __P((void));
173void listall __P((char *, struct list *));
174void parse __P((char *, int));
175void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
176void usage __P((void));
177int findname __P((char *, char *, char **, struct list *));
178int sysctl_inet __P((char *, char **, int *, int, int *));
179#ifdef INET6
180int sysctl_inet6 __P((char *, char **, int *, int, int *));
181#endif
182int sysctl_ipx __P((char *, char **, int *, int, int *));
183int sysctl_fs __P((char *, char **, int *, int, int *));
184static int sysctl_vfs __P((char *, char **, int[], int, int *));
185static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
186int sysctl_bios __P((char *, char **, int *, int, int *));
187int sysctl_swpenc __P((char *, char **, int *, int, int *));
188void vfsinit __P((void));
189
190int
191main(argc, argv)
192	int argc;
193	char *argv[];
194{
195	int ch, lvl1;
196
197	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
198		switch (ch) {
199
200		case 'A':
201			Aflag = 1;
202			break;
203
204		case 'a':
205			aflag = 1;
206			break;
207
208		case 'n':
209			nflag = 1;
210			break;
211
212		case 'w':
213			wflag = 1;
214			break;
215
216		default:
217			usage();
218		}
219	}
220	argc -= optind;
221	argv += optind;
222
223	if (argc == 0 && (Aflag || aflag)) {
224		debuginit();
225		vfsinit();
226		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
227			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
228		exit(0);
229	}
230	if (argc == 0)
231		usage();
232	for (; *argv != NULL; ++argv)
233		parse(*argv, 1);
234	exit(0);
235}
236
237/*
238 * List all variables known to the system.
239 */
240void
241listall(prefix, lp)
242	char *prefix;
243	struct list *lp;
244{
245	int lvl2;
246	char *cp, name[BUFSIZ];
247
248	if (lp->list == NULL)
249		return;
250	(void)strlcpy(name, prefix, BUFSIZ);
251	cp = &name[strlen(name)];
252	*cp++ = '.';
253	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
254		if (lp->list[lvl2].ctl_name == NULL)
255			continue;
256		(void)strcpy(cp, lp->list[lvl2].ctl_name);
257		parse(name, Aflag);
258	}
259}
260
261/*
262 * Parse a name into a MIB entry.
263 * Lookup and print out the MIB entry if it exists.
264 * Set a new value if requested.
265 */
266void
267parse(string, flags)
268	char *string;
269	int flags;
270{
271	int indx, type, state, intval, len;
272	size_t size, newsize = 0;
273	int special = 0;
274	void *newval = 0;
275	quad_t quadval;
276	struct list *lp;
277	int mib[CTL_MAXNAME];
278	char *cp, *bufp, buf[BUFSIZ];
279
280	(void)strlcpy(buf, string, sizeof(buf));
281	bufp = buf;
282	if ((cp = strchr(string, '=')) != NULL) {
283		if (!wflag)
284			errx(2, "must specify -w to set variables");
285		*strchr(buf, '=') = '\0';
286		*cp++ = '\0';
287		while (isspace(*cp))
288			cp++;
289		newval = cp;
290		newsize = strlen(cp);
291	}
292	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
293		return;
294	mib[0] = indx;
295	if (indx == CTL_VFS)
296		vfsinit();
297	if (indx == CTL_DEBUG)
298		debuginit();
299	lp = &secondlevel[indx];
300	if (lp->list == 0) {
301		warnx("%s: class is not implemented", topname[indx].ctl_name);
302		return;
303	}
304	if (bufp == NULL) {
305		listall(topname[indx].ctl_name, lp);
306		return;
307	}
308	if ((indx = findname(string, "second", &bufp, lp)) == -1)
309		return;
310	mib[1] = indx;
311	type = lp->list[indx].ctl_type;
312	len = 2;
313	switch (mib[0]) {
314
315	case CTL_KERN:
316		switch (mib[1]) {
317		case KERN_PROF:
318			mib[2] = GPROF_STATE;
319			size = sizeof(state);
320			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
321				if (flags == 0)
322					return;
323				if (!nflag)
324					(void)printf("%s: ", string);
325				(void)puts("kernel is not compiled for profiling");
326				return;
327			}
328			if (!nflag)
329				(void)printf("%s = %s\n", string,
330				    state == GMON_PROF_OFF ? "off" : "running");
331			return;
332		case KERN_VNODE:
333		case KERN_FILE:
334			if (flags == 0)
335				return;
336			warnx("use pstat to view %s information", string);
337			return;
338		case KERN_PROC:
339			if (flags == 0)
340				return;
341			warnx("use ps to view %s information", string);
342			return;
343		case KERN_NTPTIME:
344			if (flags == 0)
345				return;
346			warnx("use xntpdc to view %s information", string);
347			return;
348		case KERN_CLOCKRATE:
349			special |= CLOCK;
350			break;
351		case KERN_BOOTTIME:
352			special |= BOOTTIME;
353			break;
354		case KERN_RND:
355			special |= RNDSTATS;
356			break;
357		case KERN_HOSTID:
358		case KERN_ARND:
359			special |= UNSIGNED;
360			break;
361		}
362		break;
363
364	case CTL_HW:
365		break;
366
367	case CTL_VM:
368		if (mib[1] == VM_LOADAVG) {
369			double loads[3];
370
371			getloadavg(loads, 3);
372			if (!nflag)
373				(void)printf("%s = ", string);
374			(void)printf("%.2f %.2f %.2f\n", loads[0],
375			    loads[1], loads[2]);
376			return;
377		} else if (mib[1] == VM_PSSTRINGS) {
378			struct _ps_strings _ps;
379
380			size = sizeof(_ps);
381			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
382				if (flags == 0)
383					return;
384				if (!nflag)
385					(void)printf("%s: ", string);
386				(void)puts("can't find ps strings");
387				return;
388			}
389			if (!nflag)
390				(void)printf("%s = ", string);
391			(void)printf("%p\n", _ps.val);
392			return;
393		}
394#ifdef UVM
395		else if (mib[1] == VM_SWAPENCRYPT) {
396			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
397			if (len < 0)
398				return;
399
400			break;
401		}
402#endif
403		if (flags == 0)
404			return;
405		warnx("use vmstat or systat to view %s information", string);
406		return;
407
408		break;
409
410	case CTL_NET:
411		if (mib[1] == PF_INET) {
412			len = sysctl_inet(string, &bufp, mib, flags, &type);
413			if (len < 0)
414				return;
415
416			if ((mib[2] == IPPROTO_TCP &&
417			     mib[3] == TCPCTL_BADDYNAMIC) ||
418			    (mib[2] == IPPROTO_UDP &&
419			     mib[3] == UDPCTL_BADDYNAMIC)) {
420
421				special |= BADDYNAMIC;
422
423				if (newval != NULL)
424					parse_baddynamic(mib, len, string,
425					    &newval, &newsize, flags, nflag);
426			}
427			break;
428		}
429#ifdef INET6
430		if (mib[1] == PF_INET6) {
431			len = sysctl_inet6(string, &bufp, mib, flags, &type);
432			if (len < 0)
433				return;
434
435			break;
436		}
437#endif
438		if (mib[1] == PF_IPX) {
439			len = sysctl_ipx(string, &bufp, mib, flags, &type);
440			if (len >= 0)
441				break;
442			return;
443		}
444		if (flags == 0)
445			return;
446		warnx("use netstat to view %s information", string);
447		return;
448
449	case CTL_DEBUG:
450		mib[2] = CTL_DEBUG_VALUE;
451		len = 3;
452		break;
453
454	case CTL_MACHDEP:
455#ifdef CPU_CONSDEV
456		if (mib[1] == CPU_CONSDEV)
457			special |= CHRDEV;
458#endif
459#ifdef CPU_BLK2CHR
460		if (mib[1] == CPU_BLK2CHR) {
461			if (bufp == NULL)
462				return;
463			mib[2] = makedev(atoi(bufp),0);
464			bufp = NULL;
465			len = 3;
466			special |= CHRDEV;
467			break;
468		}
469#endif
470#ifdef CPU_CHR2BLK
471		if (mib[1] == CPU_CHR2BLK) {
472			if (bufp == NULL)
473				return;
474			mib[2] = makedev(atoi(bufp),0);
475			bufp = NULL;
476			len = 3;
477			special |= BLKDEV;
478			break;
479		}
480#endif
481#ifdef CPU_BIOS
482		if (mib[1] == CPU_BIOS) {
483			len = sysctl_bios(string, &bufp, mib, flags, &type);
484			if (len < 0)
485				return;
486			if (mib[2] == BIOS_DEV)
487				special |= BIOSDEV;
488			if (mib[2] == BIOS_DISKINFO)
489				special |= BIOSGEO;
490			break;
491		}
492#endif
493		break;
494
495	case CTL_FS:
496		len = sysctl_fs(string, &bufp, mib, flags, &type);
497		if (len >= 0)
498			break;
499		return;
500
501	case CTL_VFS:
502		if (mib[1])
503			len = sysctl_vfs(string, &bufp, mib, flags, &type);
504		else
505			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
506		if (len >= 0) {
507			if (type == CTLTYPE_STRUCT) {
508				if (flags)
509					warnx("use nfsstat to view %s information",
510					    MOUNT_NFS);
511				return;
512			} else
513				break;
514		}
515		return;
516
517	case CTL_USER:
518	case CTL_DDB:
519		break;
520
521	default:
522		warnx("illegal top level value: %d", mib[0]);
523		return;
524
525	}
526	if (bufp) {
527		warnx("name %s in %s is unknown", bufp, string);
528		return;
529	}
530	if (newsize > 0) {
531		switch (type) {
532		case CTLTYPE_INT:
533			errno = 0;
534			if (special & UNSIGNED)
535				intval = strtoul(newval, &cp, 10);
536			else
537				intval = strtol(newval, &cp, 10);
538			if (*cp != '\0') {
539				warnx("%s: illegal value: %s", string,
540				    (char *)newval);
541				return;
542			}
543			if (errno == ERANGE) {
544				warnx("%s: value %s out of range", string,
545				    (char *)newval);
546				return;
547			}
548			newval = &intval;
549			newsize = sizeof(intval);
550			break;
551
552		case CTLTYPE_QUAD:
553			(void)sscanf(newval, "%qd", &quadval);
554			newval = &quadval;
555			newsize = sizeof(quadval);
556			break;
557		}
558	}
559	size = BUFSIZ;
560	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
561		if (flags == 0)
562			return;
563		switch (errno) {
564		case EOPNOTSUPP:
565			warnx("%s: value is not available", string);
566			return;
567		case ENOTDIR:
568			warnx("%s: specification is incomplete", string);
569			return;
570		case ENOMEM:
571			warnx("%s: type is unknown to this program", string);
572			return;
573		case ENXIO:
574			if (special & BIOSGEO)
575				return;
576		default:
577			warn("%s", string);
578			return;
579		}
580	}
581	if (special & CLOCK) {
582		struct clockinfo *clkp = (struct clockinfo *)buf;
583
584		if (!nflag)
585			(void)printf("%s = ", string);
586		(void)printf(
587		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
588		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
589		return;
590	}
591	if (special & BOOTTIME) {
592		struct timeval *btp = (struct timeval *)buf;
593		time_t boottime;
594
595		if (!nflag) {
596			boottime = btp->tv_sec;
597			(void)printf("%s = %s", string, ctime(&boottime));
598		} else
599			(void)printf("%ld\n", btp->tv_sec);
600		return;
601	}
602	if (special & BLKDEV) {
603		dev_t dev = *(dev_t *)buf;
604
605		if (!nflag)
606			(void)printf("%s = %s\n", string,
607			    devname(dev, S_IFBLK));
608		else
609			(void)printf("0x%x\n", dev);
610		return;
611	}
612	if (special & CHRDEV) {
613		dev_t dev = *(dev_t *)buf;
614
615		if (!nflag)
616			(void)printf("%s = %s\n", string,
617			    devname(dev, S_IFCHR));
618		else
619			(void)printf("0x%x\n", dev);
620		return;
621	}
622#ifdef CPU_BIOS
623	if (special & BIOSGEO) {
624		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
625
626		if (!nflag)
627			(void)printf("%s = ", string);
628		(void)printf("bootdev = 0x%x, "
629			     "cylinders = %u, heads = %u, sectors = %u\n",
630			     pdi->bsd_dev, pdi->bios_cylinders, pdi->bios_heads,
631			     pdi->bios_sectors);
632		return;
633	}
634	if (special & BIOSDEV) {
635		int dev = *(int*)buf;
636
637		if (!nflag)
638			(void)printf("%s = ", string);
639		(void) printf("0x%02x\n", dev);
640		return;
641	}
642#endif
643	if (special & UNSIGNED) {
644		if (newsize == 0) {
645			if (!nflag)
646				(void)printf("%s = ", string);
647			(void)printf("%u\n", *(u_int *)buf);
648		} else {
649			if (!nflag)
650				(void)printf("%s: %u -> ", string,
651				    *(u_int *)buf);
652			(void)printf("%u\n", *(u_int *)newval);
653		}
654		return;
655	}
656	if (special & RNDSTATS) {
657		struct rndstats *rndstats = (struct rndstats *)buf;
658		int i;
659
660		if (!nflag)
661			(void)printf("%s = ", string);
662		(void)printf(
663		"%qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu",
664		    rndstats->rnd_total,
665		    rndstats->rnd_used, rndstats->rnd_reads,
666		    rndstats->arc4_reads, rndstats->arc4_nstirs,
667		    rndstats->arc4_stirs,
668		    rndstats->rnd_pad[0],
669		    rndstats->rnd_pad[1],
670		    rndstats->rnd_pad[2],
671		    rndstats->rnd_pad[3],
672		    rndstats->rnd_pad[4],
673		    rndstats->rnd_waits,
674		    rndstats->rnd_enqs, rndstats->rnd_deqs,
675		    rndstats->rnd_drops, rndstats->rnd_drople);
676		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]); i++)
677			(void)printf(" %qu", rndstats->rnd_ed[i]);
678		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]); i++)
679			(void)printf(" %qu", rndstats->rnd_sc[i]);
680		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]); i++)
681			(void)printf(" %qu", rndstats->rnd_sb[i]);
682		printf("\n");
683		return;
684	}
685	if (special & BADDYNAMIC) {
686		in_port_t port, lastport;
687		u_int32_t *baddynamic = (u_int32_t *)buf;
688
689		if (!nflag)
690			(void)printf("%s%s", string, newsize ? ": " : " = ");
691		lastport = 0;
692		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
693			if (DP_ISSET(baddynamic, port)) {
694				(void)printf("%s%hd", lastport ? "," : "",
695				    port);
696				lastport = port;
697			}
698		if (newsize != 0) {
699			if (!nflag)
700				fputs(" -> ", stdout);
701			baddynamic = (u_int32_t *)newval;
702			lastport = 0;
703			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
704			    port++)
705				if (DP_ISSET(baddynamic, port)) {
706					(void)printf("%s%hd",
707					    lastport ? "," : "", port);
708					lastport = port;
709				}
710		}
711		(void)putchar('\n');
712		return;
713	}
714	switch (type) {
715	case CTLTYPE_INT:
716		if (newsize == 0) {
717			if (!nflag)
718				(void)printf("%s = ", string);
719			(void)printf("%d\n", *(int *)buf);
720		} else {
721			if (!nflag)
722				(void)printf("%s: %d -> ", string,
723				    *(int *)buf);
724			(void)printf("%d\n", *(int *)newval);
725		}
726		return;
727
728	case CTLTYPE_STRING:
729		if (newsize == 0) {
730			if (!nflag)
731				(void)printf("%s = ", string);
732			(void)puts(buf);
733		} else {
734			if (!nflag)
735				(void)printf("%s: %s -> ", string, buf);
736			(void)puts((char *)newval);
737		}
738		return;
739
740	case CTLTYPE_QUAD:
741		if (newsize == 0) {
742			if (!nflag)
743				(void)printf("%s = ", string);
744			(void)printf("%qd\n", *(quad_t *)buf);
745		} else {
746			if (!nflag)
747				(void)printf("%s: %qd -> ", string,
748				    *(quad_t *)buf);
749			(void)printf("%qd\n", *(quad_t *)newval);
750		}
751		return;
752
753	case CTLTYPE_STRUCT:
754		warnx("%s: unknown structure returned", string);
755		return;
756
757	default:
758	case CTLTYPE_NODE:
759		warnx("%s: unknown type returned", string);
760		return;
761	}
762}
763
764void
765parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
766	int mib[];
767	size_t len;
768	char *string;
769	void **newvalp;
770	size_t *newsizep;
771	int flags;
772	int nflag;
773{
774	static u_int32_t newbaddynamic[DP_MAPSIZE];
775	in_port_t port;
776	size_t size;
777	char action, *cp;
778
779	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
780		size = sizeof(newbaddynamic);
781		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
782			if (flags == 0)
783				return;
784			if (!nflag)
785				(void)printf("%s: ", string);
786			(void)puts("kernel does contain bad dynamic port tables");
787			return;
788		}
789
790		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
791			if (*cp != '+' && *cp != '-')
792				errx(1, "cannot mix +/- with full list");
793			action = *cp++;
794			port = atoi(cp);
795			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
796				errx(1, "invalid port, range is %d to %d",
797				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
798			if (action == '+')
799				DP_SET(newbaddynamic, port);
800			else
801				DP_CLR(newbaddynamic, port);
802		}
803	} else {
804		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
805		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
806			port = atoi(cp);
807			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
808				errx(1, "invalid port, range is %d to %d",
809				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
810			DP_SET(newbaddynamic, port);
811		}
812	}
813
814	*newvalp = (void *)newbaddynamic;
815	*newsizep = sizeof(newbaddynamic);
816}
817
818/*
819 * Initialize the set of debugging names
820 */
821void
822debuginit()
823{
824	int mib[3], loc, i;
825	size_t size;
826
827	if (secondlevel[CTL_DEBUG].list != 0)
828		return;
829	secondlevel[CTL_DEBUG].list = debugname;
830	mib[0] = CTL_DEBUG;
831	mib[2] = CTL_DEBUG_NAME;
832	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
833		mib[1] = i;
834		size = BUFSIZ - loc;
835		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
836			continue;
837		debugname[i].ctl_name = &names[loc];
838		debugname[i].ctl_type = CTLTYPE_INT;
839		loc += size;
840	}
841	lastused = loc;
842}
843
844struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
845struct ctlname ffsname[] = FFS_NAMES;
846struct ctlname nfsname[] = FS_NFS_NAMES;
847struct list *vfsvars;
848int *vfs_typenums;
849
850/*
851 * Initialize the set of filesystem names
852 */
853void
854vfsinit()
855{
856	int mib[4], maxtypenum, cnt, loc, size;
857	struct vfsconf vfc;
858	size_t buflen;
859
860	if (secondlevel[CTL_VFS].list != 0)
861		return;
862	mib[0] = CTL_VFS;
863	mib[1] = VFS_GENERIC;
864	mib[2] = VFS_MAXTYPENUM;
865	buflen = 4;
866	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
867		return;
868	maxtypenum++;	/* + generic */
869	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
870		return;
871	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
872	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
873		free(vfs_typenums);
874		return;
875	}
876	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
877	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
878		free(vfs_typenums);
879		free(vfsvars);
880		return;
881	}
882	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
883	mib[2] = VFS_CONF;
884	buflen = sizeof vfc;
885	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
886		mib[3] = cnt - 1;
887		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
888			if (errno == EOPNOTSUPP)
889				continue;
890			warn("vfsinit");
891			free(vfsname);
892			return;
893		}
894		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
895			vfsvars[cnt].list = ffsname;
896			vfsvars[cnt].size = FFS_MAXID;
897		}
898		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
899			vfsvars[cnt].list = nfsname;
900			vfsvars[cnt].size = NFS_MAXID;
901		}
902		vfs_typenums[cnt] = vfc.vfc_typenum;
903		strcat(&names[loc], vfc.vfc_name);
904		vfsname[cnt].ctl_name = &names[loc];
905		vfsname[cnt].ctl_type = CTLTYPE_NODE;
906		size = strlen(vfc.vfc_name) + 1;
907		loc += size;
908	}
909	lastused = loc;
910
911	vfsname[0].ctl_name = "mounts";
912	vfsname[0].ctl_type = CTLTYPE_NODE;
913	vfsvars[0].list = vfsname + 1;
914	vfsvars[0].size = maxtypenum - 1;
915
916	secondlevel[CTL_VFS].list = vfsname;
917	secondlevel[CTL_VFS].size = maxtypenum;
918	return;
919}
920
921int
922sysctl_vfsgen(string, bufpp, mib, flags, typep)
923	char *string;
924	char **bufpp;
925	int mib[];
926	int flags;
927	int *typep;
928{
929	int indx;
930	size_t size;
931	struct vfsconf vfc;
932
933	if (*bufpp == NULL) {
934		listall(string, vfsvars);
935		return (-1);
936	}
937
938	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
939		return (-1);
940
941	mib[1] = VFS_GENERIC;
942	mib[2] = VFS_CONF;
943	mib[3] = indx;
944	size = sizeof vfc;
945	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
946		if (errno != EOPNOTSUPP)
947			warn("vfs print");
948		return -1;
949	}
950	if (flags == 0 && vfc.vfc_refcount == 0)
951		return -1;
952	if (!nflag)
953		fprintf(stdout, "%s has %d mounted instance%s\n",
954		    string, vfc.vfc_refcount,
955		    vfc.vfc_refcount != 1 ? "s" : "");
956	else
957		fprintf(stdout, "%d\n", vfc.vfc_refcount);
958
959	return -1;
960}
961
962int
963sysctl_vfs(string, bufpp, mib, flags, typep)
964	char *string;
965	char **bufpp;
966	int mib[];
967	int flags;
968	int *typep;
969{
970	struct list *lp = &vfsvars[mib[1]];
971	int indx;
972
973	if (lp->list == NULL) {
974		if (flags)
975			warnx("No variables defined for file system %s", string);
976		return(-1);
977	}
978	if (*bufpp == NULL) {
979		listall(string, lp);
980		return (-1);
981	}
982	if ((indx = findname(string, "third", bufpp, lp)) == -1)
983		return (-1);
984
985	mib[1] = vfs_typenums[mib[1]];
986	mib[2] = indx;
987	*typep = lp->list[indx].ctl_type;
988	return (3);
989}
990
991struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
992struct list fslist = { posixname, FS_POSIX_MAXID };
993
994/*
995 * handle file system requests
996 */
997int
998sysctl_fs(string, bufpp, mib, flags, typep)
999	char *string;
1000	char **bufpp;
1001	int mib[];
1002	int flags;
1003	int *typep;
1004{
1005	int indx;
1006
1007	if (*bufpp == NULL) {
1008		listall(string, &fslist);
1009		return(-1);
1010	}
1011	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1012		return(-1);
1013	mib[2] = indx;
1014	*typep = fslist.list[indx].ctl_type;
1015	return(3);
1016}
1017
1018#ifdef CPU_BIOS
1019struct ctlname biosname[] = CTL_BIOS_NAMES;
1020struct list bioslist = { biosname, BIOS_MAXID };
1021
1022/*
1023 * handle BIOS requests
1024 */
1025int
1026sysctl_bios(string, bufpp, mib, flags, typep)
1027	char *string;
1028	char **bufpp;
1029	int mib[];
1030	int flags;
1031	int *typep;
1032{
1033	char *name;
1034	int indx;
1035
1036	if (*bufpp == NULL) {
1037		listall(string, &bioslist);
1038		return(-1);
1039	}
1040	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1041		return(-1);
1042	mib[2] = indx;
1043	if (indx == BIOS_DISKINFO) {
1044		if (*bufpp == NULL) {
1045			char name[BUFSIZ];
1046
1047			/* scan all the bios devices */
1048			for (indx = 0; indx < 256; indx++) {
1049				snprintf(name, sizeof(name), "%s.%u",
1050					 string, indx);
1051				parse(name, 1);
1052			}
1053			return(-1);
1054		}
1055		if ((name = strsep(bufpp, ".")) == NULL) {
1056			warnx("%s: incomplete specification", string);
1057			return(-1);
1058		}
1059		mib[3] = atoi(name);
1060		*typep = CTLTYPE_STRUCT;
1061		return 4;
1062	} else {
1063		*typep = bioslist.list[indx].ctl_type;
1064		return(3);
1065	}
1066}
1067#endif
1068
1069#ifdef UVM
1070struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1071struct list swpenclist = { swpencname, SWPENC_MAXID };
1072
1073/*
1074 * handle swap encrypt requests
1075 */
1076int
1077sysctl_swpenc(string, bufpp, mib, flags, typep)
1078	char *string;
1079	char **bufpp;
1080	int mib[];
1081	int flags;
1082	int *typep;
1083{
1084	char *name;
1085	int indx;
1086
1087	if (*bufpp == NULL) {
1088		listall(string, &swpenclist);
1089		return(-1);
1090	}
1091	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1092		return(-1);
1093	mib[2] = indx;
1094	*typep = swpenclist.list[indx].ctl_type;
1095	return(3);
1096}
1097#endif
1098
1099struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1100struct ctlname ipname[] = IPCTL_NAMES;
1101struct ctlname icmpname[] = ICMPCTL_NAMES;
1102struct ctlname ipipname[] = IPIPCTL_NAMES;
1103struct ctlname tcpname[] = TCPCTL_NAMES;
1104struct ctlname udpname[] = UDPCTL_NAMES;
1105struct ctlname espname[] = ESPCTL_NAMES;
1106struct ctlname ahname[] = AHCTL_NAMES;
1107struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1108struct ctlname grename[] = GRECTL_NAMES;
1109struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1110struct list inetlist = { inetname, IPPROTO_MAXID };
1111struct list inetvars[] = {
1112	{ ipname, IPCTL_MAXID },	/* ip */
1113	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1114	{ 0, 0 },			/* igmp */
1115	{ 0, 0 },			/* ggmp */
1116	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1117	{ 0, 0 },
1118	{ tcpname, TCPCTL_MAXID },	/* tcp */
1119	{ 0, 0 },
1120	{ 0, 0 },			/* egp */
1121	{ 0, 0 },
1122	{ 0, 0 },
1123	{ 0, 0 },
1124	{ 0, 0 },			/* pup */
1125	{ 0, 0 },
1126	{ 0, 0 },
1127	{ 0, 0 },
1128	{ 0, 0 },
1129	{ udpname, UDPCTL_MAXID },	/* udp */
1130	{ 0, 0 },
1131	{ 0, 0 },
1132	{ 0, 0 },
1133	{ 0, 0 },
1134	{ 0, 0 },
1135	{ 0, 0 },
1136	{ 0, 0 },
1137	{ 0, 0 },
1138	{ 0, 0 },
1139	{ 0, 0 },
1140	{ 0, 0 },
1141	{ 0, 0 },
1142	{ 0, 0 },
1143	{ 0, 0 },
1144	{ 0, 0 },
1145	{ 0, 0 },
1146	{ 0, 0 },
1147	{ 0, 0 },
1148	{ 0, 0 },
1149	{ 0, 0 },
1150	{ 0, 0 },
1151	{ 0, 0 },
1152	{ 0, 0 },
1153	{ 0, 0 },
1154	{ 0, 0 },
1155	{ 0, 0 },
1156	{ 0, 0 },
1157	{ 0, 0 },
1158	{ 0, 0 },
1159	{ grename, GRECTL_MAXID }, /* GRE */
1160	{ 0, 0 },
1161	{ 0, 0 },
1162	{ espname, ESPCTL_MAXID },	/* esp */
1163	{ ahname, AHCTL_MAXID },	/* ah */
1164	{ 0, 0 },
1165	{ 0, 0 },
1166	{ 0, 0 },
1167	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1168	{ 0, 0 },
1169	{ 0, 0 },
1170	{ 0, 0 },
1171	{ 0, 0 },
1172	{ 0, 0 },
1173	{ 0, 0 },
1174	{ 0, 0 },
1175	{ 0, 0 },
1176	{ 0, 0 },
1177	{ 0, 0 },
1178	{ 0, 0 },
1179	{ 0, 0 },
1180	{ 0, 0 },
1181	{ 0, 0 },
1182	{ 0, 0 },
1183	{ 0, 0 },
1184	{ 0, 0 },
1185	{ 0, 0 },
1186	{ 0, 0 },
1187	{ 0, 0 },
1188	{ 0, 0 },
1189	{ 0, 0 },
1190	{ 0, 0 },
1191	{ 0, 0 },
1192	{ 0, 0 },
1193	{ 0, 0 },
1194	{ 0, 0 },
1195	{ 0, 0 },
1196	{ 0, 0 },
1197	{ 0, 0 },
1198	{ 0, 0 },
1199	{ 0, 0 },
1200	{ 0, 0 },
1201	{ 0, 0 },
1202	{ 0, 0 },
1203	{ 0, 0 },
1204	{ 0, 0 },
1205	{ 0, 0 },
1206	{ 0, 0 },
1207	{ 0, 0 },
1208	{ 0, 0 },
1209	{ etheripname, ETHERIPCTL_MAXID },
1210};
1211
1212/*
1213 * handle internet requests
1214 */
1215int
1216sysctl_inet(string, bufpp, mib, flags, typep)
1217	char *string;
1218	char **bufpp;
1219	int mib[];
1220	int flags;
1221	int *typep;
1222{
1223	struct list *lp;
1224	int indx;
1225
1226	if (*bufpp == NULL) {
1227		listall(string, &inetlist);
1228		return(-1);
1229	}
1230	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1231		return(-1);
1232	mib[2] = indx;
1233	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1234		lp = &inetvars[indx];
1235	else if (!flags)
1236		return(-1);
1237	else {
1238		warnx("%s: no variables defined for this protocol", string);
1239		return(-1);
1240	}
1241	if (*bufpp == NULL) {
1242		listall(string, lp);
1243		return(-1);
1244	}
1245	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1246		return(-1);
1247	mib[3] = indx;
1248	*typep = lp->list[indx].ctl_type;
1249	return(4);
1250}
1251
1252#ifdef INET6
1253struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1254struct ctlname ip6name[] = IPV6CTL_NAMES;
1255struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1256struct ctlname pim6name[] = PIM6CTL_NAMES;
1257struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1258struct list inet6vars[] = {
1259/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1260	{ 0, 0 },
1261	{ 0, 0 },
1262	{ 0, 0 },
1263	{ 0, 0 },
1264	{ 0, 0 },
1265/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1266	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1267/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1268	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1269/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1270	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1271/*40*/	{ 0, 0 },
1272	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1273	{ 0, 0 },
1274	{ 0, 0 },
1275	{ 0, 0 },
1276	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1277/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1278	{ 0, 0 },
1279	{ 0, 0 },
1280	{ 0, 0 },
1281	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1282	{ 0, 0 },
1283/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1284	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1285/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1286	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1287/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1288	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1289/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1290	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1291/*100*/	{ 0, 0 },
1292	{ 0, 0 },
1293	{ 0, 0 },
1294	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1295};
1296
1297/*
1298 * handle internet6 requests
1299 */
1300int
1301sysctl_inet6(string, bufpp, mib, flags, typep)
1302	char *string;
1303	char **bufpp;
1304	int mib[];
1305	int flags;
1306	int *typep;
1307{
1308	struct list *lp;
1309	int indx;
1310
1311	if (*bufpp == NULL) {
1312		listall(string, &inet6list);
1313		return(-1);
1314	}
1315	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1316		return(-1);
1317	mib[2] = indx;
1318	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1319		lp = &inet6vars[indx];
1320	else if (!flags)
1321		return(-1);
1322	else {
1323		warnx("%s: no variables defined for this protocol", string);
1324		return(-1);
1325	}
1326	if (*bufpp == NULL) {
1327		listall(string, lp);
1328		return(-1);
1329	}
1330	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1331		return(-1);
1332	mib[3] = indx;
1333	*typep = lp->list[indx].ctl_type;
1334	return(4);
1335}
1336#endif
1337
1338struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1339struct ctlname ipxpname[] = IPXCTL_NAMES;
1340struct ctlname spxpname[] = SPXCTL_NAMES;
1341struct list ipxlist = { ipxname, IPXCTL_MAXID };
1342struct list ipxvars[] = {
1343	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1344	{ 0, 0 },
1345	{ 0, 0 },
1346	{ 0, 0 },
1347	{ 0, 0 },
1348	{ spxpname, SPXCTL_MAXID },
1349};
1350
1351/*
1352 * Handle internet requests
1353 */
1354int
1355sysctl_ipx(string, bufpp, mib, flags, typep)
1356	char *string;
1357	char **bufpp;
1358	int mib[];
1359	int flags;
1360	int *typep;
1361{
1362	struct list *lp;
1363	int indx;
1364
1365	if (*bufpp == NULL) {
1366		listall(string, &ipxlist);
1367		return(-1);
1368	}
1369	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1370		return(-1);
1371	mib[2] = indx;
1372	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1373		lp = &ipxvars[indx];
1374	else if (!flags)
1375		return(-1);
1376	else {
1377		warnx("%s: no variables defined for this protocol", string);
1378		return(-1);
1379	}
1380	if (*bufpp == NULL) {
1381		listall(string, lp);
1382		return(-1);
1383	}
1384	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1385		return(-1);
1386	mib[3] = indx;
1387	*typep = lp->list[indx].ctl_type;
1388	return(4);
1389}
1390
1391/*
1392 * Scan a list of names searching for a particular name.
1393 */
1394int
1395findname(string, level, bufp, namelist)
1396	char *string;
1397	char *level;
1398	char **bufp;
1399	struct list *namelist;
1400{
1401	char *name;
1402	int i;
1403
1404	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1405		warnx("%s: incomplete specification", string);
1406		return(-1);
1407	}
1408	for (i = 0; i < namelist->size; i++)
1409		if (namelist->list[i].ctl_name != NULL &&
1410		    strcmp(name, namelist->list[i].ctl_name) == 0)
1411			break;
1412	if (i == namelist->size) {
1413		warnx("%s level name %s in %s is invalid", level, name, string);
1414		return(-1);
1415	}
1416	return(i);
1417}
1418
1419void
1420usage()
1421{
1422
1423	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1424	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1425	    "sysctl [-n] -a", "sysctl [-n] -A");
1426	exit(1);
1427}
1428