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