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