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