sysctl.c revision 1.13
1126557Snjl/*	$OpenBSD: sysctl.c,v 1.13 1997/07/22 14:43:19 kstailey Exp $	*/
2126557Snjl/*	$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $	*/
3126557Snjl
4126557Snjl/*
5126557Snjl * Copyright (c) 1993
6126557Snjl *	The Regents of the University of California.  All rights reserved.
7126557Snjl *
8126557Snjl * Redistribution and use in source and binary forms, with or without
9126557Snjl * modification, are permitted provided that the following conditions
10126557Snjl * are met:
11126557Snjl * 1. Redistributions of source code must retain the above copyright
12126557Snjl *    notice, this list of conditions and the following disclaimer.
13126557Snjl * 2. Redistributions in binary form must reproduce the above copyright
14126557Snjl *    notice, this list of conditions and the following disclaimer in the
15126557Snjl *    documentation and/or other materials provided with the distribution.
16126557Snjl * 3. All advertising materials mentioning features or use of this software
17126557Snjl *    must display the following acknowledgement:
18126557Snjl *	This product includes software developed by the University of
19126557Snjl *	California, Berkeley and its contributors.
20126557Snjl * 4. Neither the name of the University nor the names of its contributors
21126557Snjl *    may be used to endorse or promote products derived from this software
22126557Snjl *    without specific prior written permission.
23126557Snjl *
24126557Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25126557Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26126557Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27126557Snjl * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28137439Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29126557Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30126557Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31126557Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32126557Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33126557Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34126557Snjl * SUCH DAMAGE.
35126557Snjl */
36126557Snjl
37126557Snjl#ifndef lint
38126557Snjlstatic char copyright[] =
39126557Snjl"@(#) Copyright (c) 1993\n\
40126557Snjl	The Regents of the University of California.  All rights reserved.\n";
41130650Sru#endif /* not lint */
42148066Shrs
43126557Snjl#ifndef lint
44130650Sru#if 0
45130650Srustatic char sccsid[] = "@(#)sysctl.c	8.1 (Berkeley) 6/6/93";
46130650Sru#else
47130650Srustatic char *rcsid = "$OpenBSD: sysctl.c,v 1.13 1997/07/22 14:43:19 kstailey Exp $";
48130650Sru#endif
49130650Sru#endif /* not lint */
50126557Snjl
51130650Sru#include <sys/param.h>
52137439Snjl#include <sys/gmon.h>
53130650Sru#include <sys/stat.h>
54126557Snjl#include <sys/sysctl.h>
55130650Sru#include <sys/socket.h>
56126557Snjl#include <vm/vm_param.h>
57130650Sru#include <machine/cpu.h>
58126557Snjl
59130650Sru#include <netinet/in.h>
60126557Snjl#include <netinet/in_systm.h>
61126557Snjl#include <netinet/ip.h>
62126557Snjl#include <netinet/ip_icmp.h>
63126557Snjl#include <netinet/icmp_var.h>
64126557Snjl#include <netinet/ip_var.h>
65126557Snjl#include <netinet/udp.h>
66126557Snjl#include <netinet/udp_var.h>
67126557Snjl#include <netinet/tcp.h>
68126557Snjl#include <netinet/tcp_timer.h>
69126557Snjl#include <netinet/tcp_var.h>
70126557Snjl
71126557Snjl#include <netipx/ipx.h>
72126557Snjl#include <netipx/ipx_var.h>
73126557Snjl#include <netipx/spx_var.h>
74126557Snjl#include <ddb/db_var.h>
75126557Snjl#include <dev/rndvar.h>
76126557Snjl#include <net/encap.h>
77126557Snjl#include <netinet/ip_ipsp.h>
78126557Snjl
79126557Snjl#include <errno.h>
80126557Snjl#include <stdio.h>
81267938Sbapt#include <stdlib.h>
82126557Snjl#include <string.h>
83267938Sbapt#include <ctype.h>
84137439Snjl
85137439Snjlstruct ctlname topname[] = CTL_NAMES;
86137439Snjlstruct ctlname kernname[] = CTL_KERN_NAMES;
87137439Snjlstruct ctlname vmname[] = CTL_VM_NAMES;
88137439Snjlstruct ctlname fsname[] = CTL_FS_NAMES;
89137439Snjlstruct ctlname netname[] = CTL_NET_NAMES;
90struct ctlname hwname[] = CTL_HW_NAMES;
91struct ctlname username[] = CTL_USER_NAMES;
92struct ctlname debugname[CTL_DEBUG_MAXID];
93#ifdef CTL_MACHDEP_NAMES
94struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
95#endif
96struct ctlname ddbname[] = CTL_DDB_NAMES;
97char names[BUFSIZ];
98
99struct list {
100	struct	ctlname *list;
101	int	size;
102};
103struct list toplist = { topname, CTL_MAXID };
104struct list secondlevel[] = {
105	{ 0, 0 },			/* CTL_UNSPEC */
106	{ kernname, KERN_MAXID },	/* CTL_KERN */
107	{ vmname, VM_MAXID },		/* CTL_VM */
108	{ fsname, FS_MAXID },		/* CTL_FS */
109	{ netname, NET_MAXID },		/* CTL_NET */
110	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
111	{ hwname, HW_MAXID },		/* CTL_HW */
112#ifdef CTL_MACHDEP_NAMES
113	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
114#else
115	{ 0, 0 },			/* CTL_MACHDEP */
116#endif
117	{ username, USER_MAXID },	/* CTL_USER_NAMES */
118	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
119};
120
121int	Aflag, aflag, nflag, wflag;
122
123/*
124 * Variables requiring special processing.
125 */
126#define	CLOCK		0x00000001
127#define	BOOTTIME	0x00000002
128#define	CONSDEV		0x00000004
129#define RNDSTATS	0x00000008
130
131/* prototypes */
132void usage();
133void debuginit();
134void parse __P((	char *string, int flags));
135void listall __P((char *prefix, 	struct list *lp));
136int findname __P((char *string, 	char *level, char **bufp, struct list *namelist));
137int sysctl_inet __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
138int sysctl_ipsec __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
139int sysctl_ipx __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
140int sysctl_fs __P((char *string, char **bufpp, 	int mib[], int flags, int *typep));
141
142int
143main(argc, argv)
144	int argc;
145	char *argv[];
146{
147	extern char *optarg;
148	extern int optind;
149	int ch, lvl1;
150
151	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
152		switch (ch) {
153
154		case 'A':
155			Aflag = 1;
156			break;
157
158		case 'a':
159			aflag = 1;
160			break;
161
162		case 'n':
163			nflag = 1;
164			break;
165
166		case 'w':
167			wflag = 1;
168			break;
169
170		default:
171			usage();
172		}
173	}
174	argc -= optind;
175	argv += optind;
176
177	if (Aflag || aflag) {
178		debuginit();
179		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
180			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
181		exit(0);
182	}
183	if (argc == 0)
184		usage();
185	while (argc-- > 0)
186		parse(*argv++, 1);
187	exit(0);
188}
189
190/*
191 * List all variables known to the system.
192 */
193void
194listall(prefix, lp)
195	char *prefix;
196	struct list *lp;
197{
198	int lvl2;
199	char *cp, name[BUFSIZ];
200
201	if (lp->list == 0)
202		return;
203	strncpy(name, prefix, BUFSIZ-1);
204	cp = &name[strlen(name)];
205	*cp++ = '.';
206	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
207		if (lp->list[lvl2].ctl_name == 0)
208			continue;
209		strcpy(cp, lp->list[lvl2].ctl_name);
210		parse(name, Aflag);
211	}
212}
213
214/*
215 * Parse a name into a MIB entry.
216 * Lookup and print out the MIB entry if it exists.
217 * Set a new value if requested.
218 */
219void
220parse(string, flags)
221	char *string;
222	int flags;
223{
224	int indx, type, state;
225	int special = 0;
226	void *newval = 0;
227	int intval, newsize = 0;
228	quad_t quadval;
229	size_t size, len;
230	struct list *lp;
231	int mib[CTL_MAXNAME];
232	char *cp, *bufp, buf[BUFSIZ];
233
234	bufp = buf;
235	snprintf(buf, BUFSIZ, "%s", string);
236	if ((cp = strchr(string, '=')) != NULL) {
237		if (!wflag) {
238			fprintf(stderr, "Must specify -w to set variables\n");
239			exit(2);
240		}
241		*strchr(buf, '=') = '\0';
242		*cp++ = '\0';
243		while (isspace(*cp))
244			cp++;
245		newval = cp;
246		newsize = strlen(cp);
247	}
248	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
249		return;
250	mib[0] = indx;
251	if (indx == CTL_DEBUG)
252		debuginit();
253	lp = &secondlevel[indx];
254	if (lp->list == 0) {
255		fprintf(stderr, "%s: class is not implemented\n",
256		    topname[indx].ctl_name);
257		return;
258	}
259	if (bufp == NULL) {
260		listall(topname[indx].ctl_name, lp);
261		return;
262	}
263	if ((indx = findname(string, "second", &bufp, lp)) == -1)
264		return;
265	mib[1] = indx;
266	type = lp->list[indx].ctl_type;
267	len = 2;
268	switch (mib[0]) {
269
270	case CTL_KERN:
271		switch (mib[1]) {
272		case KERN_PROF:
273			mib[2] = GPROF_STATE;
274			size = sizeof state;
275			if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
276				if (flags == 0)
277					return;
278				if (!nflag)
279					fprintf(stdout, "%s: ", string);
280				fprintf(stdout,
281				    "kernel is not compiled for profiling\n");
282				return;
283			}
284			if (!nflag)
285				fprintf(stdout, "%s = %s\n", string,
286				    state == GMON_PROF_OFF ? "off" : "running");
287			return;
288		case KERN_VNODE:
289		case KERN_FILE:
290			if (flags == 0)
291				return;
292			fprintf(stderr,
293			    "Use pstat to view %s information\n", string);
294			return;
295		case KERN_PROC:
296			if (flags == 0)
297				return;
298			fprintf(stderr,
299			    "Use ps to view %s information\n", string);
300			return;
301		case KERN_NTPTIME:
302			if (flags == 0)
303				return;
304			fprintf(stderr,
305			    "Use xntpd to view %s information\n", string);
306			return;
307		case KERN_CLOCKRATE:
308			special |= CLOCK;
309			break;
310		case KERN_BOOTTIME:
311			special |= BOOTTIME;
312			break;
313		case KERN_RND:
314			special |= RNDSTATS;
315			break;
316		}
317		break;
318
319	case CTL_HW:
320		break;
321
322	case CTL_VM:
323		if (mib[1] == VM_LOADAVG) {
324			double loads[3];
325
326			getloadavg(loads, 3);
327			if (!nflag)
328				fprintf(stdout, "%s = ", string);
329			fprintf(stdout, "%.2f %.2f %.2f\n",
330			    loads[0], loads[1], loads[2]);
331			return;
332		} else if (mib[1] == VM_PSSTRINGS) {
333			struct _ps_strings _ps;
334
335			len = sizeof(_ps);
336			sysctl(mib, 2, &_ps, &len, NULL, 0);
337			if (!nflag)
338				fprintf(stdout, "%s = ", string);
339			fprintf(stdout, "%ld\n", _ps.val);
340			return;
341		}
342		if (flags == 0)
343			return;
344		fprintf(stderr,
345		    "Use vmstat or systat to view %s information\n", string);
346		return;
347
348	case CTL_NET:
349		if (mib[1] == PF_INET) {
350			len = sysctl_inet(string, &bufp, mib, flags, &type);
351			if (len >= 0)
352				break;
353			return;
354		}
355		if (mib[1] == PF_IPX) {
356			len = sysctl_ipx(string, &bufp, mib, flags, &type);
357			if (len >= 0)
358				break;
359			return;
360		}
361		if (mib[1] == PF_ENCAP) {
362			len = sysctl_ipsec(string, &bufp, mib, flags, &type);
363			if (len >= 0)
364				break;
365			return;
366		}
367		if (flags == 0)
368			return;
369		fprintf(stderr, "Use netstat to view %s information\n", string);
370		return;
371
372	case CTL_DEBUG:
373		mib[2] = CTL_DEBUG_VALUE;
374		len = 3;
375		break;
376
377	case CTL_MACHDEP:
378#ifdef CPU_CONSDEV
379		if (mib[1] == CPU_CONSDEV)
380			special |= CONSDEV;
381#endif
382		break;
383
384	case CTL_FS:
385		len = sysctl_fs(string, &bufp, mib, flags, &type);
386		if (len >= 0)
387			break;
388		return;
389
390	case CTL_USER:
391	case CTL_DDB:
392		break;
393
394	default:
395		fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
396		return;
397
398	}
399	if (bufp) {
400		fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
401		return;
402	}
403	if (newsize > 0) {
404		switch (type) {
405		case CTLTYPE_INT:
406			intval = atoi(newval);
407			newval = &intval;
408			newsize = sizeof intval;
409			break;
410
411		case CTLTYPE_QUAD:
412			sscanf(newval, "%qd", &quadval);
413			newval = &quadval;
414			newsize = sizeof quadval;
415			break;
416		}
417	}
418	size = BUFSIZ;
419	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
420		if (flags == 0)
421			return;
422		switch (errno) {
423		case EOPNOTSUPP:
424			fprintf(stderr, "%s: value is not available\n", string);
425			return;
426		case ENOTDIR:
427			fprintf(stderr, "%s: specification is incomplete\n",
428			    string);
429			return;
430		case ENOMEM:
431			fprintf(stderr, "%s: type is unknown to this program\n",
432			    string);
433			return;
434		default:
435			perror(string);
436			return;
437		}
438	}
439	if (special & CLOCK) {
440		struct clockinfo *clkp = (struct clockinfo *)buf;
441
442		if (!nflag)
443			fprintf(stdout, "%s = ", string);
444		fprintf(stdout,
445		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
446		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
447		return;
448	}
449	if (special & BOOTTIME) {
450		struct timeval *btp = (struct timeval *)buf;
451		time_t boottime;
452
453		if (!nflag) {
454			boottime = btp->tv_sec;
455			fprintf(stdout, "%s = %s\n", string, ctime(&boottime));
456		} else
457			fprintf(stdout, "%ld\n", btp->tv_sec);
458		return;
459	}
460	if (special & CONSDEV) {
461		dev_t dev = *(dev_t *)buf;
462
463		if (!nflag)
464			fprintf(stdout, "%s = %s\n", string,
465			    devname(dev, S_IFCHR));
466		else
467			fprintf(stdout, "0x%x\n", dev);
468		return;
469	}
470	if (special & RNDSTATS) {
471		struct rndstats *rndstats = (struct rndstats *)buf;
472		if (!nflag)
473			fprintf(stdout, "%s = ", string);
474		fprintf(stdout,
475		    "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
476		    rndstats->rnd_total, rndstats->rnd_used,
477		    rndstats->arc4_reads, rndstats->rnd_timer,
478		    rndstats->rnd_mouse, rndstats->rnd_tty,
479		    rndstats->rnd_disk, rndstats->rnd_net,
480		    rndstats->rnd_reads, rndstats->rnd_waits,
481		    rndstats->rnd_enqs, rndstats->rnd_deqs,
482		    rndstats->rnd_drops, rndstats->rnd_drople,
483		    rndstats->rnd_asleep, rndstats->rnd_queued);
484		return;
485	}
486	switch (type) {
487	case CTLTYPE_INT:
488		if (newsize == 0) {
489			if (!nflag)
490				fprintf(stdout, "%s = ", string);
491			fprintf(stdout, "%d\n", *(int *)buf);
492		} else {
493			if (!nflag)
494				fprintf(stdout, "%s: %d -> ", string,
495				    *(int *)buf);
496			fprintf(stdout, "%d\n", *(int *)newval);
497		}
498		return;
499
500	case CTLTYPE_STRING:
501		if (newsize == 0) {
502			if (!nflag)
503				fprintf(stdout, "%s = ", string);
504			fprintf(stdout, "%s\n", buf);
505		} else {
506			if (!nflag)
507				fprintf(stdout, "%s: %s -> ", string, buf);
508			fprintf(stdout, "%s\n", (char *)newval);
509		}
510		return;
511
512	case CTLTYPE_QUAD:
513		if (newsize == 0) {
514			if (!nflag)
515				fprintf(stdout, "%s = ", string);
516			fprintf(stdout, "%qd\n", *(quad_t *)buf);
517		} else {
518			if (!nflag)
519				fprintf(stdout, "%s: %qd -> ", string,
520				    *(quad_t *)buf);
521			fprintf(stdout, "%qd\n", *(quad_t *)newval);
522		}
523		return;
524
525	case CTLTYPE_STRUCT:
526		fprintf(stderr, "%s: unknown structure returned\n",
527		    string);
528		return;
529
530	default:
531	case CTLTYPE_NODE:
532		fprintf(stderr, "%s: unknown type returned\n",
533		    string);
534		return;
535	}
536}
537
538/*
539 * Initialize the set of debugging names
540 */
541void
542debuginit()
543{
544	int mib[3], loc, i;
545	size_t size;
546
547	if (secondlevel[CTL_DEBUG].list != 0)
548		return;
549	secondlevel[CTL_DEBUG].list = debugname;
550	mib[0] = CTL_DEBUG;
551	mib[2] = CTL_DEBUG_NAME;
552	for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
553		mib[1] = i;
554		size = BUFSIZ - loc;
555		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
556			continue;
557		debugname[i].ctl_name = &names[loc];
558		debugname[i].ctl_type = CTLTYPE_INT;
559		loc += size;
560	}
561}
562
563struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
564struct list fslist = { posixname, FS_POSIX_MAXID };
565
566/*
567 * handle file system requests
568 */
569int
570sysctl_fs(string, bufpp, mib, flags, typep)
571	char *string;
572	char **bufpp;
573	int mib[];
574	int flags;
575	int *typep;
576{
577	int indx;
578
579	if (*bufpp == NULL) {
580		listall(string, &fslist);
581		return (-1);
582	}
583	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
584		return (-1);
585	mib[2] = indx;
586	*typep = fslist.list[indx].ctl_type;
587	return (3);
588}
589
590struct ctlname encapname[] = ENCAPCTL_NAMES;
591struct ctlname ipsecname[] = CTL_IPSEC_NAMES;
592struct list ipseclist = { ipsecname, IPSECCTL_MAXID };
593struct list ipsecvars[] = {
594        { encapname, ENCAPCTL_MAXID },
595};
596
597/*
598 * handle ipsec requests
599 */
600int
601sysctl_ipsec(string, bufpp, mib, flags, typep)
602	char *string;
603        char **bufpp;
604        int mib[];
605        int flags;
606        int *typep;
607{
608        struct list *lp;
609        int indx;
610
611        if (*bufpp == NULL) {
612                listall(string, &ipseclist);
613                return (-1);
614        }
615        if ((indx = findname(string, "third", bufpp, &ipseclist)) == -1)
616                return (-1);
617        mib[2] = indx;
618	if (indx <= IPSECCTL_MAXID && ipsecvars[indx].list != NULL)
619	 	lp = &ipsecvars[indx];
620	else if (!flags)
621		return (-1);
622	else {
623		fprintf(stderr, "%s: no variables defined for this protocol\n",
624		    string);
625		return (-1);
626	}
627        if (*bufpp == NULL) {
628                listall(string, lp);
629                return (-1);
630        }
631        if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
632                return (-1);
633        mib[3] = indx;
634        *typep = lp->list[indx].ctl_type;
635        return (4);
636}
637
638struct ctlname inetname[] = CTL_IPPROTO_NAMES;
639struct ctlname ipname[] = IPCTL_NAMES;
640struct ctlname icmpname[] = ICMPCTL_NAMES;
641struct ctlname tcpname[] = TCPCTL_NAMES;
642struct ctlname udpname[] = UDPCTL_NAMES;
643struct list inetlist = { inetname, IPPROTO_MAXID };
644struct list inetvars[] = {
645	{ ipname, IPCTL_MAXID },	/* ip */
646	{ icmpname, ICMPCTL_MAXID },	/* icmp */
647	{ 0, 0 },			/* igmp */
648	{ 0, 0 },			/* ggmp */
649	{ 0, 0 },
650	{ 0, 0 },
651	{ tcpname, TCPCTL_MAXID },	/* tcp */
652	{ 0, 0 },
653	{ 0, 0 },			/* egp */
654	{ 0, 0 },
655	{ 0, 0 },
656	{ 0, 0 },
657	{ 0, 0 },			/* pup */
658	{ 0, 0 },
659	{ 0, 0 },
660	{ 0, 0 },
661	{ 0, 0 },
662	{ udpname, UDPCTL_MAXID },	/* udp */
663};
664
665/*
666 * handle internet requests
667 */
668int
669sysctl_inet(string, bufpp, mib, flags, typep)
670	char *string;
671	char **bufpp;
672	int mib[];
673	int flags;
674	int *typep;
675{
676	struct list *lp;
677	int indx;
678
679	if (*bufpp == NULL) {
680		listall(string, &inetlist);
681		return (-1);
682	}
683	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
684		return (-1);
685	mib[2] = indx;
686	if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
687		lp = &inetvars[indx];
688	else if (!flags)
689		return (-1);
690	else {
691		fprintf(stderr, "%s: no variables defined for this protocol\n",
692		    string);
693		return (-1);
694	}
695	if (*bufpp == NULL) {
696		listall(string, lp);
697		return (-1);
698	}
699	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
700		return (-1);
701	mib[3] = indx;
702	*typep = lp->list[indx].ctl_type;
703	return (4);
704}
705
706struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
707struct ctlname ipxpname[] = IPXCTL_NAMES;
708struct ctlname spxpname[] = SPXCTL_NAMES;
709struct list ipxlist = { ipxname, IPXCTL_MAXID };
710struct list ipxvars[] = {
711	{ ipxpname, IPXCTL_MAXID },	/* ipx */
712	{ 0, 0 },
713	{ 0, 0 },
714	{ 0, 0 },
715	{ 0, 0 },
716	{ spxpname, SPXCTL_MAXID },
717};
718
719/*
720 * handle internet requests
721 */
722int
723sysctl_ipx(string, bufpp, mib, flags, typep)
724	char *string;
725	char **bufpp;
726	int mib[];
727	int flags;
728	int *typep;
729{
730	struct list *lp;
731	int indx;
732
733	if (*bufpp == NULL) {
734		listall(string, &ipxlist);
735		return (-1);
736	}
737	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
738		return (-1);
739	mib[2] = indx;
740	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
741		lp = &ipxvars[indx];
742	else if (!flags)
743		return (-1);
744	else {
745		fprintf(stderr, "%s: no variables defined for this protocol\n",
746		    string);
747		return (-1);
748	}
749	if (*bufpp == NULL) {
750		listall(string, lp);
751		return (-1);
752	}
753	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
754		return (-1);
755	mib[3] = indx;
756	*typep = lp->list[indx].ctl_type;
757	return (4);
758}
759
760/*
761 * Scan a list of names searching for a particular name.
762 */
763int
764findname(string, level, bufp, namelist)
765	char *string;
766	char *level;
767	char **bufp;
768	struct list *namelist;
769{
770	char *name;
771	int i;
772
773	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
774		fprintf(stderr, "%s: incomplete specification\n", string);
775		return (-1);
776	}
777	for (i = 0; i < namelist->size; i++)
778		if (namelist->list[i].ctl_name != NULL &&
779		    strcmp(name, namelist->list[i].ctl_name) == 0)
780			break;
781	if (i == namelist->size) {
782		fprintf(stderr, "%s level name %s in %s is invalid\n",
783		    level, name, string);
784		return (-1);
785	}
786	return (i);
787}
788
789void
790usage()
791{
792
793	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
794	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
795	    "sysctl [-n] -a", "sysctl [-n] -A");
796	exit(1);
797}
798