sysctl.c revision 1.15
1/*	$OpenBSD: sysctl.c,v 1.15 1997/08/09 23:36: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.15 1997/08/09 23:36: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();
137void debuginit();
138void parse __P((	char *string, int flags));
139void listall __P((char *prefix, 	struct list *lp));
140int findname __P((char *string, 	char *level, char **bufp, struct list *namelist));
141int sysctl_inet __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
142int sysctl_ipsec __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
143int sysctl_ipx __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
144int sysctl_fs __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
145
146int
147main(argc, argv)
148	int argc;
149	char *argv[];
150{
151	extern char *optarg;
152	extern int optind;
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	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		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	bufp = buf;
239	snprintf(buf, BUFSIZ, "%s", string);
240	if ((cp = strchr(string, '=')) != NULL) {
241		if (!wflag) {
242			fprintf(stderr, "Must specify -w to set variables\n");
243			exit(2);
244		}
245		*strchr(buf, '=') = '\0';
246		*cp++ = '\0';
247		while (isspace(*cp))
248			cp++;
249		newval = cp;
250		newsize = strlen(cp);
251	}
252	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
253		return;
254	mib[0] = indx;
255	if (indx == CTL_DEBUG)
256		debuginit();
257	lp = &secondlevel[indx];
258	if (lp->list == 0) {
259		fprintf(stderr, "%s: class is not implemented\n",
260		    topname[indx].ctl_name);
261		return;
262	}
263	if (bufp == NULL) {
264		listall(topname[indx].ctl_name, lp);
265		return;
266	}
267	if ((indx = findname(string, "second", &bufp, lp)) == -1)
268		return;
269	mib[1] = indx;
270	type = lp->list[indx].ctl_type;
271	len = 2;
272	switch (mib[0]) {
273
274	case CTL_KERN:
275		switch (mib[1]) {
276		case KERN_PROF:
277			mib[2] = GPROF_STATE;
278			size = sizeof state;
279			if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
280				if (flags == 0)
281					return;
282				if (!nflag)
283					fprintf(stdout, "%s: ", string);
284				fprintf(stdout,
285				    "kernel is not compiled for profiling\n");
286				return;
287			}
288			if (!nflag)
289				fprintf(stdout, "%s = %s\n", string,
290				    state == GMON_PROF_OFF ? "off" : "running");
291			return;
292		case KERN_VNODE:
293		case KERN_FILE:
294			if (flags == 0)
295				return;
296			fprintf(stderr,
297			    "Use pstat to view %s information\n", string);
298			return;
299		case KERN_PROC:
300			if (flags == 0)
301				return;
302			fprintf(stderr,
303			    "Use ps to view %s information\n", string);
304			return;
305		case KERN_NTPTIME:
306			if (flags == 0)
307				return;
308			fprintf(stderr,
309			    "Use xntpd to view %s information\n", 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				fprintf(stdout, "%s = ", string);
333			fprintf(stdout, "%.2f %.2f %.2f\n",
334			    loads[0], loads[1], loads[2]);
335			return;
336		} else if (mib[1] == VM_PSSTRINGS) {
337			struct _ps_strings _ps;
338
339			len = sizeof(_ps);
340			sysctl(mib, 2, &_ps, &len, NULL, 0);
341			if (!nflag)
342				fprintf(stdout, "%s = ", string);
343			fprintf(stdout, "%ld\n", _ps.val);
344			return;
345		}
346		if (flags == 0)
347			return;
348		fprintf(stderr,
349		    "Use vmstat or systat to view %s information\n", 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			if (mib[3] == TCPCTL_BADDYNAMIC ||
358			    mib[3] == UDPCTL_BADDYNAMIC) {
359				u_int32_t newbaddynamic[DP_MAPSIZE];
360				in_port_t port;
361
362				special |= BADDYNAMIC;
363				if (newval != NULL) {
364					(void)memset((void *)&newbaddynamic, 0,
365					    sizeof(newbaddynamic));
366					while (newval &&
367					    (cp = strsep((char **)&newval,
368					    ", \t")) && *cp) {
369						port = atoi(cp);
370						if (port < IPPORT_RESERVED/2 ||
371						    port >= IPPORT_RESERVED)
372							errx(1, "invalid port, "
373							    "range is %d to %d",
374							    IPPORT_RESERVED/2,
375							    IPPORT_RESERVED-1);
376						DP_SET(newbaddynamic, port);
377					}
378					newval = (void *)newbaddynamic;
379					newsize = sizeof(newbaddynamic);
380				}
381			}
382			break;
383		}
384		if (mib[1] == PF_IPX) {
385			len = sysctl_ipx(string, &bufp, mib, flags, &type);
386			if (len >= 0)
387				break;
388			return;
389		}
390		if (mib[1] == PF_ENCAP) {
391			len = sysctl_ipsec(string, &bufp, mib, flags, &type);
392			if (len >= 0)
393				break;
394			return;
395		}
396		if (flags == 0)
397			return;
398		fprintf(stderr, "Use netstat to view %s information\n", string);
399		return;
400
401	case CTL_DEBUG:
402		mib[2] = CTL_DEBUG_VALUE;
403		len = 3;
404		break;
405
406	case CTL_MACHDEP:
407#ifdef CPU_CONSDEV
408		if (mib[1] == CPU_CONSDEV)
409			special |= CONSDEV;
410#endif
411		break;
412
413	case CTL_FS:
414		len = sysctl_fs(string, &bufp, mib, flags, &type);
415		if (len >= 0)
416			break;
417		return;
418
419	case CTL_USER:
420	case CTL_DDB:
421		break;
422
423	default:
424		fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
425		return;
426
427	}
428	if (bufp) {
429		fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
430		return;
431	}
432	if (newsize > 0) {
433		switch (type) {
434		case CTLTYPE_INT:
435			intval = atoi(newval);
436			newval = &intval;
437			newsize = sizeof intval;
438			break;
439
440		case CTLTYPE_QUAD:
441			sscanf(newval, "%qd", &quadval);
442			newval = &quadval;
443			newsize = sizeof quadval;
444			break;
445		}
446	}
447	size = BUFSIZ;
448	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
449		if (flags == 0)
450			return;
451		switch (errno) {
452		case EOPNOTSUPP:
453			fprintf(stderr, "%s: value is not available\n", string);
454			return;
455		case ENOTDIR:
456			fprintf(stderr, "%s: specification is incomplete\n",
457			    string);
458			return;
459		case ENOMEM:
460			fprintf(stderr, "%s: type is unknown to this program\n",
461			    string);
462			return;
463		default:
464			perror(string);
465			return;
466		}
467	}
468	if (special & CLOCK) {
469		struct clockinfo *clkp = (struct clockinfo *)buf;
470
471		if (!nflag)
472			fprintf(stdout, "%s = ", string);
473		fprintf(stdout,
474		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
475		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
476		return;
477	}
478	if (special & BOOTTIME) {
479		struct timeval *btp = (struct timeval *)buf;
480		time_t boottime;
481
482		if (!nflag) {
483			boottime = btp->tv_sec;
484			fprintf(stdout, "%s = %s\n", string, ctime(&boottime));
485		} else
486			fprintf(stdout, "%ld\n", btp->tv_sec);
487		return;
488	}
489	if (special & CONSDEV) {
490		dev_t dev = *(dev_t *)buf;
491
492		if (!nflag)
493			fprintf(stdout, "%s = %s\n", string,
494			    devname(dev, S_IFCHR));
495		else
496			fprintf(stdout, "0x%x\n", dev);
497		return;
498	}
499	if (special & RNDSTATS) {
500		struct rndstats *rndstats = (struct rndstats *)buf;
501		if (!nflag)
502			fprintf(stdout, "%s = ", string);
503		fprintf(stdout,
504		    "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
505		    rndstats->rnd_total, rndstats->rnd_used,
506		    rndstats->arc4_reads, rndstats->rnd_timer,
507		    rndstats->rnd_mouse, rndstats->rnd_tty,
508		    rndstats->rnd_disk, rndstats->rnd_net,
509		    rndstats->rnd_reads, rndstats->rnd_waits,
510		    rndstats->rnd_enqs, rndstats->rnd_deqs,
511		    rndstats->rnd_drops, rndstats->rnd_drople,
512		    rndstats->rnd_asleep, rndstats->rnd_queued);
513		return;
514	}
515	if (special & BADDYNAMIC) {
516		in_port_t port;
517		u_int32_t *baddynamic = (u_int32_t *)buf;
518
519		if (!nflag)
520			printf("%s%s", string, newsize ? ":" : " =");
521		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
522			if (DP_ISSET(baddynamic, port))
523				printf(" %hd", port);
524		if (newsize != 0) {
525			if (!nflag)
526				fputs(" ->", stdout);
527			baddynamic = (u_int32_t *)newval;
528			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
529			    port++)
530				if (DP_ISSET(baddynamic, port))
531					printf(" %hd", port);
532		}
533		putchar('\n');
534		return;
535	}
536	switch (type) {
537	case CTLTYPE_INT:
538		if (newsize == 0) {
539			if (!nflag)
540				fprintf(stdout, "%s = ", string);
541			fprintf(stdout, "%d\n", *(int *)buf);
542		} else {
543			if (!nflag)
544				fprintf(stdout, "%s: %d -> ", string,
545				    *(int *)buf);
546			fprintf(stdout, "%d\n", *(int *)newval);
547		}
548		return;
549
550	case CTLTYPE_STRING:
551		if (newsize == 0) {
552			if (!nflag)
553				fprintf(stdout, "%s = ", string);
554			fprintf(stdout, "%s\n", buf);
555		} else {
556			if (!nflag)
557				fprintf(stdout, "%s: %s -> ", string, buf);
558			fprintf(stdout, "%s\n", (char *)newval);
559		}
560		return;
561
562	case CTLTYPE_QUAD:
563		if (newsize == 0) {
564			if (!nflag)
565				fprintf(stdout, "%s = ", string);
566			fprintf(stdout, "%qd\n", *(quad_t *)buf);
567		} else {
568			if (!nflag)
569				fprintf(stdout, "%s: %qd -> ", string,
570				    *(quad_t *)buf);
571			fprintf(stdout, "%qd\n", *(quad_t *)newval);
572		}
573		return;
574
575	case CTLTYPE_STRUCT:
576		fprintf(stderr, "%s: unknown structure returned\n",
577		    string);
578		return;
579
580	default:
581	case CTLTYPE_NODE:
582		fprintf(stderr, "%s: unknown type returned\n",
583		    string);
584		return;
585	}
586}
587
588/*
589 * Initialize the set of debugging names
590 */
591void
592debuginit()
593{
594	int mib[3], loc, i;
595	size_t size;
596
597	if (secondlevel[CTL_DEBUG].list != 0)
598		return;
599	secondlevel[CTL_DEBUG].list = debugname;
600	mib[0] = CTL_DEBUG;
601	mib[2] = CTL_DEBUG_NAME;
602	for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
603		mib[1] = i;
604		size = BUFSIZ - loc;
605		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
606			continue;
607		debugname[i].ctl_name = &names[loc];
608		debugname[i].ctl_type = CTLTYPE_INT;
609		loc += size;
610	}
611}
612
613struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
614struct list fslist = { posixname, FS_POSIX_MAXID };
615
616/*
617 * handle file system requests
618 */
619int
620sysctl_fs(string, bufpp, mib, flags, typep)
621	char *string;
622	char **bufpp;
623	int mib[];
624	int flags;
625	int *typep;
626{
627	int indx;
628
629	if (*bufpp == NULL) {
630		listall(string, &fslist);
631		return (-1);
632	}
633	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
634		return (-1);
635	mib[2] = indx;
636	*typep = fslist.list[indx].ctl_type;
637	return (3);
638}
639
640struct ctlname encapname[] = ENCAPCTL_NAMES;
641struct ctlname ipsecname[] = CTL_IPSEC_NAMES;
642struct list ipseclist = { ipsecname, IPSECCTL_MAXID };
643struct list ipsecvars[] = {
644	{ encapname, ENCAPCTL_MAXID },
645};
646
647/*
648 * handle ipsec requests
649 */
650int
651sysctl_ipsec(string, bufpp, mib, flags, typep)
652	char *string;
653	char **bufpp;
654	int mib[];
655	int flags;
656	int *typep;
657{
658	struct list *lp;
659	int indx;
660
661	if (*bufpp == NULL) {
662		listall(string, &ipseclist);
663		return (-1);
664	}
665	if ((indx = findname(string, "third", bufpp, &ipseclist)) == -1)
666		return (-1);
667	mib[2] = indx;
668	if (indx <= IPSECCTL_MAXID && ipsecvars[indx].list != NULL)
669		lp = &ipsecvars[indx];
670	else if (!flags)
671		return (-1);
672	else {
673		fprintf(stderr, "%s: no variables defined for this protocol\n",
674		    string);
675		return (-1);
676	}
677	if (*bufpp == NULL) {
678		listall(string, lp);
679		return (-1);
680	}
681	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
682		return (-1);
683	mib[3] = indx;
684	*typep = lp->list[indx].ctl_type;
685	return (4);
686}
687
688struct ctlname inetname[] = CTL_IPPROTO_NAMES;
689struct ctlname ipname[] = IPCTL_NAMES;
690struct ctlname icmpname[] = ICMPCTL_NAMES;
691struct ctlname tcpname[] = TCPCTL_NAMES;
692struct ctlname udpname[] = UDPCTL_NAMES;
693struct list inetlist = { inetname, IPPROTO_MAXID };
694struct list inetvars[] = {
695	{ ipname, IPCTL_MAXID },	/* ip */
696	{ icmpname, ICMPCTL_MAXID },	/* icmp */
697	{ 0, 0 },			/* igmp */
698	{ 0, 0 },			/* ggmp */
699	{ 0, 0 },
700	{ 0, 0 },
701	{ tcpname, TCPCTL_MAXID },	/* tcp */
702	{ 0, 0 },
703	{ 0, 0 },			/* egp */
704	{ 0, 0 },
705	{ 0, 0 },
706	{ 0, 0 },
707	{ 0, 0 },			/* pup */
708	{ 0, 0 },
709	{ 0, 0 },
710	{ 0, 0 },
711	{ 0, 0 },
712	{ udpname, UDPCTL_MAXID },	/* udp */
713};
714
715/*
716 * handle internet requests
717 */
718int
719sysctl_inet(string, bufpp, mib, flags, typep)
720	char *string;
721	char **bufpp;
722	int mib[];
723	int flags;
724	int *typep;
725{
726	struct list *lp;
727	int indx;
728
729	if (*bufpp == NULL) {
730		listall(string, &inetlist);
731		return (-1);
732	}
733	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
734		return (-1);
735	mib[2] = indx;
736	if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
737		lp = &inetvars[indx];
738	else if (!flags)
739		return (-1);
740	else {
741		fprintf(stderr, "%s: no variables defined for this protocol\n",
742		    string);
743		return (-1);
744	}
745	if (*bufpp == NULL) {
746		listall(string, lp);
747		return (-1);
748	}
749	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
750		return (-1);
751	mib[3] = indx;
752	*typep = lp->list[indx].ctl_type;
753	return (4);
754}
755
756struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
757struct ctlname ipxpname[] = IPXCTL_NAMES;
758struct ctlname spxpname[] = SPXCTL_NAMES;
759struct list ipxlist = { ipxname, IPXCTL_MAXID };
760struct list ipxvars[] = {
761	{ ipxpname, IPXCTL_MAXID },	/* ipx */
762	{ 0, 0 },
763	{ 0, 0 },
764	{ 0, 0 },
765	{ 0, 0 },
766	{ spxpname, SPXCTL_MAXID },
767};
768
769/*
770 * handle internet requests
771 */
772int
773sysctl_ipx(string, bufpp, mib, flags, typep)
774	char *string;
775	char **bufpp;
776	int mib[];
777	int flags;
778	int *typep;
779{
780	struct list *lp;
781	int indx;
782
783	if (*bufpp == NULL) {
784		listall(string, &ipxlist);
785		return (-1);
786	}
787	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
788		return (-1);
789	mib[2] = indx;
790	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
791		lp = &ipxvars[indx];
792	else if (!flags)
793		return (-1);
794	else {
795		fprintf(stderr, "%s: no variables defined for this protocol\n",
796		    string);
797		return (-1);
798	}
799	if (*bufpp == NULL) {
800		listall(string, lp);
801		return (-1);
802	}
803	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
804		return (-1);
805	mib[3] = indx;
806	*typep = lp->list[indx].ctl_type;
807	return (4);
808}
809
810/*
811 * Scan a list of names searching for a particular name.
812 */
813int
814findname(string, level, bufp, namelist)
815	char *string;
816	char *level;
817	char **bufp;
818	struct list *namelist;
819{
820	char *name;
821	int i;
822
823	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
824		fprintf(stderr, "%s: incomplete specification\n", string);
825		return (-1);
826	}
827	for (i = 0; i < namelist->size; i++)
828		if (namelist->list[i].ctl_name != NULL &&
829		    strcmp(name, namelist->list[i].ctl_name) == 0)
830			break;
831	if (i == namelist->size) {
832		fprintf(stderr, "%s level name %s in %s is invalid\n",
833		    level, name, string);
834		return (-1);
835	}
836	return (i);
837}
838
839void
840usage()
841{
842
843	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
844	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
845	    "sysctl [-n] -a", "sysctl [-n] -A");
846	exit(1);
847}
848