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