xref: /original-bsd/usr.sbin/sysctl/sysctl.c (revision 48611f03)
1 /*
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1993 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)sysctl.c	5.3 (Berkeley) 04/01/93";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/sysctl.h>
21 #include <sys/socket.h>
22 #include <vm/vm_param.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 
28 char *topname[] = CTL_NAMES;
29 char *kernname[] = CTL_KERN_NAMES;
30 char *vmname[] = CTL_VM_NAMES;
31 char *netname[] = CTL_NET_NAMES;
32 char *hwname[] = CTL_HW_NAMES;
33 
34 struct list {
35 	char	**list;
36 	int	size;
37 } secondlevel[] = {
38 	{ 0, 0 },			/* CTL_UNSPEC */
39 	{ kernname, KERN_MAXID },	/* CTL_KERN */
40 	{ vmname, VM_MAXID },		/* CTL_VM */
41 	{ 0, 0 },			/* CTL_FS */
42 	{ netname, NET_MAXID },		/* CTL_NET */
43 	{ 0, 0 },			/* CTL_DEBUG */
44 	{ hwname, HW_MAXID },		/* CTL_HW */
45 	{ 0, 0 },			/* CTL_MACHDEP */
46 };
47 
48 int	Aflag, aflag, nflag, wflag;
49 
50 int
51 main(argc, argv)
52 	int argc;
53 	char *argv[];
54 {
55 	extern char *optarg;
56 	extern int optind;
57 	int ch, lvl1;
58 
59 	while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
60 		switch (ch) {
61 
62 		case 'A':
63 			Aflag = 1;
64 			break;
65 
66 		case 'a':
67 			aflag = 1;
68 			break;
69 
70 		case 'n':
71 			nflag = 1;
72 			break;
73 
74 		case 'w':
75 			wflag = 1;
76 			break;
77 
78 		default:
79 			usage();
80 		}
81 	}
82 	argc -= optind;
83 	argv += optind;
84 
85 	if (Aflag || aflag) {
86 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
87 			listall(lvl1);
88 		exit(0);
89 	}
90 	if (argc == 0)
91 		usage();
92 	while (argc-- > 0)
93 		parse(*argv, 1);
94 	exit(0);
95 }
96 
97 /*
98  * List all variables known to the system.
99  */
100 listall(lvl1)
101 	int lvl1;
102 {
103 	struct list *lp;
104 	int lvl2;
105 	char *cp, name[BUFSIZ];
106 
107 	lp = &secondlevel[lvl1];
108 	if (lp->list == 0)
109 		return;
110 	strcpy(name, topname[lvl1]);
111 	cp = &name[strlen(name)];
112 	*cp++ = '.';
113 	for (lvl2 = 1; lvl2 < lp->size; lvl2++) {
114 		strcpy(cp, lp->list[lvl2]);
115 		parse(name, Aflag);
116 	}
117 }
118 
119 /*
120  * Parse a name into a MIB entry.
121  * Lookup and print out the MIB entry if it exists.
122  * Set a new value if requested.
123  */
124 parse(string, flags)
125 	char *string;
126 	int flags;
127 {
128 	int indx, size;
129 	int isclockrate = 0;
130 	void *newval = 0;
131 	int intval, newsize = 0;
132 	struct list top, *lp;
133 	int mib[CTL_MAXNAME];
134 	char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
135 
136 	bufp = buf;
137 	snprintf(buf, BUFSIZ, "%s", string);
138 	if ((cp = strchr(string, '=')) != NULL) {
139 		if (!wflag) {
140 			fprintf(stderr, "Must specify -w to set variables\n");
141 			exit(2);
142 		}
143 		*strchr(buf, '=') = '\0';
144 		*cp++ = '\0';
145 		while (isspace(*cp))
146 			cp++;
147 		if (isdigit(*cp)) {
148 			intval = atoi(cp);
149 			newval = &intval;
150 			newsize = sizeof intval;
151 		} else {
152 			newval = cp;
153 			newsize = strlen(cp);
154 		}
155 	}
156 	top.list = topname;
157 	top.size = CTL_MAXID;
158 	if ((indx = findname(string, "top", &bufp, &top)) == -1)
159 		return;
160 	mib[0] = indx;
161 	lp = &secondlevel[indx];
162 	if (lp->list == 0) {
163 		fprintf(stderr, "%s: class is not implemented\n",
164 		    topname[indx]);
165 		return;
166 	}
167 	if (bufp == NULL) {
168 		listall(indx);
169 		return;
170 	}
171 	if ((indx = findname(string, "second", &bufp, lp)) == -1)
172 		return;
173 	mib[1] = indx;
174 	if (bufp) {
175 		fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
176 		return;
177 	}
178 	switch (mib[0]) {
179 
180 	case CTL_KERN:
181 		switch (mib[1]) {
182 		case KERN_VNODE:
183 		case KERN_FILE:
184 			if (flags == 0)
185 				return;
186 			fprintf(stderr,
187 			    "Use pstat to view %s information\n", string);
188 			return;
189 		case KERN_PROC:
190 			if (flags == 0)
191 				return;
192 			fprintf(stderr,
193 			    "Use ps to view %s information\n", string);
194 			return;
195 		case KERN_CLOCKRATE:
196 			isclockrate = 1;
197 			break;
198 		}
199 		break;
200 
201 	case CTL_HW:
202 		break;
203 
204 	case CTL_VM:
205 		if (mib[1] == VM_LOADAVG) {
206 			double loads[3];
207 
208 			getloadavg(loads, 3);
209 			if (!nflag)
210 				fprintf(stdout, "%s: ", string);
211 			fprintf(stdout, "%.2f %.2f %.2f\n",
212 			    loads[0], loads[1], loads[2]);
213 			return;
214 		}
215 		if (flags == 0)
216 			return;
217 		fprintf(stderr,
218 		    "Use vmstat or systat to view %s information\n", string);
219 		return;
220 
221 	case CTL_NET:
222 		if (flags == 0)
223 			return;
224 		fprintf(stderr, "Use netstat to view %s information\n", string);
225 		return;
226 
227 	case CTL_FS:
228 	case CTL_DEBUG:
229 	case CTL_MACHDEP:
230 		break;
231 
232 	default:
233 		fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
234 		return;
235 
236 	}
237 
238 	size = BUFSIZ;
239 	if (sysctl(mib, 2, buf, &size, newsize ? newval : 0, newsize) == -1) {
240 		if (flags == 0)
241 			return;
242 		switch (errno) {
243 		case EOPNOTSUPP:
244 			fprintf(stderr, "%s: value is not available\n", string);
245 			return;
246 		case ENOTDIR:
247 			fprintf(stderr, "%s: specification is incomplete\n",
248 			    string);
249 			return;
250 		case ENOMEM:
251 			fprintf(stderr, "%s: type is unknown to this program\n",
252 			    string);
253 			return;
254 		default:
255 			perror(string);
256 			return;
257 		}
258 	}
259 	if (isclockrate) {
260 		struct clockinfo *clkp = (struct clockinfo *)buf;
261 
262 		if (!nflag)
263 			fprintf(stdout, "%s: ", string);
264 		fprintf(stdout,
265 		    "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
266 		    clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
267 		return;
268 	}
269 	if (size == sizeof(int) && !(isprint(buf[0]) && isprint(buf[1]) &&
270 	    isprint(buf[2]) && isprint(buf[3])))
271 		if (newsize == 0) {
272 			if (!nflag)
273 				fprintf(stdout, "%s = ", string);
274 			fprintf(stdout, "%d\n", *(int *)buf);
275 		} else {
276 			if (!nflag)
277 				fprintf(stdout, "%s: %d -> ", string,
278 				    *(int *)buf);
279 			fprintf(stdout, "%d\n", *(int *)newval);
280 		}
281 	else
282 		if (newsize == 0) {
283 			if (!nflag)
284 				fprintf(stdout, "%s = ", string);
285 			fprintf(stdout, "%s\n", buf);
286 		} else {
287 			if (!nflag)
288 				fprintf(stdout, "%s: %s -> ", string, buf);
289 			fprintf(stdout, "%s\n", newval);
290 		}
291 	return;
292 }
293 
294 /*
295  * Scan a list of names searching for a particular name.
296  */
297 findname(string, level, bufp, namelist)
298 	char *string;
299 	char *level;
300 	char **bufp;
301 	struct list *namelist;
302 {
303 	char *name;
304 	int i;
305 
306 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
307 		fprintf(stderr, "%s: incomplete specification\n", string);
308 		return (-1);
309 	}
310 	for (i = 0; i < namelist->size; i++)
311 		if (!strcmp(name, namelist->list[i]))
312 			break;
313 	if (i == namelist->size) {
314 		fprintf(stderr, "%s level name %s in %s is invalid\n",
315 		    level, name, string);
316 		return (-1);
317 	}
318 	return (i);
319 }
320 
321 usage()
322 {
323 
324 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
325 	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
326 	    "sysctl [-n] -a", "sysctl [-n] -A");
327 	exit(1);
328 }
329