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.7 1995/06/11 19:32:58 rgrimes 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 #ifdef CTL_MACHDEP_NAMES 80 struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 81 #endif 82 char names[BUFSIZ]; 83 84 struct list { 85 struct ctlname *list; 86 int size; 87 }; 88 struct list toplist = { topname, CTL_MAXID }; 89 struct list secondlevel[] = { 90 { 0, 0 }, /* CTL_UNSPEC */ 91 { kernname, KERN_MAXID }, /* CTL_KERN */ 92 { vmname, VM_MAXID }, /* CTL_VM */ 93 { 0, 0 }, /* CTL_FS */ 94 { netname, NET_MAXID }, /* CTL_NET */ 95 { 0, 0 }, /* CTL_DEBUG */ 96 { hwname, HW_MAXID }, /* CTL_HW */ 97 #ifdef CTL_MACHDEP_NAMES 98 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 99 #else 100 { 0, 0 }, /* CTL_MACHDEP */ 101 #endif 102 { username, USER_MAXID }, /* CTL_USER_NAMES */ 103 }; 104 105 int Aflag, aflag, nflag, wflag; 106 107 /* 108 * Variables requiring special processing. 109 */ 110 #define CLOCK 0x00000001 111 #define BOOTTIME 0x00000002 112 #define CONSDEV 0x00000004 113 #define DUMPDEV 0x00000008 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 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 152 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 153 exit(0); 154 } 155 if (argc == 0) 156 usage(); 157 while (argc-- > 0) 158 parse(*argv, 1); 159 exit(0); 160 } 161 162 /* 163 * List all variables known to the system. 164 */ 165 listall(prefix, lp) 166 char *prefix; 167 struct list *lp; 168 { 169 int lvl2; 170 char *cp, name[BUFSIZ]; 171 172 if (lp->list == 0) 173 return; 174 strcpy(name, prefix); 175 cp = &name[strlen(name)]; 176 *cp++ = '.'; 177 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 178 if (lp->list[lvl2].ctl_name == 0) 179 continue; 180 strcpy(cp, lp->list[lvl2].ctl_name); 181 parse(name, Aflag); 182 } 183 } 184 185 /* 186 * Parse a name into a MIB entry. 187 * Lookup and print out the MIB entry if it exists. 188 * Set a new value if requested. 189 */ 190 parse(string, flags) 191 char *string; 192 int flags; 193 { 194 int indx, type, state, size, len; 195 int special = 0; 196 void *newval = 0; 197 int intval, newsize = 0; 198 quad_t quadval; 199 struct list *lp; 200 int mib[CTL_MAXNAME]; 201 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 202 203 bufp = buf; 204 snprintf(buf, BUFSIZ, "%s", string); 205 if ((cp = strchr(string, '=')) != NULL) { 206 if (!wflag) { 207 fprintf(stderr, "Must specify -w to set variables\n"); 208 exit(2); 209 } 210 *strchr(buf, '=') = '\0'; 211 *cp++ = '\0'; 212 while (isspace(*cp)) 213 cp++; 214 newval = cp; 215 newsize = strlen(cp); 216 } 217 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 218 return; 219 mib[0] = indx; 220 lp = &secondlevel[indx]; 221 if (lp->list == 0) { 222 fprintf(stderr, "%s: class is not implemented\n", 223 topname[indx]); 224 return; 225 } 226 if (bufp == NULL) { 227 listall(topname[indx].ctl_name, lp); 228 return; 229 } 230 if ((indx = findname(string, "second", &bufp, lp)) == -1) 231 return; 232 mib[1] = indx; 233 type = lp->list[indx].ctl_type; 234 len = 2; 235 switch (mib[0]) { 236 237 case CTL_KERN: 238 switch (mib[1]) { 239 case KERN_PROF: 240 mib[2] = GPROF_STATE; 241 size = sizeof state; 242 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 243 if (flags == 0) 244 return; 245 if (!nflag) 246 fprintf(stdout, "%s: ", string); 247 fprintf(stderr, 248 "kernel is not compiled for profiling\n"); 249 return; 250 } 251 if (!nflag) 252 fprintf(stdout, "%s: %s\n", string, 253 state == GMON_PROF_OFF ? "off" : "running"); 254 return; 255 case KERN_VNODE: 256 case KERN_FILE: 257 if (flags == 0) 258 return; 259 fprintf(stderr, 260 "Use pstat to view %s information\n", string); 261 return; 262 case KERN_PROC: 263 if (flags == 0) 264 return; 265 fprintf(stderr, 266 "Use ps to view %s information\n", string); 267 return; 268 case KERN_CLOCKRATE: 269 special |= CLOCK; 270 break; 271 case KERN_BOOTTIME: 272 special |= BOOTTIME; 273 break; 274 case KERN_DUMPDEV: 275 special |= DUMPDEV; 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 314 case CTL_MACHDEP: 315 #ifdef CPU_CONSDEV 316 if (mib[1] == CPU_CONSDEV) 317 special |= CONSDEV; 318 #endif 319 break; 320 321 case CTL_FS: 322 case CTL_USER: 323 break; 324 325 default: 326 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 327 return; 328 329 } 330 if (bufp) { 331 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 332 return; 333 } 334 if (newsize > 0) { 335 switch (type) { 336 case CTLTYPE_INT: 337 intval = atoi(newval); 338 newval = &intval; 339 newsize = sizeof intval; 340 break; 341 342 case CTLTYPE_QUAD: 343 sscanf(newval, "%qd", &quadval); 344 newval = &quadval; 345 newsize = sizeof quadval; 346 break; 347 } 348 } 349 size = BUFSIZ; 350 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 351 if (flags == 0) 352 return; 353 switch (errno) { 354 case EOPNOTSUPP: 355 fprintf(stderr, "%s: value is not available\n", string); 356 return; 357 case ENOTDIR: 358 fprintf(stderr, "%s: specification is incomplete\n", 359 string); 360 return; 361 case ENOMEM: 362 fprintf(stderr, "%s: type is unknown to this program\n", 363 string); 364 return; 365 default: 366 perror(string); 367 return; 368 } 369 } 370 if (special & CLOCK) { 371 struct clockinfo *clkp = (struct clockinfo *)buf; 372 373 if (!nflag) 374 fprintf(stdout, "%s: ", string); 375 fprintf(stdout, 376 "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 377 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 378 return; 379 } 380 if (special & BOOTTIME) { 381 struct timeval *btp = (struct timeval *)buf; 382 383 if (!nflag) 384 fprintf(stdout, "%s = %s", string, 385 ctime(&btp->tv_sec)); 386 else 387 fprintf(stdout, "%d\n", btp->tv_sec); 388 return; 389 } 390 if (special & (CONSDEV | DUMPDEV)) { 391 dev_t dev = *(dev_t *)buf; 392 393 if ((special & DUMPDEV) && dev == NODEV && !nflag) { 394 printf("%s = disabled\n", string); 395 return; 396 } 397 if (!nflag) 398 fprintf(stdout, "%s = %s\n", string, 399 devname(dev, 400 (special & CONSDEV) ? S_IFCHR : S_IFBLK)); 401 else 402 fprintf(stdout, "0x%x\n", dev); 403 return; 404 } 405 switch (type) { 406 case CTLTYPE_INT: 407 if (newsize == 0) { 408 if (!nflag) 409 fprintf(stdout, "%s = ", string); 410 fprintf(stdout, "%d\n", *(int *)buf); 411 } else { 412 if (!nflag) 413 fprintf(stdout, "%s: %d -> ", string, 414 *(int *)buf); 415 fprintf(stdout, "%d\n", *(int *)newval); 416 } 417 return; 418 419 case CTLTYPE_STRING: 420 if (newsize == 0) { 421 if (!nflag) 422 fprintf(stdout, "%s = ", string); 423 fprintf(stdout, "%s\n", buf); 424 } else { 425 if (!nflag) 426 fprintf(stdout, "%s: %s -> ", string, buf); 427 fprintf(stdout, "%s\n", newval); 428 } 429 return; 430 431 case CTLTYPE_QUAD: 432 if (newsize == 0) { 433 if (!nflag) 434 fprintf(stdout, "%s = ", string); 435 fprintf(stdout, "%qd\n", *(quad_t *)buf); 436 } else { 437 if (!nflag) 438 fprintf(stdout, "%s: %qd -> ", string, 439 *(quad_t *)buf); 440 fprintf(stdout, "%qd\n", *(quad_t *)newval); 441 } 442 return; 443 444 case CTLTYPE_STRUCT: 445 fprintf(stderr, "%s: unknown structure returned\n", 446 string); 447 return; 448 449 default: 450 case CTLTYPE_NODE: 451 fprintf(stderr, "%s: unknown type returned\n", 452 string); 453 return; 454 } 455 } 456 457 458 struct ctlname inetname[] = CTL_IPPROTO_NAMES; 459 struct ctlname ipname[] = IPCTL_NAMES; 460 struct ctlname icmpname[] = ICMPCTL_NAMES; 461 struct ctlname udpname[] = UDPCTL_NAMES; 462 struct ctlname tcpname[] = TCPCTL_NAMES; 463 struct ctlname igmpname[] = IGMPCTL_NAMES; 464 struct list inetlist = { inetname, IPPROTO_MAXID }; 465 struct list inetvars[] = { 466 { ipname, IPCTL_MAXID }, /* ip */ 467 { icmpname, ICMPCTL_MAXID }, /* icmp */ 468 { igmpname, IGMPCTL_MAXID }, /* igmp */ 469 { 0, 0 }, /* ggp */ 470 { 0, 0 }, /* ipencap */ 471 { 0, 0 }, 472 { tcpname, TCPCTL_MAXID }, /* tcp */ 473 { 0, 0 }, 474 { 0, 0 }, /* egp */ 475 { 0, 0 }, 476 { 0, 0 }, 477 { 0, 0 }, 478 { 0, 0 }, /* pup */ 479 { 0, 0 }, 480 { 0, 0 }, 481 { 0, 0 }, 482 { 0, 0 }, 483 { udpname, UDPCTL_MAXID }, /* udp */ 484 }; 485 486 /* 487 * handle internet requests 488 */ 489 int 490 sysctl_inet(string, bufpp, mib, flags, typep, specialp) 491 char *string; 492 char **bufpp; 493 int mib[]; 494 int flags; 495 int *typep; 496 int *specialp; 497 { 498 struct list *lp; 499 int indx; 500 501 if (*bufpp == NULL) { 502 listall(string, &inetlist); 503 return (-1); 504 } 505 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 506 return (-1); 507 mib[2] = indx; 508 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 509 lp = &inetvars[indx]; 510 else if (!flags) 511 return (-1); 512 else { 513 fprintf(stderr, "%s: no variables defined for this protocol\n", 514 string); 515 return (-1); 516 } 517 if (*bufpp == NULL) { 518 listall(string, lp); 519 return (-1); 520 } 521 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 522 return (-1); 523 mib[3] = indx; 524 *typep = lp->list[indx].ctl_type; 525 return (4); 526 } 527 528 /* 529 * Scan a list of names searching for a particular name. 530 */ 531 findname(string, level, bufp, namelist) 532 char *string; 533 char *level; 534 char **bufp; 535 struct list *namelist; 536 { 537 char *name; 538 int i; 539 540 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 541 fprintf(stderr, "%s: incomplete specification\n", string); 542 return (-1); 543 } 544 for (i = 0; i < namelist->size; i++) 545 if (namelist->list[i].ctl_name != NULL && 546 strcmp(name, namelist->list[i].ctl_name) == 0) 547 break; 548 if (i == namelist->size) { 549 fprintf(stderr, "%s level name %s in %s is invalid\n", 550 level, name, string); 551 return (-1); 552 } 553 return (i); 554 } 555 556 usage() 557 { 558 559 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 560 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 561 "sysctl [-n] -a", "sysctl [-n] -A"); 562 exit(1); 563 } 564