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