| 1 | /* |
| 2 | * Copyright (c) 1993 |
| 3 | * The Regents of the University of California. All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in the |
| 12 | * documentation and/or other materials provided with the distribution. |
| 13 | * 3. All advertising materials mentioning features or use of this software |
| 14 | * must display the following acknowledgement: |
| 15 | * This product includes software developed by the University of |
| 16 | * California, Berkeley and its contributors. |
| 17 | * 4. Neither the name of the University nor the names of its contributors |
| 18 | * may be used to endorse or promote products derived from this software |
| 19 | * without specific prior written permission. |
| 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 31 | * SUCH DAMAGE. |
| 32 | * |
| 33 | * @(#) Copyright (c) 1993 The Regents of the University of California. All rights reserved. |
| 34 | * @(#)from: sysctl.c 8.1 (Berkeley) 6/6/93 |
| 35 | * $FreeBSD: src/sbin/sysctl/sysctl.c,v 1.25.2.11 2003/05/01 22:48:08 trhodes Exp $ |
| 36 | */ |
| 37 | |
| 38 | #ifdef __i386__ |
| 39 | #include <sys/diskslice.h> /* used for bootdev parsing */ |
| 40 | #include <sys/reboot.h> /* used for bootdev parsing */ |
| 41 | #endif |
| 42 | #include <sys/types.h> |
| 43 | #include <sys/stat.h> |
| 44 | #include <sys/sysctl.h> |
| 45 | #include <sys/resource.h> |
| 46 | #include <sys/sensors.h> |
| 47 | #include <sys/param.h> |
| 48 | |
| 49 | #include <machine/inttypes.h> |
| 50 | |
| 51 | #include <ctype.h> |
| 52 | #include <err.h> |
| 53 | #include <errno.h> |
| 54 | #include <stdio.h> |
| 55 | #include <stdlib.h> |
| 56 | #include <string.h> |
| 57 | #include <unistd.h> |
| 58 | |
| 59 | static int aflag, bflag, dflag, eflag, Nflag, nflag, oflag, xflag; |
| 60 | |
| 61 | static int oidfmt(int *, size_t, char *, u_int *); |
| 62 | static void parse(const char *); |
| 63 | static int show_var(int *, size_t); |
| 64 | static int sysctl_all(int *, size_t); |
| 65 | static void set_T_dev_t(const char *, void **, size_t *); |
| 66 | static int set_IK(const char *, int *); |
| 67 | |
| 68 | static void |
| 69 | usage(void) |
| 70 | { |
| 71 | |
| 72 | fprintf(stderr, "%s\n%s\n", |
| 73 | "usage: sysctl [-bdeNnox] variable[=value] ...", |
| 74 | " sysctl [-bdeNnox] -a"); |
| 75 | exit(1); |
| 76 | } |
| 77 | |
| 78 | int |
| 79 | main(int argc, char **argv) |
| 80 | { |
| 81 | int ch; |
| 82 | setbuf(stdout,0); |
| 83 | setbuf(stderr,0); |
| 84 | |
| 85 | while ((ch = getopt(argc, argv, "AabdeNnowxX")) != -1) { |
| 86 | switch (ch) { |
| 87 | case 'A': |
| 88 | /* compatibility */ |
| 89 | aflag = oflag = 1; |
| 90 | break; |
| 91 | case 'a': |
| 92 | aflag = 1; |
| 93 | break; |
| 94 | case 'b': |
| 95 | bflag = 1; |
| 96 | break; |
| 97 | case 'd': |
| 98 | dflag = 1; |
| 99 | break; |
| 100 | case 'e': |
| 101 | eflag = 1; |
| 102 | break; |
| 103 | case 'N': |
| 104 | Nflag = 1; |
| 105 | break; |
| 106 | case 'n': |
| 107 | nflag = 1; |
| 108 | break; |
| 109 | case 'o': |
| 110 | oflag = 1; |
| 111 | break; |
| 112 | case 'w': |
| 113 | /* compatibility */ |
| 114 | /* ignored */ |
| 115 | break; |
| 116 | case 'X': |
| 117 | /* compatibility */ |
| 118 | aflag = xflag = 1; |
| 119 | break; |
| 120 | case 'x': |
| 121 | xflag = 1; |
| 122 | break; |
| 123 | default: |
| 124 | usage(); |
| 125 | } |
| 126 | } |
| 127 | argc -= optind; |
| 128 | argv += optind; |
| 129 | |
| 130 | if (Nflag && nflag) |
| 131 | usage(); |
| 132 | if (aflag && argc == 0) |
| 133 | exit(sysctl_all(0, 0)); |
| 134 | if (argc == 0) |
| 135 | usage(); |
| 136 | while (argc-- > 0) |
| 137 | parse(*argv++); |
| 138 | exit(0); |
| 139 | } |
| 140 | |
| 141 | /* |
| 142 | * Parse a name into a MIB entry. |
| 143 | * Lookup and print out the MIB entry if it exists. |
| 144 | * Set a new value if requested. |
| 145 | */ |
| 146 | static void |
| 147 | parse(const char *string) |
| 148 | { |
| 149 | size_t len; |
| 150 | int i, j; |
| 151 | void *newval = NULL; |
| 152 | int intval; |
| 153 | unsigned int uintval; |
| 154 | long longval; |
| 155 | unsigned long ulongval; |
| 156 | size_t newsize = 0; |
| 157 | quad_t quadval; |
| 158 | u_quad_t uquadval; |
| 159 | int mib[CTL_MAXNAME]; |
| 160 | char *cp, fmt[BUFSIZ]; |
| 161 | const char *name; |
| 162 | char *name_allocated = NULL; |
| 163 | u_int kind; |
| 164 | |
| 165 | if ((cp = strchr(string, '=')) != NULL) { |
| 166 | if ((name_allocated = malloc(cp - string + 1)) == NULL) |
| 167 | err(1, "malloc failed"); |
| 168 | strlcpy(name_allocated, string, cp - string + 1); |
| 169 | name = name_allocated; |
| 170 | |
| 171 | while (isspace(*++cp)) |
| 172 | ; |
| 173 | |
| 174 | newval = cp; |
| 175 | newsize = strlen(cp); |
| 176 | } else { |
| 177 | name = string; |
| 178 | } |
| 179 | |
| 180 | len = CTL_MAXNAME; |
| 181 | if (sysctlnametomib(name, mib, &len) < 0) { |
| 182 | if (errno == ENOENT) { |
| 183 | errx(1, "unknown oid '%s'", name); |
| 184 | } else { |
| 185 | err(1, "sysctlnametomib(\"%s\")", name); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | if (oidfmt(mib, len, fmt, &kind)) |
| 190 | err(1, "couldn't find format of oid '%s'", name); |
| 191 | |
| 192 | if (newval == NULL) { |
| 193 | if ((kind & CTLTYPE) == CTLTYPE_NODE) { |
| 194 | sysctl_all(mib, len); |
| 195 | } else { |
| 196 | i = show_var(mib, len); |
| 197 | if (!i && !bflag) |
| 198 | putchar('\n'); |
| 199 | } |
| 200 | } else { |
| 201 | if ((kind & CTLTYPE) == CTLTYPE_NODE) |
| 202 | errx(1, "oid '%s' isn't a leaf node", name); |
| 203 | |
| 204 | if (!(kind&CTLFLAG_WR)) |
| 205 | errx(1, "oid '%s' is read only", name); |
| 206 | |
| 207 | switch (kind & CTLTYPE) { |
| 208 | case CTLTYPE_INT: |
| 209 | if (!strcmp(fmt, "IK") == 0) { |
| 210 | if (!set_IK(newval, &intval)) |
| 211 | errx(1, "invalid value '%s'", |
| 212 | (char *)newval); |
| 213 | } else |
| 214 | intval = (int) strtol(newval, NULL, 0); |
| 215 | newval = &intval; |
| 216 | newsize = sizeof(intval); |
| 217 | break; |
| 218 | case CTLTYPE_UINT: |
| 219 | uintval = (int) strtoul(newval, NULL, 0); |
| 220 | newval = &uintval; |
| 221 | newsize = sizeof uintval; |
| 222 | break; |
| 223 | case CTLTYPE_LONG: |
| 224 | longval = strtol(newval, NULL, 0); |
| 225 | newval = &longval; |
| 226 | newsize = sizeof longval; |
| 227 | break; |
| 228 | case CTLTYPE_ULONG: |
| 229 | ulongval = strtoul(newval, NULL, 0); |
| 230 | newval = &ulongval; |
| 231 | newsize = sizeof ulongval; |
| 232 | break; |
| 233 | case CTLTYPE_STRING: |
| 234 | break; |
| 235 | case CTLTYPE_QUAD: |
| 236 | quadval = strtoq(newval, NULL, 0); |
| 237 | newval = &quadval; |
| 238 | newsize = sizeof(quadval); |
| 239 | break; |
| 240 | case CTLTYPE_UQUAD: |
| 241 | uquadval = strtouq(newval, NULL, 0); |
| 242 | newval = &uquadval; |
| 243 | newsize = sizeof(uquadval); |
| 244 | break; |
| 245 | case CTLTYPE_OPAQUE: |
| 246 | if (strcmp(fmt, "T,dev_t") == 0 || |
| 247 | strcmp(fmt, "T,udev_t") == 0 |
| 248 | ) { |
| 249 | set_T_dev_t((char*)newval, &newval, |
| 250 | &newsize); |
| 251 | break; |
| 252 | } |
| 253 | /* FALLTHROUGH */ |
| 254 | default: |
| 255 | errx(1, "oid '%s' is type %d," |
| 256 | " cannot set that", name, |
| 257 | kind & CTLTYPE); |
| 258 | } |
| 259 | |
| 260 | i = show_var(mib, len); |
| 261 | if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { |
| 262 | if (!i && !bflag) |
| 263 | putchar('\n'); |
| 264 | switch (errno) { |
| 265 | case EOPNOTSUPP: |
| 266 | errx(1, "%s: value is not available", |
| 267 | string); |
| 268 | case ENOTDIR: |
| 269 | errx(1, "%s: specification is incomplete", |
| 270 | string); |
| 271 | case ENOMEM: |
| 272 | errx(1, "%s: type is unknown to this program", |
| 273 | string); |
| 274 | default: |
| 275 | warn("%s", string); |
| 276 | return; |
| 277 | } |
| 278 | } |
| 279 | if (!bflag) |
| 280 | printf(" -> "); |
| 281 | i = nflag; |
| 282 | nflag = 1; |
| 283 | j = show_var(mib, len); |
| 284 | if (!j && !bflag) |
| 285 | putchar('\n'); |
| 286 | nflag = i; |
| 287 | } |
| 288 | |
| 289 | if (name_allocated != NULL) |
| 290 | free(name_allocated); |
| 291 | } |
| 292 | |
| 293 | /* These functions will dump out various interesting structures. */ |
| 294 | |
| 295 | static int |
| 296 | S_clockinfo(int l2, void *p) |
| 297 | { |
| 298 | struct clockinfo *ci = (struct clockinfo*)p; |
| 299 | if (l2 != sizeof(*ci)) |
| 300 | err(1, "S_clockinfo %d != %zu", l2, sizeof(*ci)); |
| 301 | printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", |
| 302 | ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); |
| 303 | return (0); |
| 304 | } |
| 305 | |
| 306 | static int |
| 307 | S_loadavg(int l2, void *p) |
| 308 | { |
| 309 | struct loadavg *tv = (struct loadavg*)p; |
| 310 | |
| 311 | if (l2 != sizeof(*tv)) |
| 312 | err(1, "S_loadavg %d != %zu", l2, sizeof(*tv)); |
| 313 | |
| 314 | printf("{ %.2f %.2f %.2f }", |
| 315 | (double)tv->ldavg[0]/(double)tv->fscale, |
| 316 | (double)tv->ldavg[1]/(double)tv->fscale, |
| 317 | (double)tv->ldavg[2]/(double)tv->fscale); |
| 318 | return (0); |
| 319 | } |
| 320 | |
| 321 | static int |
| 322 | S_timespec(int l2, void *p) |
| 323 | { |
| 324 | struct timespec *ts = (struct timespec*)p; |
| 325 | time_t tv_sec; |
| 326 | char *p1, *p2; |
| 327 | |
| 328 | if (l2 != sizeof(*ts)) |
| 329 | err(1, "S_timespec %d != %zu", l2, sizeof(*ts)); |
| 330 | printf("{ sec = %ld, nsec = %ld } ", |
| 331 | ts->tv_sec, ts->tv_nsec); |
| 332 | tv_sec = ts->tv_sec; |
| 333 | p1 = strdup(ctime(&tv_sec)); |
| 334 | for (p2=p1; *p2 ; p2++) |
| 335 | if (*p2 == '\n') |
| 336 | *p2 = '\0'; |
| 337 | fputs(p1, stdout); |
| 338 | return (0); |
| 339 | } |
| 340 | |
| 341 | static int |
| 342 | S_timeval(int l2, void *p) |
| 343 | { |
| 344 | struct timeval *tv = (struct timeval*)p; |
| 345 | time_t tv_sec; |
| 346 | char *p1, *p2; |
| 347 | |
| 348 | if (l2 != sizeof(*tv)) |
| 349 | err(1, "S_timeval %d != %zu", l2, sizeof(*tv)); |
| 350 | printf("{ sec = %ld, usec = %ld } ", |
| 351 | tv->tv_sec, tv->tv_usec); |
| 352 | tv_sec = tv->tv_sec; |
| 353 | p1 = strdup(ctime(&tv_sec)); |
| 354 | for (p2=p1; *p2 ; p2++) |
| 355 | if (*p2 == '\n') |
| 356 | *p2 = '\0'; |
| 357 | fputs(p1, stdout); |
| 358 | return (0); |
| 359 | } |
| 360 | |
| 361 | static int |
| 362 | S_sensor(int l2, void *p) |
| 363 | { |
| 364 | struct sensor *s = (struct sensor *)p; |
| 365 | |
| 366 | if (l2 != sizeof(*s)) { |
| 367 | warnx("S_sensor %d != %zu", l2, sizeof(*s)); |
| 368 | return (1); |
| 369 | } |
| 370 | |
| 371 | if (s->flags & SENSOR_FINVALID) { |
| 372 | /* |
| 373 | * XXX: with this flag, the node should be entirely ignored, |
| 374 | * but as the magic-based sysctl(8) is not too flexible, we |
| 375 | * simply have to print out that the sensor is invalid. |
| 376 | */ |
| 377 | printf("invalid"); |
| 378 | return (0); |
| 379 | } |
| 380 | |
| 381 | if (s->flags & SENSOR_FUNKNOWN) |
| 382 | printf("unknown"); |
| 383 | else { |
| 384 | switch (s->type) { |
| 385 | case SENSOR_TEMP: |
| 386 | printf("%.2f degC", |
| 387 | (s->value - 273150000) / 1000000.0); |
| 388 | break; |
| 389 | case SENSOR_FANRPM: |
| 390 | printf("%jd RPM", (intmax_t)s->value); |
| 391 | break; |
| 392 | case SENSOR_VOLTS_DC: |
| 393 | printf("%.2f VDC", s->value / 1000000.0); |
| 394 | break; |
| 395 | case SENSOR_AMPS: |
| 396 | printf("%.2f A", s->value / 1000000.0); |
| 397 | break; |
| 398 | case SENSOR_WATTHOUR: |
| 399 | printf("%.2f Wh", s->value / 1000000.0); |
| 400 | break; |
| 401 | case SENSOR_AMPHOUR: |
| 402 | printf("%.2f Ah", s->value / 1000000.0); |
| 403 | break; |
| 404 | case SENSOR_INDICATOR: |
| 405 | printf("%s", s->value ? "On" : "Off"); |
| 406 | break; |
| 407 | case SENSOR_INTEGER: |
| 408 | printf("%jd", (intmax_t)s->value); |
| 409 | break; |
| 410 | case SENSOR_PERCENT: |
| 411 | printf("%.2f%%", s->value / 1000.0); |
| 412 | break; |
| 413 | case SENSOR_LUX: |
| 414 | printf("%.2f lx", s->value / 1000000.0); |
| 415 | break; |
| 416 | case SENSOR_DRIVE: |
| 417 | { |
| 418 | const char *name; |
| 419 | |
| 420 | switch (s->value) { |
| 421 | case SENSOR_DRIVE_EMPTY: |
| 422 | name = "empty"; |
| 423 | break; |
| 424 | case SENSOR_DRIVE_READY: |
| 425 | name = "ready"; |
| 426 | break; |
| 427 | case SENSOR_DRIVE_POWERUP: |
| 428 | name = "powering up"; |
| 429 | break; |
| 430 | case SENSOR_DRIVE_ONLINE: |
| 431 | name = "online"; |
| 432 | break; |
| 433 | case SENSOR_DRIVE_IDLE: |
| 434 | name = "idle"; |
| 435 | break; |
| 436 | case SENSOR_DRIVE_ACTIVE: |
| 437 | name = "active"; |
| 438 | break; |
| 439 | case SENSOR_DRIVE_REBUILD: |
| 440 | name = "rebuilding"; |
| 441 | break; |
| 442 | case SENSOR_DRIVE_POWERDOWN: |
| 443 | name = "powering down"; |
| 444 | break; |
| 445 | case SENSOR_DRIVE_FAIL: |
| 446 | name = "failed"; |
| 447 | break; |
| 448 | case SENSOR_DRIVE_PFAIL: |
| 449 | name = "degraded"; |
| 450 | break; |
| 451 | default: |
| 452 | name = "unknown"; |
| 453 | break; |
| 454 | } |
| 455 | printf(name); |
| 456 | break; |
| 457 | } |
| 458 | case SENSOR_TIMEDELTA: |
| 459 | printf("%.6f secs", s->value / 1000000000.0); |
| 460 | break; |
| 461 | default: |
| 462 | printf("unknown"); |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | if (s->desc[0] != '\0') |
| 467 | printf(" (%s)", s->desc); |
| 468 | |
| 469 | switch (s->status) { |
| 470 | case SENSOR_S_UNSPEC: |
| 471 | break; |
| 472 | case SENSOR_S_OK: |
| 473 | printf(", OK"); |
| 474 | break; |
| 475 | case SENSOR_S_WARN: |
| 476 | printf(", WARNING"); |
| 477 | break; |
| 478 | case SENSOR_S_CRIT: |
| 479 | printf(", CRITICAL"); |
| 480 | break; |
| 481 | case SENSOR_S_UNKNOWN: |
| 482 | printf(", UNKNOWN"); |
| 483 | break; |
| 484 | } |
| 485 | |
| 486 | if (s->tv.tv_sec) { |
| 487 | time_t t = s->tv.tv_sec; |
| 488 | char ct[26]; |
| 489 | |
| 490 | ctime_r(&t, ct); |
| 491 | ct[19] = '\0'; |
| 492 | printf(", %s.%03ld", ct, s->tv.tv_usec / 1000); |
| 493 | } |
| 494 | |
| 495 | return (0); |
| 496 | } |
| 497 | |
| 498 | static int |
| 499 | T_dev_t(int l2, void *p) |
| 500 | { |
| 501 | dev_t *d = (dev_t *)p; |
| 502 | if (l2 != sizeof(*d)) |
| 503 | err(1, "T_dev_T %d != %zu", l2, sizeof(*d)); |
| 504 | if ((int)(*d) != -1) { |
| 505 | if (minor(*d) > 255 || minor(*d) < 0) |
| 506 | printf("{ major = %d, minor = 0x%x }", |
| 507 | major(*d), minor(*d)); |
| 508 | else |
| 509 | printf("{ major = %d, minor = %d }", |
| 510 | major(*d), minor(*d)); |
| 511 | } |
| 512 | return (0); |
| 513 | } |
| 514 | |
| 515 | static void |
| 516 | set_T_dev_t(const char *path, void **val, size_t *size) |
| 517 | { |
| 518 | static struct stat statb; |
| 519 | |
| 520 | if (strcmp(path, "none") && strcmp(path, "off")) { |
| 521 | int rc = stat (path, &statb); |
| 522 | if (rc) { |
| 523 | err(1, "cannot stat %s", path); |
| 524 | } |
| 525 | |
| 526 | if (!S_ISCHR(statb.st_mode)) { |
| 527 | errx(1, "must specify a device special file."); |
| 528 | } |
| 529 | } else { |
| 530 | statb.st_rdev = NODEV; |
| 531 | } |
| 532 | *val = (char*) &statb.st_rdev; |
| 533 | *size = sizeof statb.st_rdev; |
| 534 | } |
| 535 | |
| 536 | static int |
| 537 | set_IK(const char *str, int *val) |
| 538 | { |
| 539 | float temp; |
| 540 | int len, kelv; |
| 541 | const char *p; |
| 542 | char *endptr; |
| 543 | |
| 544 | if ((len = strlen(str)) == 0) |
| 545 | return (0); |
| 546 | p = &str[len - 1]; |
| 547 | if (*p == 'C' || *p == 'F') { |
| 548 | temp = strtof(str, &endptr); |
| 549 | if (endptr == str || endptr != p) |
| 550 | return 0; |
| 551 | if (*p == 'F') |
| 552 | temp = (temp - 32) * 5 / 9; |
| 553 | kelv = temp * 10 + 2732; |
| 554 | } else { |
| 555 | kelv = (int)strtol(str, &endptr, 10); |
| 556 | if (endptr == str || *endptr != '\0') |
| 557 | return 0; |
| 558 | } |
| 559 | *val = kelv; |
| 560 | return 1; |
| 561 | } |
| 562 | |
| 563 | /* |
| 564 | * These functions uses a presently undocumented interface to the kernel |
| 565 | * to walk the tree and get the type so it can print the value. |
| 566 | * This interface is under work and consideration, and should probably |
| 567 | * be killed with a big axe by the first person who can find the time. |
| 568 | * (be aware though, that the proper interface isn't as obvious as it |
| 569 | * may seem, there are various conflicting requirements. |
| 570 | */ |
| 571 | |
| 572 | static int |
| 573 | oidfmt(int *oid, size_t len, char *fmt, u_int *kind) |
| 574 | { |
| 575 | int qoid[CTL_MAXNAME+2]; |
| 576 | u_char buf[BUFSIZ]; |
| 577 | int i; |
| 578 | size_t j; |
| 579 | |
| 580 | qoid[0] = 0; |
| 581 | qoid[1] = 4; |
| 582 | memcpy(qoid + 2, oid, len * sizeof(int)); |
| 583 | |
| 584 | j = sizeof(buf); |
| 585 | i = sysctl(qoid, len + 2, buf, &j, 0, 0); |
| 586 | if (i) |
| 587 | err(1, "sysctl fmt %d %zu %d", i, j, errno); |
| 588 | |
| 589 | if (kind) |
| 590 | *kind = *(u_int *)buf; |
| 591 | |
| 592 | if (fmt) |
| 593 | strcpy(fmt, (char *)(buf + sizeof(u_int))); |
| 594 | return 0; |
| 595 | } |
| 596 | |
| 597 | #ifdef __i386__ |
| 598 | /* |
| 599 | * Code to map a bootdev major number into a suitable device name. |
| 600 | * Major numbers are mapped into names as in boot2.c |
| 601 | */ |
| 602 | struct _foo { |
| 603 | int majdev; |
| 604 | const char *name; |
| 605 | } maj2name[] = { |
| 606 | { 30, "ad" }, |
| 607 | { 0, "wd" }, |
| 608 | { 1, "wfd" }, |
| 609 | { 2, "fd" }, |
| 610 | { 4, "da" }, |
| 611 | { -1, NULL } /* terminator */ |
| 612 | }; |
| 613 | |
| 614 | static int |
| 615 | machdep_bootdev(u_long value) |
| 616 | { |
| 617 | int majdev, unit, slice, part; |
| 618 | struct _foo *p; |
| 619 | |
| 620 | if ((value & B_MAGICMASK) != B_DEVMAGIC) { |
| 621 | printf("invalid (0x%08lx)", value); |
| 622 | return 0; |
| 623 | } |
| 624 | majdev = B_TYPE(value); |
| 625 | unit = B_UNIT(value); |
| 626 | slice = B_SLICE(value); |
| 627 | part = B_PARTITION(value); |
| 628 | if (majdev == 2) { /* floppy, as known to the boot block... */ |
| 629 | printf("/dev/fd%d", unit); |
| 630 | return 0; |
| 631 | } |
| 632 | for (p = maj2name; p->name != NULL && p->majdev != majdev ; p++) ; |
| 633 | if (p->name != NULL) { /* found */ |
| 634 | if (slice == WHOLE_DISK_SLICE) |
| 635 | printf("/dev/%s%d%c", p->name, unit, part); |
| 636 | else |
| 637 | printf("/dev/%s%ds%d%c", |
| 638 | p->name, unit, slice - BASE_SLICE + 1, part + 'a'); |
| 639 | } else |
| 640 | printf("unknown (major %d unit %d slice %d part %d)", |
| 641 | majdev, unit, slice, part); |
| 642 | return 0; |
| 643 | } |
| 644 | #endif |
| 645 | |
| 646 | /* |
| 647 | * This formats and outputs the value of one variable |
| 648 | * |
| 649 | * Returns zero if anything was actually output. |
| 650 | * Returns one if didn't know what to do with this. |
| 651 | * Return minus one if we had errors. |
| 652 | */ |
| 653 | |
| 654 | static int |
| 655 | show_var(int *oid, size_t nlen) |
| 656 | { |
| 657 | u_char buf[BUFSIZ], *val = NULL, *p, *nul; |
| 658 | char name[BUFSIZ], *fmt; |
| 659 | const char *sep, *spacer; |
| 660 | int qoid[CTL_MAXNAME+2]; |
| 661 | int i; |
| 662 | size_t j, len; |
| 663 | u_int kind; |
| 664 | int (*func)(int, void *); |
| 665 | int error = 0; |
| 666 | |
| 667 | qoid[0] = 0; |
| 668 | memcpy(qoid + 2, oid, nlen * sizeof(int)); |
| 669 | |
| 670 | qoid[1] = 1; |
| 671 | j = sizeof(name); |
| 672 | i = sysctl(qoid, nlen + 2, name, &j, 0, 0); |
| 673 | if (i || !j) |
| 674 | err(1, "sysctl name %d %zu %d", i, j, errno); |
| 675 | |
| 676 | if (Nflag) { |
| 677 | printf("%s", name); |
| 678 | return (0); |
| 679 | } |
| 680 | |
| 681 | if (eflag) |
| 682 | sep = "="; |
| 683 | else |
| 684 | sep = ": "; |
| 685 | |
| 686 | if (dflag) { /* just print description */ |
| 687 | qoid[1] = 5; |
| 688 | j = sizeof(buf); |
| 689 | i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); |
| 690 | if (!nflag) |
| 691 | printf("%s%s", name, sep); |
| 692 | printf("%s", buf); |
| 693 | return(0); |
| 694 | } |
| 695 | /* find an estimate of how much we need for this var */ |
| 696 | j = 0; |
| 697 | i = sysctl(oid, nlen, 0, &j, 0, 0); |
| 698 | j += j; /* we want to be sure :-) */ |
| 699 | |
| 700 | val = malloc(j + 1); |
| 701 | if (val == NULL) |
| 702 | return (1); |
| 703 | |
| 704 | len = j; |
| 705 | i = sysctl(oid, nlen, val, &len, 0, 0); |
| 706 | if (i || !len) { |
| 707 | error = 1; |
| 708 | goto done; |
| 709 | } |
| 710 | |
| 711 | if (bflag) { |
| 712 | fwrite(val, 1, len, stdout); |
| 713 | goto done; |
| 714 | } |
| 715 | |
| 716 | val[len] = '\0'; |
| 717 | fmt = buf; |
| 718 | oidfmt(oid, nlen, fmt, &kind); |
| 719 | p = val; |
| 720 | switch (*fmt) { |
| 721 | case 'A': |
| 722 | if (!nflag) |
| 723 | printf("%s%s", name, sep); |
| 724 | nul = memchr(p, '\0', len); |
| 725 | fwrite(p, nul == NULL ? (int)len : nul - p, 1, stdout); |
| 726 | return (0); |
| 727 | |
| 728 | case 'I': |
| 729 | if (!nflag) |
| 730 | printf("%s%s", name, sep); |
| 731 | fmt++; |
| 732 | spacer = ""; |
| 733 | while (len >= sizeof(int)) { |
| 734 | if(*fmt == 'U') |
| 735 | printf("%s%u", spacer, *(unsigned int *)p); |
| 736 | else if (*fmt == 'K' && *(int *)p >= 0) |
| 737 | printf("%s%.1fC", spacer, (*(int *)p - 2732) / 10.0); |
| 738 | else |
| 739 | printf("%s%d", spacer, *(int *)p); |
| 740 | spacer = " "; |
| 741 | len -= sizeof(int); |
| 742 | p += sizeof(int); |
| 743 | } |
| 744 | goto done; |
| 745 | |
| 746 | case 'L': |
| 747 | if (!nflag) |
| 748 | printf("%s%s", name, sep); |
| 749 | fmt++; |
| 750 | #ifdef __i386__ |
| 751 | if (!strcmp(name, "machdep.guessed_bootdev")) |
| 752 | return machdep_bootdev(*(unsigned long *)p); |
| 753 | #endif |
| 754 | spacer = ""; |
| 755 | while (len >= sizeof(long)) { |
| 756 | if(*fmt == 'U') |
| 757 | printf("%s%lu", spacer, *(unsigned long *)p); |
| 758 | else |
| 759 | printf("%s%ld", spacer, *(long *)p); |
| 760 | spacer = " "; |
| 761 | len -= sizeof(long); |
| 762 | p += sizeof(long); |
| 763 | } |
| 764 | goto done; |
| 765 | |
| 766 | case 'P': |
| 767 | if (!nflag) |
| 768 | printf("%s%s", name, sep); |
| 769 | printf("%p", *(void **)p); |
| 770 | goto done; |
| 771 | |
| 772 | case 'Q': |
| 773 | if (!nflag) |
| 774 | printf("%s%s", name, sep); |
| 775 | fmt++; |
| 776 | spacer = ""; |
| 777 | while (len >= sizeof(quad_t)) { |
| 778 | if(*fmt == 'U') { |
| 779 | printf("%s%ju", |
| 780 | spacer, (uintmax_t)*(u_quad_t *)p); |
| 781 | } else { |
| 782 | printf("%s%jd", |
| 783 | spacer, (intmax_t)*(quad_t *)p); |
| 784 | } |
| 785 | spacer = " "; |
| 786 | len -= sizeof(int64_t); |
| 787 | p += sizeof(int64_t); |
| 788 | } |
| 789 | goto done; |
| 790 | |
| 791 | case 'T': |
| 792 | case 'S': |
| 793 | if (!oflag && !xflag) { |
| 794 | i = 0; |
| 795 | if (strcmp(fmt, "S,clockinfo") == 0) |
| 796 | func = S_clockinfo; |
| 797 | else if (strcmp(fmt, "S,timespec") == 0) |
| 798 | func = S_timespec; |
| 799 | else if (strcmp(fmt, "S,timeval") == 0) |
| 800 | func = S_timeval; |
| 801 | else if (strcmp(fmt, "S,loadavg") == 0) |
| 802 | func = S_loadavg; |
| 803 | else if (strcmp(fmt, "S,sensor") == 0) |
| 804 | func = S_sensor; |
| 805 | else if (strcmp(fmt, "T,dev_t") == 0) |
| 806 | func = T_dev_t; |
| 807 | else if (strcmp(fmt, "T,udev_t") == 0) |
| 808 | func = T_dev_t; |
| 809 | else |
| 810 | func = NULL; |
| 811 | if (func) { |
| 812 | if (!nflag) |
| 813 | printf("%s%s", name, sep); |
| 814 | error = (*func)(len, p); |
| 815 | goto done; |
| 816 | } |
| 817 | } |
| 818 | /* FALL THROUGH */ |
| 819 | default: |
| 820 | if (!oflag && !xflag) { |
| 821 | error = 1; |
| 822 | goto done; |
| 823 | } |
| 824 | if (!nflag) |
| 825 | printf("%s%s", name, sep); |
| 826 | printf("Format:%s Length:%zu Dump:0x", fmt, len); |
| 827 | while (len-- && (xflag || p < val + 16)) |
| 828 | printf("%02x", *p++); |
| 829 | if (!xflag && len > 16) |
| 830 | printf("..."); |
| 831 | goto done; |
| 832 | } |
| 833 | |
| 834 | done: |
| 835 | if (val != NULL) |
| 836 | free(val); |
| 837 | return (error); |
| 838 | } |
| 839 | |
| 840 | static int |
| 841 | sysctl_all(int *oid, size_t len) |
| 842 | { |
| 843 | int name1[22], name2[22]; |
| 844 | int retval; |
| 845 | size_t i, l1, l2; |
| 846 | |
| 847 | name1[0] = 0; |
| 848 | name1[1] = 2; |
| 849 | l1 = 2; |
| 850 | if (len) { |
| 851 | memcpy(name1+2, oid, len * sizeof(int)); |
| 852 | l1 += len; |
| 853 | } else { |
| 854 | name1[2] = 1; |
| 855 | l1++; |
| 856 | } |
| 857 | for (;;) { |
| 858 | l2 = sizeof(name2); |
| 859 | retval = sysctl(name1, l1, name2, &l2, 0, 0); |
| 860 | if (retval < 0) { |
| 861 | if (errno == ENOENT) |
| 862 | return 0; |
| 863 | else |
| 864 | err(1, "sysctl(getnext) %d %zu", retval, l2); |
| 865 | } |
| 866 | |
| 867 | l2 /= sizeof(int); |
| 868 | |
| 869 | if (l2 < len) |
| 870 | return 0; |
| 871 | |
| 872 | for (i = 0; i < len; i++) |
| 873 | if (name2[i] != oid[i]) |
| 874 | return 0; |
| 875 | |
| 876 | retval = show_var(name2, l2); |
| 877 | if (retval == 0 && !bflag) |
| 878 | putchar('\n'); |
| 879 | |
| 880 | memcpy(name1+2, name2, l2 * sizeof(int)); |
| 881 | l1 = 2 + l2; |
| 882 | } |
| 883 | } |