1 /*
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 05/09/95";
16 #endif /* not lint */
17
18 #include <sys/param.h>
19 #include <sys/gmon.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/sysctl.h>
23 #include <sys/socket.h>
24 #include <vm/vm_param.h>
25 #include <machine/cpu.h>
26
27 #include <netinet/in.h>
28 #include <netinet/in_systm.h>
29 #include <netinet/ip.h>
30 #include <netinet/ip_icmp.h>
31 #include <netinet/icmp_var.h>
32 #include <netinet/ip_var.h>
33 #include <netinet/udp.h>
34 #include <netinet/udp_var.h>
35
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 struct ctlname topname[] = CTL_NAMES;
42 struct ctlname kernname[] = CTL_KERN_NAMES;
43 struct ctlname vmname[] = CTL_VM_NAMES;
44 struct ctlname netname[] = CTL_NET_NAMES;
45 struct ctlname hwname[] = CTL_HW_NAMES;
46 struct ctlname username[] = CTL_USER_NAMES;
47 struct ctlname debugname[CTL_DEBUG_MAXID];
48 struct ctlname *vfsname;
49 #ifdef CTL_MACHDEP_NAMES
50 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
51 #endif
52 char names[BUFSIZ];
53 int lastused;
54
55 struct list {
56 struct ctlname *list;
57 int size;
58 };
59 struct list toplist = { topname, CTL_MAXID };
60 struct list secondlevel[] = {
61 { 0, 0 }, /* CTL_UNSPEC */
62 { kernname, KERN_MAXID }, /* CTL_KERN */
63 { vmname, VM_MAXID }, /* CTL_VM */
64 { 0, 0 }, /* CTL_VFS */
65 { netname, NET_MAXID }, /* CTL_NET */
66 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
67 { hwname, HW_MAXID }, /* CTL_HW */
68 #ifdef CTL_MACHDEP_NAMES
69 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
70 #else
71 { 0, 0 }, /* CTL_MACHDEP */
72 #endif
73 { username, USER_MAXID }, /* CTL_USER_NAMES */
74 };
75
76 int Aflag, aflag, nflag, wflag;
77
78 /*
79 * Variables requiring special processing.
80 */
81 #define CLOCK 0x00000001
82 #define BOOTTIME 0x00000002
83 #define CONSDEV 0x00000004
84
85 int
main(argc,argv)86 main(argc, argv)
87 int argc;
88 char *argv[];
89 {
90 extern char *optarg;
91 extern int optind;
92 int ch, lvl1;
93
94 while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
95 switch (ch) {
96
97 case 'A':
98 Aflag = 1;
99 break;
100
101 case 'a':
102 aflag = 1;
103 break;
104
105 case 'n':
106 nflag = 1;
107 break;
108
109 case 'w':
110 wflag = 1;
111 break;
112
113 default:
114 usage();
115 }
116 }
117 argc -= optind;
118 argv += optind;
119
120 if (argc == 0 && (Aflag || aflag)) {
121 debuginit();
122 vfsinit();
123 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
124 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
125 exit(0);
126 }
127 if (argc == 0)
128 usage();
129 for (; *argv != NULL; ++argv)
130 parse(*argv, 1);
131 exit(0);
132 }
133
134 /*
135 * List all variables known to the system.
136 */
listall(prefix,lp)137 listall(prefix, lp)
138 char *prefix;
139 struct list *lp;
140 {
141 int lvl2;
142 char *cp, name[BUFSIZ];
143
144 if (lp->list == 0)
145 return;
146 strcpy(name, prefix);
147 cp = &name[strlen(name)];
148 *cp++ = '.';
149 for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
150 if (lp->list[lvl2].ctl_name == 0)
151 continue;
152 strcpy(cp, lp->list[lvl2].ctl_name);
153 parse(name, Aflag);
154 }
155 }
156
157 /*
158 * Parse a name into a MIB entry.
159 * Lookup and print out the MIB entry if it exists.
160 * Set a new value if requested.
161 */
parse(string,flags)162 parse(string, flags)
163 char *string;
164 int flags;
165 {
166 int indx, type, state, len;
167 size_t size;
168 int special = 0;
169 void *newval = 0;
170 int intval, newsize = 0;
171 quad_t quadval;
172 struct list *lp;
173 struct vfsconf vfc;
174 int mib[CTL_MAXNAME];
175 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
176
177 bufp = buf;
178 snprintf(buf, BUFSIZ, "%s", string);
179 if ((cp = strchr(string, '=')) != NULL) {
180 if (!wflag) {
181 fprintf(stderr, "Must specify -w to set variables\n");
182 exit(2);
183 }
184 *strchr(buf, '=') = '\0';
185 *cp++ = '\0';
186 while (isspace(*cp))
187 cp++;
188 newval = cp;
189 newsize = strlen(cp);
190 }
191 if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
192 return;
193 mib[0] = indx;
194 if (indx == CTL_VFS)
195 vfsinit();
196 if (indx == CTL_DEBUG)
197 debuginit();
198 lp = &secondlevel[indx];
199 if (lp->list == 0) {
200 fprintf(stderr, "%s: class is not implemented\n",
201 topname[indx]);
202 return;
203 }
204 if (bufp == NULL) {
205 listall(topname[indx].ctl_name, lp);
206 return;
207 }
208 if ((indx = findname(string, "second", &bufp, lp)) == -1)
209 return;
210 mib[1] = indx;
211 type = lp->list[indx].ctl_type;
212 len = 2;
213 switch (mib[0]) {
214
215 case CTL_KERN:
216 switch (mib[1]) {
217 case KERN_PROF:
218 mib[2] = GPROF_STATE;
219 size = sizeof state;
220 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
221 if (flags == 0)
222 return;
223 if (!nflag)
224 fprintf(stdout, "%s: ", string);
225 fprintf(stderr,
226 "kernel is not compiled for profiling\n");
227 return;
228 }
229 if (!nflag)
230 fprintf(stdout, "%s: %s\n", string,
231 state == GMON_PROF_OFF ? "off" : "running");
232 return;
233 case KERN_VNODE:
234 case KERN_FILE:
235 if (flags == 0)
236 return;
237 fprintf(stderr,
238 "Use pstat to view %s information\n", string);
239 return;
240 case KERN_PROC:
241 if (flags == 0)
242 return;
243 fprintf(stderr,
244 "Use ps to view %s information\n", string);
245 return;
246 case KERN_CLOCKRATE:
247 special |= CLOCK;
248 break;
249 case KERN_BOOTTIME:
250 special |= BOOTTIME;
251 break;
252 }
253 break;
254
255 case CTL_HW:
256 break;
257
258 case CTL_VM:
259 if (mib[1] == VM_LOADAVG) {
260 double loads[3];
261
262 getloadavg(loads, 3);
263 if (!nflag)
264 fprintf(stdout, "%s: ", string);
265 fprintf(stdout, "%.2f %.2f %.2f\n",
266 loads[0], loads[1], loads[2]);
267 return;
268 }
269 if (flags == 0)
270 return;
271 fprintf(stderr,
272 "Use vmstat or systat to view %s information\n", string);
273 return;
274
275 case CTL_NET:
276 if (mib[1] == PF_INET) {
277 len = sysctl_inet(string, &bufp, mib, flags, &type);
278 if (len >= 0)
279 break;
280 return;
281 }
282 if (flags == 0)
283 return;
284 fprintf(stderr, "Use netstat to view %s information\n", string);
285 return;
286
287 case CTL_DEBUG:
288 mib[2] = CTL_DEBUG_VALUE;
289 len = 3;
290 break;
291
292 case CTL_MACHDEP:
293 #ifdef CPU_CONSDEV
294 if (mib[1] == CPU_CONSDEV)
295 special |= CONSDEV;
296 #endif
297 break;
298
299 case CTL_VFS:
300 mib[3] = mib[1];
301 mib[1] = VFS_GENERIC;
302 mib[2] = VFS_CONF;
303 len = 4;
304 size = sizeof vfc;
305 if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
306 perror("vfs print");
307 return;
308 }
309 if (flags == 0 && vfc.vfc_refcount == 0)
310 return;
311 if (!nflag)
312 fprintf(stdout, "%s has %d mounted instance%s\n",
313 string, vfc.vfc_refcount,
314 vfc.vfc_refcount != 1 ? "s" : "");
315 else
316 fprintf(stdout, "%d\n", vfc.vfc_refcount);
317 return;
318
319 case CTL_USER:
320 break;
321
322 default:
323 fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
324 return;
325
326 }
327 if (bufp) {
328 fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
329 return;
330 }
331 if (newsize > 0) {
332 switch (type) {
333 case CTLTYPE_INT:
334 intval = atoi(newval);
335 newval = &intval;
336 newsize = sizeof intval;
337 break;
338
339 case CTLTYPE_QUAD:
340 sscanf(newval, "%qd", &quadval);
341 newval = &quadval;
342 newsize = sizeof quadval;
343 break;
344 }
345 }
346 size = BUFSIZ;
347 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
348 if (flags == 0)
349 return;
350 switch (errno) {
351 case EOPNOTSUPP:
352 fprintf(stderr, "%s: value is not available\n", string);
353 return;
354 case ENOTDIR:
355 fprintf(stderr, "%s: specification is incomplete\n",
356 string);
357 return;
358 case ENOMEM:
359 fprintf(stderr, "%s: type is unknown to this program\n",
360 string);
361 return;
362 default:
363 perror(string);
364 return;
365 }
366 }
367 if (special & CLOCK) {
368 struct clockinfo *clkp = (struct clockinfo *)buf;
369
370 if (!nflag)
371 fprintf(stdout, "%s: ", string);
372 fprintf(stdout,
373 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
374 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
375 return;
376 }
377 if (special & BOOTTIME) {
378 struct timeval *btp = (struct timeval *)buf;
379
380 if (!nflag)
381 fprintf(stdout, "%s = %s\n", string,
382 ctime(&btp->tv_sec));
383 else
384 fprintf(stdout, "%d\n", btp->tv_sec);
385 return;
386 }
387 if (special & CONSDEV) {
388 dev_t dev = *(dev_t *)buf;
389
390 if (!nflag)
391 fprintf(stdout, "%s = %s\n", string,
392 devname(dev, S_IFCHR));
393 else
394 fprintf(stdout, "0x%x\n", dev);
395 return;
396 }
397 switch (type) {
398 case CTLTYPE_INT:
399 if (newsize == 0) {
400 if (!nflag)
401 fprintf(stdout, "%s = ", string);
402 fprintf(stdout, "%d\n", *(int *)buf);
403 } else {
404 if (!nflag)
405 fprintf(stdout, "%s: %d -> ", string,
406 *(int *)buf);
407 fprintf(stdout, "%d\n", *(int *)newval);
408 }
409 return;
410
411 case CTLTYPE_STRING:
412 if (newsize == 0) {
413 if (!nflag)
414 fprintf(stdout, "%s = ", string);
415 fprintf(stdout, "%s\n", buf);
416 } else {
417 if (!nflag)
418 fprintf(stdout, "%s: %s -> ", string, buf);
419 fprintf(stdout, "%s\n", newval);
420 }
421 return;
422
423 case CTLTYPE_QUAD:
424 if (newsize == 0) {
425 if (!nflag)
426 fprintf(stdout, "%s = ", string);
427 fprintf(stdout, "%qd\n", *(quad_t *)buf);
428 } else {
429 if (!nflag)
430 fprintf(stdout, "%s: %qd -> ", string,
431 *(quad_t *)buf);
432 fprintf(stdout, "%qd\n", *(quad_t *)newval);
433 }
434 return;
435
436 case CTLTYPE_STRUCT:
437 fprintf(stderr, "%s: unknown structure returned\n",
438 string);
439 return;
440
441 default:
442 case CTLTYPE_NODE:
443 fprintf(stderr, "%s: unknown type returned\n",
444 string);
445 return;
446 }
447 }
448
449 /*
450 * Initialize the set of debugging names
451 */
debuginit()452 debuginit()
453 {
454 int mib[3], loc, i;
455 size_t size;
456
457 if (secondlevel[CTL_DEBUG].list != 0)
458 return;
459 secondlevel[CTL_DEBUG].list = debugname;
460 mib[0] = CTL_DEBUG;
461 mib[2] = CTL_DEBUG_NAME;
462 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
463 mib[1] = i;
464 size = BUFSIZ - loc;
465 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
466 continue;
467 debugname[i].ctl_name = &names[loc];
468 debugname[i].ctl_type = CTLTYPE_INT;
469 loc += size;
470 }
471 lastused = loc;
472 }
473
474 /*
475 * Initialize the set of filesystem names
476 */
vfsinit()477 vfsinit()
478 {
479 int mib[4], maxtypenum, cnt, loc, size;
480 struct vfsconf vfc;
481 size_t buflen;
482
483 if (secondlevel[CTL_VFS].list != 0)
484 return;
485 mib[0] = CTL_VFS;
486 mib[1] = VFS_GENERIC;
487 mib[2] = VFS_MAXTYPENUM;
488 buflen = 4;
489 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
490 return;
491 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
492 return;
493 memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
494 mib[2] = VFS_CONF;
495 buflen = sizeof vfc;
496 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
497 mib[3] = cnt;
498 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
499 if (errno == EOPNOTSUPP)
500 continue;
501 perror("vfsinit");
502 free(vfsname);
503 return;
504 }
505 strcat(&names[loc], vfc.vfc_name);
506 vfsname[cnt].ctl_name = &names[loc];
507 vfsname[cnt].ctl_type = CTLTYPE_INT;
508 size = strlen(vfc.vfc_name) + 1;
509 loc += size;
510 }
511 lastused = loc;
512 secondlevel[CTL_VFS].list = vfsname;
513 secondlevel[CTL_VFS].size = maxtypenum;
514 return;
515 }
516
517 struct ctlname inetname[] = CTL_IPPROTO_NAMES;
518 struct ctlname ipname[] = IPCTL_NAMES;
519 struct ctlname icmpname[] = ICMPCTL_NAMES;
520 struct ctlname udpname[] = UDPCTL_NAMES;
521 struct list inetlist = { inetname, IPPROTO_MAXID };
522 struct list inetvars[] = {
523 { ipname, IPCTL_MAXID }, /* ip */
524 { icmpname, ICMPCTL_MAXID }, /* icmp */
525 { 0, 0 }, /* igmp */
526 { 0, 0 }, /* ggmp */
527 { 0, 0 },
528 { 0, 0 },
529 { 0, 0 }, /* tcp */
530 { 0, 0 },
531 { 0, 0 }, /* egp */
532 { 0, 0 },
533 { 0, 0 },
534 { 0, 0 },
535 { 0, 0 }, /* pup */
536 { 0, 0 },
537 { 0, 0 },
538 { 0, 0 },
539 { 0, 0 },
540 { udpname, UDPCTL_MAXID }, /* udp */
541 };
542
543 /*
544 * handle internet requests
545 */
sysctl_inet(string,bufpp,mib,flags,typep)546 sysctl_inet(string, bufpp, mib, flags, typep)
547 char *string;
548 char **bufpp;
549 int mib[];
550 int flags;
551 int *typep;
552 {
553 struct list *lp;
554 int indx;
555
556 if (*bufpp == NULL) {
557 listall(string, &inetlist);
558 return (-1);
559 }
560 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
561 return (-1);
562 mib[2] = indx;
563 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
564 lp = &inetvars[indx];
565 else if (!flags)
566 return (-1);
567 else {
568 fprintf(stderr, "%s: no variables defined for this protocol\n",
569 string);
570 return (-1);
571 }
572 if (*bufpp == NULL) {
573 listall(string, lp);
574 return (-1);
575 }
576 if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
577 return (-1);
578 mib[3] = indx;
579 *typep = lp->list[indx].ctl_type;
580 return (4);
581 }
582
583 /*
584 * Scan a list of names searching for a particular name.
585 */
findname(string,level,bufp,namelist)586 findname(string, level, bufp, namelist)
587 char *string;
588 char *level;
589 char **bufp;
590 struct list *namelist;
591 {
592 char *name;
593 int i;
594
595 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
596 fprintf(stderr, "%s: incomplete specification\n", string);
597 return (-1);
598 }
599 for (i = 0; i < namelist->size; i++)
600 if (namelist->list[i].ctl_name != NULL &&
601 strcmp(name, namelist->list[i].ctl_name) == 0)
602 break;
603 if (i == namelist->size) {
604 fprintf(stderr, "%s level name %s in %s is invalid\n",
605 level, name, string);
606 return (-1);
607 }
608 return (i);
609 }
610
usage()611 usage()
612 {
613
614 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
615 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
616 "sysctl [-n] -a", "sysctl [-n] -A");
617 exit(1);
618 }
619