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