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