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