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.10 (Berkeley) 05/04/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 void *newval = 0; 150 int intval, newsize = 0; 151 quad_t quadval; 152 struct list *lp; 153 int mib[CTL_MAXNAME]; 154 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 155 156 bufp = buf; 157 snprintf(buf, BUFSIZ, "%s", string); 158 if ((cp = strchr(string, '=')) != NULL) { 159 if (!wflag) { 160 fprintf(stderr, "Must specify -w to set variables\n"); 161 exit(2); 162 } 163 *strchr(buf, '=') = '\0'; 164 *cp++ = '\0'; 165 while (isspace(*cp)) 166 cp++; 167 newval = cp; 168 newsize = strlen(cp); 169 } 170 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 171 return; 172 mib[0] = indx; 173 if (indx == CTL_DEBUG) 174 debuginit(); 175 lp = &secondlevel[indx]; 176 if (lp->list == 0) { 177 fprintf(stderr, "%s: class is not implemented\n", 178 topname[indx]); 179 return; 180 } 181 if (bufp == NULL) { 182 listall(topname[indx].ctl_name, lp); 183 return; 184 } 185 if ((indx = findname(string, "second", &bufp, lp)) == -1) 186 return; 187 mib[1] = indx; 188 type = lp->list[indx].ctl_type; 189 len = 2; 190 switch (mib[0]) { 191 192 case CTL_KERN: 193 switch (mib[1]) { 194 case KERN_PROF: 195 mib[2] = GPROF_STATE; 196 size = sizeof state; 197 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 198 if (flags == 0) 199 return; 200 if (!nflag) 201 fprintf(stdout, "%s: ", string); 202 fprintf(stderr, 203 "kernel is not compiled for profiling\n"); 204 return; 205 } 206 if (!nflag) 207 fprintf(stdout, "%s: %s\n", string, 208 state == GMON_PROF_OFF ? "off" : "running"); 209 return; 210 case KERN_VNODE: 211 case KERN_FILE: 212 if (flags == 0) 213 return; 214 fprintf(stderr, 215 "Use pstat to view %s information\n", string); 216 return; 217 case KERN_PROC: 218 if (flags == 0) 219 return; 220 fprintf(stderr, 221 "Use ps to view %s information\n", string); 222 return; 223 case KERN_CLOCKRATE: 224 isclockrate = 1; 225 break; 226 } 227 break; 228 229 case CTL_HW: 230 break; 231 232 case CTL_VM: 233 if (mib[1] == VM_LOADAVG) { 234 double loads[3]; 235 236 getloadavg(loads, 3); 237 if (!nflag) 238 fprintf(stdout, "%s: ", string); 239 fprintf(stdout, "%.2f %.2f %.2f\n", 240 loads[0], loads[1], loads[2]); 241 return; 242 } 243 if (flags == 0) 244 return; 245 fprintf(stderr, 246 "Use vmstat or systat to view %s information\n", string); 247 return; 248 249 case CTL_NET: 250 if (mib[1] == PF_INET) { 251 len = sysctl_inet(string, &bufp, mib, flags, &type); 252 if (len >= 0) 253 break; 254 return; 255 } 256 if (flags == 0) 257 return; 258 fprintf(stderr, "Use netstat to view %s information\n", string); 259 return; 260 261 case CTL_DEBUG: 262 mib[2] = CTL_DEBUG_VALUE; 263 len = 3; 264 break; 265 266 case CTL_FS: 267 case CTL_MACHDEP: 268 case CTL_USER: 269 break; 270 271 default: 272 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 273 return; 274 275 } 276 if (bufp) { 277 fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); 278 return; 279 } 280 if (newsize > 0) { 281 switch (type) { 282 case CTLTYPE_INT: 283 intval = atoi(newval); 284 newval = &intval; 285 newsize = sizeof intval; 286 break; 287 288 case CTLTYPE_QUAD: 289 sscanf(newval, "%qd", &quadval); 290 newval = &quadval; 291 newsize = sizeof quadval; 292 break; 293 } 294 } 295 size = BUFSIZ; 296 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 297 if (flags == 0) 298 return; 299 switch (errno) { 300 case EOPNOTSUPP: 301 fprintf(stderr, "%s: value is not available\n", string); 302 return; 303 case ENOTDIR: 304 fprintf(stderr, "%s: specification is incomplete\n", 305 string); 306 return; 307 case ENOMEM: 308 fprintf(stderr, "%s: type is unknown to this program\n", 309 string); 310 return; 311 default: 312 perror(string); 313 return; 314 } 315 } 316 if (isclockrate) { 317 struct clockinfo *clkp = (struct clockinfo *)buf; 318 319 if (!nflag) 320 fprintf(stdout, "%s: ", string); 321 fprintf(stdout, 322 "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 323 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 324 return; 325 } 326 switch (type) { 327 case CTLTYPE_INT: 328 if (newsize == 0) { 329 if (!nflag) 330 fprintf(stdout, "%s = ", string); 331 fprintf(stdout, "%d\n", *(int *)buf); 332 } else { 333 if (!nflag) 334 fprintf(stdout, "%s: %d -> ", string, 335 *(int *)buf); 336 fprintf(stdout, "%d\n", *(int *)newval); 337 } 338 return; 339 340 case CTLTYPE_STRING: 341 if (newsize == 0) { 342 if (!nflag) 343 fprintf(stdout, "%s = ", string); 344 fprintf(stdout, "%s\n", buf); 345 } else { 346 if (!nflag) 347 fprintf(stdout, "%s: %s -> ", string, buf); 348 fprintf(stdout, "%s\n", newval); 349 } 350 return; 351 352 case CTLTYPE_QUAD: 353 if (newsize == 0) { 354 if (!nflag) 355 fprintf(stdout, "%s = ", string); 356 fprintf(stdout, "%qd\n", *(quad_t *)buf); 357 } else { 358 if (!nflag) 359 fprintf(stdout, "%s: %qd -> ", string, 360 *(quad_t *)buf); 361 fprintf(stdout, "%qd\n", *(quad_t *)newval); 362 } 363 return; 364 365 case CTLTYPE_STRUCT: 366 fprintf(stderr, "%s: unknown structure returned\n", 367 string); 368 return; 369 370 default: 371 case CTLTYPE_NODE: 372 fprintf(stderr, "%s: unknown type returned\n", 373 string); 374 return; 375 } 376 } 377 378 /* 379 * Initialize the set of debugging names 380 */ 381 debuginit() 382 { 383 int mib[3], size, loc, i; 384 385 if (secondlevel[CTL_DEBUG].list != 0) 386 return; 387 secondlevel[CTL_DEBUG].list = debugname; 388 mib[0] = CTL_DEBUG; 389 mib[2] = CTL_DEBUG_NAME; 390 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 391 mib[1] = i; 392 size = BUFSIZ - loc; 393 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 394 continue; 395 debugname[i].ctl_name = &names[loc]; 396 debugname[i].ctl_type = CTLTYPE_INT; 397 loc += size; 398 } 399 } 400 401 struct ctlname inetname[] = CTL_IPPROTO_NAMES; 402 struct ctlname ipname[] = IPCTL_NAMES; 403 struct ctlname icmpname[] = ICMPCTL_NAMES; 404 struct ctlname udpname[] = UDPCTL_NAMES; 405 struct list inetlist = { inetname, IPPROTO_MAXID }; 406 struct list inetvars[] = { 407 { ipname, IPCTL_MAXID }, /* ip */ 408 { icmpname, ICMPCTL_MAXID }, /* icmp */ 409 { 0, 0 }, /* igmp */ 410 { 0, 0 }, /* ggmp */ 411 { 0, 0 }, 412 { 0, 0 }, 413 { 0, 0 }, /* tcp */ 414 { 0, 0 }, 415 { 0, 0 }, /* egp */ 416 { 0, 0 }, 417 { 0, 0 }, 418 { 0, 0 }, 419 { 0, 0 }, /* pup */ 420 { 0, 0 }, 421 { 0, 0 }, 422 { 0, 0 }, 423 { 0, 0 }, 424 { udpname, UDPCTL_MAXID }, /* udp */ 425 }; 426 427 /* 428 * handle internet requests 429 */ 430 sysctl_inet(string, bufpp, mib, flags, typep) 431 char *string; 432 char **bufpp; 433 int mib[]; 434 int flags; 435 int *typep; 436 { 437 struct list *lp; 438 int indx; 439 440 if (*bufpp == NULL) { 441 listall(string, &inetlist); 442 return (-1); 443 } 444 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 445 return (-1); 446 mib[2] = indx; 447 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 448 lp = &inetvars[indx]; 449 else if (!flags) 450 return (-1); 451 else { 452 fprintf(stderr, "%s: no variables defined for this protocol\n", 453 string); 454 return (-1); 455 } 456 if (*bufpp == NULL) { 457 listall(string, lp); 458 return (-1); 459 } 460 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 461 return (-1); 462 mib[3] = indx; 463 *typep = lp->list[indx].ctl_type; 464 return (4); 465 } 466 467 /* 468 * Scan a list of names searching for a particular name. 469 */ 470 findname(string, level, bufp, namelist) 471 char *string; 472 char *level; 473 char **bufp; 474 struct list *namelist; 475 { 476 char *name; 477 int i; 478 479 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 480 fprintf(stderr, "%s: incomplete specification\n", string); 481 return (-1); 482 } 483 for (i = 0; i < namelist->size; i++) 484 if (namelist->list[i].ctl_name != NULL && 485 strcmp(name, namelist->list[i].ctl_name) == 0) 486 break; 487 if (i == namelist->size) { 488 fprintf(stderr, "%s level name %s in %s is invalid\n", 489 level, name, string); 490 return (-1); 491 } 492 return (i); 493 } 494 495 usage() 496 { 497 498 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 499 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 500 "sysctl [-n] -a", "sysctl [-n] -A"); 501 exit(1); 502 } 503