sysctl.c revision 1.27
1/*	$OpenBSD: sysctl.c,v 1.27 1997/10/03 20:58: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.1 (Berkeley) 6/6/93";
46#else
47static char *rcsid = "$OpenBSD: sysctl.c,v 1.27 1997/10/03 20:58:04 deraadt Exp $";
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/gmon.h>
53#include <sys/stat.h>
54#include <sys/sysctl.h>
55#include <sys/socket.h>
56#include <vm/vm_param.h>
57#include <machine/cpu.h>
58
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/icmp_var.h>
67#include <netinet/ip_var.h>
68#include <netinet/udp.h>
69#include <netinet/udp_var.h>
70#include <netinet/tcp.h>
71#include <netinet/tcp_timer.h>
72#include <netinet/tcp_var.h>
73
74#include <netipx/ipx.h>
75#include <netipx/ipx_var.h>
76#include <netipx/spx_var.h>
77#include <ddb/db_var.h>
78#include <dev/rndvar.h>
79#include <net/encap.h>
80#include <netinet/ip_ipsp.h>
81
82#include <err.h>
83#include <errno.h>
84#include <stdio.h>
85#include <stdlib.h>
86#include <string.h>
87#include <ctype.h>
88
89#ifdef CPU_BIOS
90#include <machine/biosvar.h>
91#endif
92
93struct ctlname topname[] = CTL_NAMES;
94struct ctlname kernname[] = CTL_KERN_NAMES;
95struct ctlname vmname[] = CTL_VM_NAMES;
96struct ctlname fsname[] = CTL_FS_NAMES;
97struct ctlname netname[] = CTL_NET_NAMES;
98struct ctlname hwname[] = CTL_HW_NAMES;
99struct ctlname username[] = CTL_USER_NAMES;
100struct ctlname debugname[CTL_DEBUG_MAXID];
101#ifdef CTL_MACHDEP_NAMES
102struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
103#endif
104struct ctlname ddbname[] = CTL_DDB_NAMES;
105char names[BUFSIZ];
106
107struct list {
108	struct	ctlname *list;
109	int	size;
110};
111struct list toplist = { topname, CTL_MAXID };
112struct list secondlevel[] = {
113	{ 0, 0 },			/* CTL_UNSPEC */
114	{ kernname, KERN_MAXID },	/* CTL_KERN */
115	{ vmname, VM_MAXID },		/* CTL_VM */
116	{ fsname, FS_MAXID },		/* CTL_FS */
117	{ netname, NET_MAXID },		/* CTL_NET */
118	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
119	{ hwname, HW_MAXID },		/* CTL_HW */
120#ifdef CTL_MACHDEP_NAMES
121	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
122#else
123	{ 0, 0 },			/* CTL_MACHDEP */
124#endif
125	{ username, USER_MAXID },	/* CTL_USER_NAMES */
126	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
127};
128
129int	Aflag, aflag, nflag, wflag;
130
131/*
132 * Variables requiring special processing.
133 */
134#define	CLOCK		0x00000001
135#define	BOOTTIME	0x00000002
136#define	CONSDEV		0x00000004
137#define RNDSTATS	0x00000008
138#define BADDYNAMIC	0x00000010
139#define BIOSGEO		0x00000020
140#define BIOSDEV		0x00000040
141
142/* prototypes */
143void debuginit __P((void));
144void listall __P((char *, struct list *));
145void parse __P((char *, int));
146void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
147void usage __P((void));
148int findname __P((char *, char *, char **, struct list *));
149int sysctl_inet __P((char *, char **, int *, int, int *));
150int sysctl_ipsec __P((char *, char **, int *, int, int *));
151int sysctl_ipx __P((char *, char **, int *, int, int *));
152int sysctl_fs __P((char *, char **, int *, int, int *));
153int sysctl_bios __P((char *, char **, int *, int, int *));
154
155int
156main(argc, argv)
157	int argc;
158	char *argv[];
159{
160	int ch, lvl1;
161
162	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
163		switch (ch) {
164
165		case 'A':
166			Aflag = 1;
167			break;
168
169		case 'a':
170			aflag = 1;
171			break;
172
173		case 'n':
174			nflag = 1;
175			break;
176
177		case 'w':
178			wflag = 1;
179			break;
180
181		default:
182			usage();
183		}
184	}
185	argc -= optind;
186	argv += optind;
187
188	if (Aflag || aflag) {
189		debuginit();
190		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
191			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
192		exit(0);
193	}
194	if (argc == 0)
195		usage();
196	while (argc-- > 0)
197		parse(*argv++, 1);
198	exit(0);
199}
200
201/*
202 * List all variables known to the system.
203 */
204void
205listall(prefix, lp)
206	char *prefix;
207	struct list *lp;
208{
209	int lvl2;
210	char *cp, name[BUFSIZ];
211
212	if (lp->list == NULL)
213		return;
214	(void)strncpy(name, prefix, BUFSIZ-1);
215	cp = &name[strlen(name)];
216	*cp++ = '.';
217	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
218		if (lp->list[lvl2].ctl_name == NULL)
219			continue;
220		(void)strcpy(cp, lp->list[lvl2].ctl_name);
221		parse(name, Aflag);
222	}
223}
224
225/*
226 * Parse a name into a MIB entry.
227 * Lookup and print out the MIB entry if it exists.
228 * Set a new value if requested.
229 */
230void
231parse(string, flags)
232	char *string;
233	int flags;
234{
235	int indx, type, state;
236	int special = 0;
237	void *newval = 0;
238	int intval, newsize = 0;
239	quad_t quadval;
240	size_t size, len;
241	struct list *lp;
242	int mib[CTL_MAXNAME];
243	char *cp, *bufp, buf[BUFSIZ];
244
245	(void)strncpy(buf, string, sizeof(buf) - 1);
246	buf[sizeof(buf) - 1] = '\0';
247	bufp = buf;
248	if ((cp = strchr(string, '=')) != NULL) {
249		if (!wflag)
250			errx(2, "must specify -w to set variables");
251		*strchr(buf, '=') = '\0';
252		*cp++ = '\0';
253		while (isspace(*cp))
254			cp++;
255		newval = cp;
256		newsize = strlen(cp);
257	}
258	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
259		return;
260	mib[0] = indx;
261	if (indx == CTL_DEBUG)
262		debuginit();
263	lp = &secondlevel[indx];
264	if (lp->list == 0) {
265		warnx("%s: class is not implemented", topname[indx].ctl_name);
266		return;
267	}
268	if (bufp == NULL) {
269		listall(topname[indx].ctl_name, lp);
270		return;
271	}
272	if ((indx = findname(string, "second", &bufp, lp)) == -1)
273		return;
274	mib[1] = indx;
275	type = lp->list[indx].ctl_type;
276	len = 2;
277	switch (mib[0]) {
278
279	case CTL_KERN:
280		switch (mib[1]) {
281		case KERN_PROF:
282			mib[2] = GPROF_STATE;
283			size = sizeof(state);
284			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
285				if (flags == 0)
286					return;
287				if (!nflag)
288					(void)printf("%s: ", string);
289				(void)puts("kernel is not compiled for profiling");
290				return;
291			}
292			if (!nflag)
293				(void)printf("%s = %s\n", string,
294				    state == GMON_PROF_OFF ? "off" : "running");
295			return;
296		case KERN_VNODE:
297		case KERN_FILE:
298			if (flags == 0)
299				return;
300			warnx("use pstat to view %s information", string);
301			return;
302		case KERN_PROC:
303			if (flags == 0)
304				return;
305			warnx("use ps to view %s information", string);
306			return;
307		case KERN_NTPTIME:
308			if (flags == 0)
309				return;
310			warnx("use xntpd to view %s information", string);
311			return;
312		case KERN_CLOCKRATE:
313			special |= CLOCK;
314			break;
315		case KERN_BOOTTIME:
316			special |= BOOTTIME;
317			break;
318		case KERN_RND:
319			special |= RNDSTATS;
320			break;
321		}
322		break;
323
324	case CTL_HW:
325		break;
326
327	case CTL_VM:
328		if (mib[1] == VM_LOADAVG) {
329			double loads[3];
330
331			getloadavg(loads, 3);
332			if (!nflag)
333				(void)printf("%s = ", string);
334			(void)printf("%.2f %.2f %.2f\n", loads[0],
335			    loads[1], loads[2]);
336			return;
337		} else if (mib[1] == VM_PSSTRINGS) {
338			struct _ps_strings _ps;
339
340			len = sizeof(_ps);
341			if (sysctl(mib, 2, &_ps, &len, NULL, 0) == -1) {
342				if (flags == 0)
343					return;
344				if (!nflag)
345					(void)printf("%s: ", string);
346				(void)puts("can't find ps strings");
347				return;
348			}
349			if (!nflag)
350				(void)printf("%s = ", string);
351			(void)printf("%p\n", _ps.val);
352			return;
353		}
354		if (flags == 0)
355			return;
356		warnx("use vmstat or systat to view %s information", string);
357		return;
358
359	case CTL_NET:
360		if (mib[1] == PF_INET) {
361			len = sysctl_inet(string, &bufp, mib, flags, &type);
362			if (len < 0)
363				return;
364
365			if ((mib[2] == IPPROTO_TCP &&
366			     mib[3] == TCPCTL_BADDYNAMIC) ||
367			    (mib[2] == IPPROTO_UDP &&
368			     mib[3] == UDPCTL_BADDYNAMIC)) {
369
370				special |= BADDYNAMIC;
371
372				if (newval != NULL)
373					parse_baddynamic(mib, len, string,
374					    &newval, &newsize, flags, nflag);
375			}
376			break;
377		}
378		if (mib[1] == PF_IPX) {
379			len = sysctl_ipx(string, &bufp, mib, flags, &type);
380			if (len >= 0)
381				break;
382			return;
383		}
384		if (mib[1] == PF_ENCAP) {
385			len = sysctl_ipsec(string, &bufp, mib, flags, &type);
386			if (len >= 0)
387				break;
388			return;
389		}
390		if (flags == 0)
391			return;
392		warnx("use netstat to view %s information", string);
393		return;
394
395	case CTL_DEBUG:
396		mib[2] = CTL_DEBUG_VALUE;
397		len = 3;
398		break;
399
400	case CTL_MACHDEP:
401#ifdef CPU_CONSDEV
402		if (mib[1] == CPU_CONSDEV)
403			special |= CONSDEV;
404#endif
405#ifdef CPU_BIOS
406		if (mib[1] == CPU_BIOS) {
407			len = sysctl_bios(string, &bufp, mib, flags, &type);
408			if (mib[2] == BIOS_GEOMETRY)
409				special |= BIOSGEO;
410			if (mib[2] == BIOS_DEV)
411				special |= BIOSDEV;
412			if (len >= 0)
413				break;
414			return;
415		}
416#endif
417		break;
418
419	case CTL_FS:
420		len = sysctl_fs(string, &bufp, mib, flags, &type);
421		if (len >= 0)
422			break;
423		return;
424
425	case CTL_USER:
426	case CTL_DDB:
427		break;
428
429	default:
430		warnx("illegal top level value: %d", mib[0]);
431		return;
432
433	}
434	if (bufp) {
435		warnx("name %s in %s is unknown", bufp, string);
436		return;
437	}
438	if (newsize > 0) {
439		switch (type) {
440		case CTLTYPE_INT:
441			intval = atoi(newval);
442			newval = &intval;
443			newsize = sizeof(intval);
444			break;
445
446		case CTLTYPE_QUAD:
447			(void)sscanf(newval, "%qd", &quadval);
448			newval = &quadval;
449			newsize = sizeof(quadval);
450			break;
451		}
452	}
453	size = BUFSIZ;
454	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
455		if (flags == 0)
456			return;
457		switch (errno) {
458		case EOPNOTSUPP:
459			warnx("%s: value is not available", string);
460			return;
461		case ENOTDIR:
462			warnx("%s: specification is incomplete", string);
463			return;
464		case ENOMEM:
465			warnx("%s: type is unknown to this program", string);
466			return;
467		default:
468			warnx(string);
469			return;
470		}
471	}
472	if (special & CLOCK) {
473		struct clockinfo *clkp = (struct clockinfo *)buf;
474
475		if (!nflag)
476			(void)printf("%s = ", string);
477		(void)printf(
478		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
479		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
480		return;
481	}
482	if (special & BOOTTIME) {
483		struct timeval *btp = (struct timeval *)buf;
484		time_t boottime;
485
486		if (!nflag) {
487			boottime = btp->tv_sec;
488			(void)printf("%s = %s", string, ctime(&boottime));
489		} else
490			(void)printf("%ld\n", btp->tv_sec);
491		return;
492	}
493	if (special & CONSDEV) {
494		dev_t dev = *(dev_t *)buf;
495
496		if (!nflag)
497			(void)printf("%s = %s\n", string,
498			    devname(dev, S_IFCHR));
499		else
500			(void)printf("0x%x\n", dev);
501		return;
502	}
503#ifdef CPU_BIOS
504	if (special & BIOSGEO) {
505		u_int geo = *(int *)buf;
506
507		if (!nflag)
508			(void)printf("%s = ", string);
509		printf("Cylinders=%d Tracks=%d Sectors=%d %08x\n",
510		    BIOSNTRACKS(geo), BIOSNHEADS(geo), BIOSNSECTS(geo), geo);
511		return;
512	}
513	if (special & BIOSDEV) {
514		int dev = *(int*)buf;
515
516		if (!nflag)
517			(void)printf("%s = ", string);
518		if (dev & 0x80)
519			dev = ('c' + dev) & 0x7f;
520		else
521			dev += 'a';
522		(void) printf("%c:\n", dev);
523		return;
524	}
525#endif
526	if (special & RNDSTATS) {
527		struct rndstats *rndstats = (struct rndstats *)buf;
528
529		if (!nflag)
530			(void)printf("%s = ", string);
531		(void)printf(
532		    "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
533		    rndstats->rnd_total, rndstats->rnd_used,
534		    rndstats->arc4_reads, rndstats->rnd_timer,
535		    rndstats->rnd_mouse, rndstats->rnd_tty,
536		    rndstats->rnd_disk, rndstats->rnd_net,
537		    rndstats->rnd_reads, rndstats->rnd_waits,
538		    rndstats->rnd_enqs, rndstats->rnd_deqs,
539		    rndstats->rnd_drops, rndstats->rnd_drople,
540		    rndstats->rnd_asleep, rndstats->rnd_queued);
541		return;
542	}
543	if (special & BADDYNAMIC) {
544		in_port_t port, lastport;
545		u_int32_t *baddynamic = (u_int32_t *)buf;
546
547		if (!nflag)
548			(void)printf("%s%s", string, newsize ? ": " : " = ");
549		lastport = 0;
550		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
551			if (DP_ISSET(baddynamic, port)) {
552				(void)printf("%s%hd", lastport ? "," : "",
553				    port);
554				lastport = port;
555			}
556		if (newsize != 0) {
557			if (!nflag)
558				fputs(" -> ", stdout);
559			baddynamic = (u_int32_t *)newval;
560			lastport = 0;
561			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
562			    port++)
563				if (DP_ISSET(baddynamic, port)) {
564					(void)printf("%s%hd",
565					    lastport ? "," : "", port);
566					lastport = port;
567				}
568		}
569		(void)putchar('\n');
570		return;
571	}
572	switch (type) {
573	case CTLTYPE_INT:
574		if (newsize == 0) {
575			if (!nflag)
576				(void)printf("%s = ", string);
577			(void)printf("%d\n", *(int *)buf);
578		} else {
579			if (!nflag)
580				(void)printf("%s: %d -> ", string,
581				    *(int *)buf);
582			(void)printf("%d\n", *(int *)newval);
583		}
584		return;
585
586	case CTLTYPE_STRING:
587		if (newsize == 0) {
588			if (!nflag)
589				(void)printf("%s = ", string);
590			(void)puts(buf);
591		} else {
592			if (!nflag)
593				(void)printf("%s: %s -> ", string, buf);
594			(void)puts((char *)newval);
595		}
596		return;
597
598	case CTLTYPE_QUAD:
599		if (newsize == 0) {
600			if (!nflag)
601				(void)printf("%s = ", string);
602			(void)printf("%qd\n", *(quad_t *)buf);
603		} else {
604			if (!nflag)
605				(void)printf("%s: %qd -> ", string,
606				    *(quad_t *)buf);
607			(void)printf("%qd\n", *(quad_t *)newval);
608		}
609		return;
610
611	case CTLTYPE_STRUCT:
612		warnx("%s: unknown structure returned", string);
613		return;
614
615	default:
616	case CTLTYPE_NODE:
617		warnx("%s: unknown type returned", string);
618		return;
619	}
620}
621
622void
623parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
624	int mib[];
625	size_t len;
626	char *string;
627	void **newvalp;
628	size_t *newsizep;
629	int flags;
630	int nflag;
631{
632	static u_int32_t newbaddynamic[DP_MAPSIZE];
633	in_port_t port;
634	size_t size;
635	char action, *cp;
636
637	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
638		size = sizeof(newbaddynamic);
639		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
640			if (flags == 0)
641				return;
642			if (!nflag)
643				(void)printf("%s: ", string);
644			(void)puts("kernel does contain bad dynamic port tables");
645			return;
646		}
647
648		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
649			if (*cp != '+' && *cp != '-')
650				errx(1, "cannot mix +/- with full list");
651			action = *cp++;
652			port = atoi(cp);
653			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
654				errx(1, "invalid port, range is %d to %d",
655				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
656			if (action == '+')
657				DP_SET(newbaddynamic, port);
658			else
659				DP_CLR(newbaddynamic, port);
660		}
661	} else {
662		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
663		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
664			port = atoi(cp);
665			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
666				errx(1, "invalid port, range is %d to %d",
667				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
668			DP_SET(newbaddynamic, port);
669		}
670	}
671
672	*newvalp = (void *)newbaddynamic;
673	*newsizep = sizeof(newbaddynamic);
674}
675
676/*
677 * Initialize the set of debugging names
678 */
679void
680debuginit()
681{
682	int mib[3], loc, i;
683	size_t size;
684
685	if (secondlevel[CTL_DEBUG].list != 0)
686		return;
687	secondlevel[CTL_DEBUG].list = debugname;
688	mib[0] = CTL_DEBUG;
689	mib[2] = CTL_DEBUG_NAME;
690	for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
691		mib[1] = i;
692		size = BUFSIZ - loc;
693		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
694			continue;
695		debugname[i].ctl_name = &names[loc];
696		debugname[i].ctl_type = CTLTYPE_INT;
697		loc += size;
698	}
699}
700
701struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
702struct list fslist = { posixname, FS_POSIX_MAXID };
703
704/*
705 * handle file system requests
706 */
707int
708sysctl_fs(string, bufpp, mib, flags, typep)
709	char *string;
710	char **bufpp;
711	int mib[];
712	int flags;
713	int *typep;
714{
715	int indx;
716
717	if (*bufpp == NULL) {
718		listall(string, &fslist);
719		return(-1);
720	}
721	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
722		return(-1);
723	mib[2] = indx;
724	*typep = fslist.list[indx].ctl_type;
725	return(3);
726}
727
728#ifdef CPU_BIOS
729struct ctlname biosname[] = CTL_BIOS_NAMES;
730struct list bioslist = { biosname, BIOS_MAXID };
731
732/*
733 * handle BIOS requests
734 */
735int
736sysctl_bios(string, bufpp, mib, flags, typep)
737	char *string;
738	char **bufpp;
739	int mib[];
740	int flags;
741	int *typep;
742{
743	int indx;
744
745	if (*bufpp == NULL) {
746		listall(string, &bioslist);
747		return(-1);
748	}
749	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
750		return(-1);
751	mib[2] = indx;
752	*typep = bioslist.list[indx].ctl_type;
753	return(3);
754}
755#endif
756
757struct ctlname encapname[] = ENCAPCTL_NAMES;
758struct ctlname ipsecname[] = CTL_IPSEC_NAMES;
759struct list ipseclist = { ipsecname, IPSECCTL_MAXID };
760struct list ipsecvars[] = {
761	{ encapname, ENCAPCTL_MAXID },
762};
763
764/*
765 * handle ipsec requests
766 */
767int
768sysctl_ipsec(string, bufpp, mib, flags, typep)
769	char *string;
770	char **bufpp;
771	int mib[];
772	int flags;
773	int *typep;
774{
775	struct list *lp;
776	int indx;
777
778	if (*bufpp == NULL) {
779		listall(string, &ipseclist);
780		return(-1);
781	}
782	if ((indx = findname(string, "third", bufpp, &ipseclist)) == -1)
783		return(-1);
784	mib[2] = indx;
785	if (indx <= IPSECCTL_MAXID && ipsecvars[indx].list != NULL)
786		lp = &ipsecvars[indx];
787	else if (!flags)
788		return(-1);
789	else {
790		warnx("%s: no variables defined for this protocol", string);
791		return(-1);
792	}
793	if (*bufpp == NULL) {
794		listall(string, lp);
795		return(-1);
796	}
797	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
798		return(-1);
799	mib[3] = indx;
800	*typep = lp->list[indx].ctl_type;
801	return(4);
802}
803
804struct ctlname inetname[] = CTL_IPPROTO_NAMES;
805struct ctlname ipname[] = IPCTL_NAMES;
806struct ctlname icmpname[] = ICMPCTL_NAMES;
807struct ctlname tcpname[] = TCPCTL_NAMES;
808struct ctlname udpname[] = UDPCTL_NAMES;
809struct list inetlist = { inetname, IPPROTO_MAXID };
810struct list inetvars[] = {
811	{ ipname, IPCTL_MAXID },	/* ip */
812	{ icmpname, ICMPCTL_MAXID },	/* icmp */
813	{ 0, 0 },			/* igmp */
814	{ 0, 0 },			/* ggmp */
815	{ 0, 0 },
816	{ 0, 0 },
817	{ tcpname, TCPCTL_MAXID },	/* tcp */
818	{ 0, 0 },
819	{ 0, 0 },			/* egp */
820	{ 0, 0 },
821	{ 0, 0 },
822	{ 0, 0 },
823	{ 0, 0 },			/* pup */
824	{ 0, 0 },
825	{ 0, 0 },
826	{ 0, 0 },
827	{ 0, 0 },
828	{ udpname, UDPCTL_MAXID },	/* udp */
829};
830
831/*
832 * handle internet requests
833 */
834int
835sysctl_inet(string, bufpp, mib, flags, typep)
836	char *string;
837	char **bufpp;
838	int mib[];
839	int flags;
840	int *typep;
841{
842	struct list *lp;
843	int indx;
844
845	if (*bufpp == NULL) {
846		listall(string, &inetlist);
847		return(-1);
848	}
849	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
850		return(-1);
851	mib[2] = indx;
852	if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
853		lp = &inetvars[indx];
854	else if (!flags)
855		return(-1);
856	else {
857		warnx("%s: no variables defined for this protocol", string);
858		return(-1);
859	}
860	if (*bufpp == NULL) {
861		listall(string, lp);
862		return(-1);
863	}
864	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
865		return(-1);
866	mib[3] = indx;
867	*typep = lp->list[indx].ctl_type;
868	return(4);
869}
870
871struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
872struct ctlname ipxpname[] = IPXCTL_NAMES;
873struct ctlname spxpname[] = SPXCTL_NAMES;
874struct list ipxlist = { ipxname, IPXCTL_MAXID };
875struct list ipxvars[] = {
876	{ ipxpname, IPXCTL_MAXID },	/* ipx */
877	{ 0, 0 },
878	{ 0, 0 },
879	{ 0, 0 },
880	{ 0, 0 },
881	{ spxpname, SPXCTL_MAXID },
882};
883
884/*
885 * Handle internet requests
886 */
887int
888sysctl_ipx(string, bufpp, mib, flags, typep)
889	char *string;
890	char **bufpp;
891	int mib[];
892	int flags;
893	int *typep;
894{
895	struct list *lp;
896	int indx;
897
898	if (*bufpp == NULL) {
899		listall(string, &ipxlist);
900		return(-1);
901	}
902	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
903		return(-1);
904	mib[2] = indx;
905	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
906		lp = &ipxvars[indx];
907	else if (!flags)
908		return(-1);
909	else {
910		warnx("%s: no variables defined for this protocol", string);
911		return(-1);
912	}
913	if (*bufpp == NULL) {
914		listall(string, lp);
915		return(-1);
916	}
917	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
918		return(-1);
919	mib[3] = indx;
920	*typep = lp->list[indx].ctl_type;
921	return(4);
922}
923
924/*
925 * Scan a list of names searching for a particular name.
926 */
927int
928findname(string, level, bufp, namelist)
929	char *string;
930	char *level;
931	char **bufp;
932	struct list *namelist;
933{
934	char *name;
935	int i;
936
937	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
938		warnx("%s: incomplete specification", string);
939		return(-1);
940	}
941	for (i = 0; i < namelist->size; i++)
942		if (namelist->list[i].ctl_name != NULL &&
943		    strcmp(name, namelist->list[i].ctl_name) == 0)
944			break;
945	if (i == namelist->size) {
946		warnx("%s level name %s in %s is invalid", level, name, string);
947		return(-1);
948	}
949	return(i);
950}
951
952void
953usage()
954{
955
956	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
957	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
958	    "sysctl [-n] -a", "sysctl [-n] -A");
959	exit(1);
960}
961