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