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