]> git.saurik.com Git - apple/system_cmds.git/blob - sysctl.tproj/sysctl.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / sysctl.tproj / sysctl.c
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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 #ifndef lint
32 __unused static const char copyright[] =
33 "@(#) Copyright (c) 1993\n\
34 The Regents of the University of California. All rights reserved.\n";
35 #endif /* not lint */
36
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93";
40 #endif
41 __unused static const char rcsid[] =
42 "$FreeBSD$";
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <sys/stat.h>
49 #include <sys/sysctl.h>
50 #ifdef __APPLE__
51 #include <mach/machine/vm_param.h>
52 #include <mach/machine/vm_types.h>
53 #include <mach/mach_types.h>
54 #else // !__APPLE__
55 #include <sys/vmmeter.h>
56 #endif // !__APPLE__
57
58 #include <ctype.h>
59 #include <err.h>
60 #include <errno.h>
61 #include <inttypes.h>
62 #include <locale.h>
63 #ifdef __APPLE__
64 #endif
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <unistd.h>
69
70 static int aflag, bflag, dflag, eflag, hflag, iflag;
71 static int Nflag, nflag, oflag, qflag, xflag, warncount;
72
73 static int oidfmt(int *, int, char *, u_int *);
74 static void parse(const char *);
75 #ifdef __APPLE__
76 static int show_var(int *, int, int);
77 #else
78 static int show_var(int *, int);
79 #endif
80 static int sysctl_all(int *oid, int len);
81 static int name2oid(char *, int *);
82
83 #ifndef __APPLE__
84 static int set_IK(const char *, int *);
85 #endif
86
87 #ifdef __APPLE__
88 // Shims for FreeBSD source compatibility.
89 #define CTLTYPE_UINT 0xa
90 #define CTLTYPE_LONG 0xb
91 #define CTLTYPE_ULONG 0xc
92 #define CTLTYPE_S64 0xd
93 #define CTLTYPE_U64 0xe
94
95 #define CTLFLAG_TUN 0
96
97 // Support for CTL_USER
98 const struct ctlname names[] = CTL_NAMES;
99 const struct ctlname user_names[] = CTL_USER_NAMES;
100 const int user_names_count = sizeof(user_names) / sizeof(*user_names);
101 #endif
102
103 static void
104 usage(void)
105 {
106
107 (void)fprintf(stderr, "%s\n%s\n",
108 "usage: sysctl [-bdehiNnoqx] name[=value] ...",
109 " sysctl [-bdehNnoqx] -a");
110 exit(1);
111 }
112
113 int
114 main(int argc, char **argv)
115 {
116 int ch;
117
118 setlocale(LC_NUMERIC, "");
119 setbuf(stdout,0);
120 setbuf(stderr,0);
121
122 while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) {
123 switch (ch) {
124 case 'A':
125 /* compatibility */
126 aflag = oflag = 1;
127 break;
128 case 'a':
129 aflag = 1;
130 break;
131 case 'b':
132 bflag = 1;
133 break;
134 case 'd':
135 dflag = 1;
136 break;
137 case 'e':
138 eflag = 1;
139 break;
140 case 'h':
141 hflag = 1;
142 break;
143 case 'i':
144 iflag = 1;
145 break;
146 case 'N':
147 Nflag = 1;
148 break;
149 case 'n':
150 nflag = 1;
151 break;
152 case 'o':
153 oflag = 1;
154 break;
155 case 'q':
156 qflag = 1;
157 break;
158 case 'w':
159 /* compatibility */
160 /* ignored */
161 break;
162 case 'X':
163 /* compatibility */
164 aflag = xflag = 1;
165 break;
166 case 'x':
167 xflag = 1;
168 break;
169 default:
170 usage();
171 }
172 }
173 argc -= optind;
174 argv += optind;
175
176 if (Nflag && nflag)
177 usage();
178 if (aflag && argc == 0)
179 exit(sysctl_all(0, 0));
180 if (argc == 0)
181 usage();
182
183 warncount = 0;
184 while (argc-- > 0)
185 parse(*argv++);
186 exit(warncount);
187 }
188
189 /*
190 * Parse a name into a MIB entry.
191 * Lookup and print out the MIB entry if it exists.
192 * Set a new value if requested.
193 */
194 static void
195 parse(const char *string)
196 {
197 int len, i, j;
198 void *newval = 0;
199 int intval;
200 unsigned int uintval;
201 long longval;
202 unsigned long ulongval;
203 size_t newsize = 0;
204 int64_t i64val;
205 uint64_t u64val;
206 int mib[CTL_MAXNAME];
207 char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ];
208 u_int kind;
209
210 cp = buf;
211 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
212 errx(1, "oid too long: '%s'", string);
213 bufp = strsep(&cp, "=");
214 if (cp != NULL) {
215 while (isspace(*cp))
216 cp++;
217 newval = cp;
218 newsize = strlen(cp);
219 }
220 len = name2oid(bufp, mib);
221
222 if (len < 0) {
223 if (iflag)
224 return;
225 if (qflag)
226 exit(1);
227 else
228 errx(1, "unknown oid '%s'", bufp);
229 }
230
231 if (oidfmt(mib, len, fmt, &kind))
232 err(1, "couldn't find format of oid '%s'", bufp);
233
234 if (newval == NULL || dflag) {
235 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
236 if (dflag) {
237 #ifdef __APPLE__
238 i = show_var(mib, len, 1);
239 #else
240 i = show_var(mib, len);
241 #endif
242 if (!i && !bflag)
243 putchar('\n');
244 }
245 sysctl_all(mib, len);
246 } else {
247 #ifdef __APPLE__
248 i = show_var(mib, len, 1);
249 #else
250 i = show_var(mib, len);
251 #endif
252 if (!i && !bflag)
253 putchar('\n');
254 }
255 } else {
256 if ((kind & CTLTYPE) == CTLTYPE_NODE)
257 errx(1, "oid '%s' isn't a leaf node", bufp);
258
259 if (!(kind & CTLFLAG_WR)) {
260 if (kind & CTLFLAG_TUN) {
261 warnx("oid '%s' is a read only tunable", bufp);
262 errx(1, "Tunable values are set in /boot/loader.conf");
263 } else {
264 errx(1, "oid '%s' is read only", bufp);
265 }
266 }
267
268 if ((kind & CTLTYPE) == CTLTYPE_INT ||
269 (kind & CTLTYPE) == CTLTYPE_UINT ||
270 (kind & CTLTYPE) == CTLTYPE_LONG ||
271 (kind & CTLTYPE) == CTLTYPE_ULONG ||
272 (kind & CTLTYPE) == CTLTYPE_S64 ||
273 (kind & CTLTYPE) == CTLTYPE_U64) {
274 if (strlen(newval) == 0)
275 errx(1, "empty numeric value");
276 }
277
278 switch (kind & CTLTYPE) {
279 case CTLTYPE_INT:
280 if (strcmp(fmt, "IK") == 0) {
281 #ifndef __APPLE__
282 if (!set_IK(newval, &intval))
283 #endif
284 errx(1, "invalid value '%s'",
285 (char *)newval);
286 } else {
287 intval = (int)strtol(newval, &endptr,
288 0);
289 if (endptr == newval || *endptr != '\0')
290 errx(1, "invalid integer '%s'",
291 (char *)newval);
292 }
293 newval = &intval;
294 newsize = sizeof(intval);
295 break;
296 case CTLTYPE_UINT:
297 uintval = (int) strtoul(newval, &endptr, 0);
298 if (endptr == newval || *endptr != '\0')
299 errx(1, "invalid unsigned integer '%s'",
300 (char *)newval);
301 newval = &uintval;
302 newsize = sizeof(uintval);
303 break;
304 case CTLTYPE_LONG:
305 longval = strtol(newval, &endptr, 0);
306 if (endptr == newval || *endptr != '\0')
307 errx(1, "invalid long integer '%s'",
308 (char *)newval);
309 newval = &longval;
310 newsize = sizeof(longval);
311 break;
312 case CTLTYPE_ULONG:
313 ulongval = strtoul(newval, &endptr, 0);
314 if (endptr == newval || *endptr != '\0')
315 errx(1, "invalid unsigned long integer"
316 " '%s'", (char *)newval);
317 newval = &ulongval;
318 newsize = sizeof(ulongval);
319 break;
320 case CTLTYPE_STRING:
321 break;
322 case CTLTYPE_S64:
323 i64val = strtoimax(newval, &endptr, 0);
324 if (endptr == newval || *endptr != '\0')
325 errx(1, "invalid int64_t '%s'",
326 (char *)newval);
327 newval = &i64val;
328 newsize = sizeof(i64val);
329 break;
330 case CTLTYPE_U64:
331 u64val = strtoumax(newval, &endptr, 0);
332 if (endptr == newval || *endptr != '\0')
333 errx(1, "invalid uint64_t '%s'",
334 (char *)newval);
335 newval = &u64val;
336 newsize = sizeof(u64val);
337 break;
338 case CTLTYPE_OPAQUE:
339 /* FALLTHROUGH */
340 default:
341 errx(1, "oid '%s' is type %d,"
342 " cannot set that", bufp,
343 kind & CTLTYPE);
344 }
345
346 #ifdef __APPLE__
347 i = show_var(mib, len, 1);
348 #else
349 i = show_var(mib, len);
350 #endif
351 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
352 if (!i && !bflag)
353 putchar('\n');
354 switch (errno) {
355 #ifdef __APPLE__
356 case ENOTSUP:
357 #endif // __APPLE__
358 case EOPNOTSUPP:
359 errx(1, "%s: value is not available",
360 string);
361 case ENOTDIR:
362 errx(1, "%s: specification is incomplete",
363 string);
364 case ENOMEM:
365 errx(1, "%s: type is unknown to this program",
366 string);
367 default:
368 warn("%s", string);
369 warncount++;
370 return;
371 }
372 }
373 if (!bflag)
374 printf(" -> ");
375 i = nflag;
376 nflag = 1;
377 #ifdef __APPLE__
378 j = show_var(mib, len, 1);
379 #else
380 j = show_var(mib, len);
381 #endif
382 if (!j && !bflag)
383 putchar('\n');
384 nflag = i;
385 }
386 }
387
388 /* These functions will dump out various interesting structures. */
389
390 static int
391 S_clockinfo(int l2, void *p)
392 {
393 struct clockinfo *ci = (struct clockinfo*)p;
394
395 if (l2 != sizeof(*ci)) {
396 warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
397 return (1);
398 }
399 #ifdef __APPLE__
400 printf(hflag ? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" :
401 "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
402 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
403 #else
404 printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
405 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
406 ci->hz, ci->tick, ci->profhz, ci->stathz);
407 #endif
408 return (0);
409 }
410
411 static int
412 S_loadavg(int l2, void *p)
413 {
414 struct loadavg *tv = (struct loadavg*)p;
415
416 if (l2 != sizeof(*tv)) {
417 warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
418 return (1);
419 }
420 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
421 (double)tv->ldavg[0]/(double)tv->fscale,
422 (double)tv->ldavg[1]/(double)tv->fscale,
423 (double)tv->ldavg[2]/(double)tv->fscale);
424 return (0);
425 }
426
427 static int
428 S_timeval(int l2, void *p)
429 {
430 struct timeval *tv = (struct timeval*)p;
431 time_t tv_sec;
432 char *p1, *p2;
433
434 if (l2 != sizeof(*tv)) {
435 warnx("S_timeval %d != %zu", l2, sizeof(*tv));
436 return (1);
437 }
438 printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
439 "{ sec = %jd, usec = %ld } ",
440 (intmax_t)tv->tv_sec, (long)tv->tv_usec);
441 tv_sec = tv->tv_sec;
442 p1 = strdup(ctime(&tv_sec));
443 for (p2=p1; *p2 ; p2++)
444 if (*p2 == '\n')
445 *p2 = '\0';
446 fputs(p1, stdout);
447 free(p1);
448 return (0);
449 }
450
451 #ifndef __APPLE__
452 static int
453 S_vmtotal(int l2, void *p)
454 {
455 struct vmtotal *v = (struct vmtotal *)p;
456 int pageKilo = getpagesize() / 1024;
457
458 if (l2 != sizeof(*v)) {
459 warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
460 return (1);
461 }
462
463 printf(
464 "\nSystem wide totals computed every five seconds:"
465 " (values in kilobytes)\n");
466 printf("===============================================\n");
467 printf(
468 "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
469 "%hd Sleep: %hd)\n",
470 v->t_rq, v->t_dw, v->t_pw, v->t_sl);
471 printf(
472 "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
473 v->t_vm * pageKilo, v->t_avm * pageKilo);
474 printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
475 v->t_rm * pageKilo, v->t_arm * pageKilo);
476 printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
477 v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
478 printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
479 v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
480 printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
481
482 return (0);
483 }
484
485 static int
486 set_IK(const char *str, int *val)
487 {
488 float temp;
489 int len, kelv;
490 const char *p;
491 char *endptr;
492
493 if ((len = strlen(str)) == 0)
494 return (0);
495 p = &str[len - 1];
496 if (*p == 'C' || *p == 'F') {
497 temp = strtof(str, &endptr);
498 if (endptr == str || endptr != p)
499 return (0);
500 if (*p == 'F')
501 temp = (temp - 32) * 5 / 9;
502 kelv = temp * 10 + 2732;
503 } else {
504 kelv = (int)strtol(str, &endptr, 10);
505 if (endptr == str || *endptr != '\0')
506 return (0);
507 }
508 *val = kelv;
509 return (1);
510 }
511 #endif // !__APPLE__
512
513 #ifdef __APPLE__
514 static int
515 S_xswusage(int l2, void *p)
516 {
517 struct xsw_usage *xsu = (struct xsw_usage *)p;
518
519 if (l2 != sizeof(*xsu)) {
520 warnx("S_xswusage %d != %ld", l2, sizeof(*xsu));
521 return (1);
522 }
523 fprintf(stdout,
524 "total = %.2fM used = %.2fM free = %.2fM %s",
525 ((double)xsu->xsu_total) / (1024.0 * 1024.0),
526 ((double)xsu->xsu_used) / (1024.0 * 1024.0),
527 ((double)xsu->xsu_avail) / (1024.0 * 1024.0),
528 xsu->xsu_encrypted ? "(encrypted)" : "");
529 return (0);
530 }
531
532 static int
533 T_dev_t(int l2, void *p)
534 {
535 dev_t *d = (dev_t *)p;
536
537 if (l2 != sizeof(*d)) {
538 warnx("T_dev_T %d != %ld", l2, sizeof(*d));
539 return (1);
540 }
541 if ((int)(*d) != -1) {
542 if (minor(*d) > 255 || minor(*d) < 0)
543 printf("{ major = %d, minor = 0x%x }",
544 major(*d), minor(*d));
545 else
546 printf("{ major = %d, minor = %d }",
547 major(*d), minor(*d));
548 }
549 return (0);
550 }
551
552 static int
553 S_quads(int len, void *p)
554 {
555 size_t size = sizeof(int64_t);
556 if (len & (size-1)) {
557 return 1;
558 }
559 while (len > 0) {
560 int64_t i = *(int64_t *)p;
561 printf("%llu", i);
562 if (len > size) {
563 len -= size;
564 p = (uintptr_t)p + size;
565 printf(" ");
566 } else {
567 break;
568 }
569 }
570 return 0;
571 }
572 #endif // __APPLE__
573
574 /*
575 * These functions uses a presently undocumented interface to the kernel
576 * to walk the tree and get the type so it can print the value.
577 * This interface is under work and consideration, and should probably
578 * be killed with a big axe by the first person who can find the time.
579 * (be aware though, that the proper interface isn't as obvious as it
580 * may seem, there are various conflicting requirements.
581 */
582
583 static int
584 name2oid(char *name, int *oidp)
585 {
586 int oid[2];
587 int i;
588 size_t j;
589
590 #ifdef __APPLE__
591 // Support for CTL_USER
592 const char *user = names[CTL_USER].ctl_name;
593 j = strlen(user);
594 if (!strncmp(name, user, j)) {
595 oidp[0] = CTL_USER;
596 if (name[j] == '.') {
597 for (i = 1; i < user_names_count; ++i) {
598 if (!strcmp(&name[j+1], user_names[i].ctl_name)) {
599 oidp[1] = i;
600 return 2;
601 }
602 }
603 return -1;
604 } else if (name[j] == 0) {
605 return 1;
606 }
607 return -1;
608 }
609 #endif
610
611 oid[0] = 0;
612 oid[1] = 3;
613
614 j = CTL_MAXNAME * sizeof(int);
615 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
616 if (i < 0)
617 return (i);
618 j /= sizeof(int);
619 return (int)j;
620 }
621
622 static int
623 oidfmt(int *oid, int len, char *fmt, u_int *kind)
624 {
625 int qoid[CTL_MAXNAME+2];
626 u_char buf[BUFSIZ];
627 int i;
628 size_t j;
629
630 qoid[0] = 0;
631 qoid[1] = 4;
632 memcpy(qoid + 2, oid, len * sizeof(int));
633
634 j = sizeof(buf);
635 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
636 #ifdef __APPLE__
637 if (i && errno == ENOENT) {
638 // Support for CTL_USER
639 if (oid[0] == CTL_USER) {
640 if (len == 1) {
641 *kind = CTLTYPE_NODE;
642 return 0;
643 } else if (len == 2 && oid[1] < user_names_count) {
644 *kind = user_names[oid[1]].ctl_type;
645 return 0;
646 }
647 }
648 return 1;
649 }
650 #endif
651 if (i)
652 err(1, "sysctl fmt %d %zu %d", i, j, errno);
653
654 if (kind)
655 #ifdef __APPLE__
656 memcpy(kind, buf, sizeof(*kind));
657 #else
658 *kind = *(u_int *)buf;
659 #endif
660
661 if (fmt)
662 strcpy(fmt, (char *)(buf + sizeof(u_int)));
663
664 #ifdef __APPLE__
665 // Map Darwin sysctl types to FreeBSD types.
666 // - 0 with "I" -> CTLTYPE_INT
667 // - 0 with "S," -> CTLTYPE_STRUCT
668 // - CTLTYPE_INT with "IU" -> CTLTYPE_UINT
669 // - CTLTYPE_INT with "L" -> CTLTYPE_LONG
670 // - CTLTYPE_QUAD -> CTLTYPE_S64
671 // - CTLTYPE_QUAD with "*U" -> CTLTYPE_U64
672 if (kind) {
673 switch (*kind & CTLTYPE) {
674 case 0:
675 case CTLTYPE_INT:
676 if (buf[sizeof(u_int)] == 'S') {
677 *kind = (*kind & ~CTLTYPE) | CTLTYPE_STRUCT;
678 } else if (buf[sizeof(u_int)] == 'I') {
679 *kind = (*kind & ~CTLTYPE) | CTLTYPE_INT;
680 if (buf[sizeof(u_int)+1] == 'U') {
681 *kind = (*kind & ~CTLTYPE) | CTLTYPE_UINT;
682 }
683 } else if (buf[sizeof(u_int)] == 'L') {
684 *kind = (*kind & ~CTLTYPE) | CTLTYPE_LONG;
685 if (buf[sizeof(u_int)+1] == 'U') {
686 *kind = (*kind & ~CTLTYPE) | CTLTYPE_ULONG;
687 }
688 }
689 break;
690 case CTLTYPE_QUAD:
691 *kind = (*kind & ~CTLTYPE);
692 if (fmt && strchr(fmt, 'U')) {
693 *kind |= CTLTYPE_U64;
694 } else {
695 *kind |= CTLTYPE_S64;
696 }
697 break;
698 }
699 }
700 #endif
701
702 return (0);
703 }
704
705 static int ctl_sign[CTLTYPE+1] = {
706 [CTLTYPE_INT] = 1,
707 [CTLTYPE_LONG] = 1,
708 [CTLTYPE_S64] = 1,
709 };
710
711 static int ctl_size[CTLTYPE+1] = {
712 [CTLTYPE_INT] = sizeof(int),
713 [CTLTYPE_UINT] = sizeof(u_int),
714 [CTLTYPE_LONG] = sizeof(long),
715 [CTLTYPE_ULONG] = sizeof(u_long),
716 [CTLTYPE_S64] = sizeof(int64_t),
717 [CTLTYPE_U64] = sizeof(int64_t),
718 };
719
720 /*
721 * This formats and outputs the value of one variable
722 *
723 * Returns zero if anything was actually output.
724 * Returns one if didn't know what to do with this.
725 * Return minus one if we had errors.
726 */
727 static int
728 #ifdef __APPLE__
729 show_var(int *oid, int nlen, int show_masked)
730 #else
731 show_var(int *oid, int nlen)
732 #endif
733 {
734 u_char buf[BUFSIZ], *val, *oval, *p;
735 char name[BUFSIZ], *fmt;
736 const char *sep, *sep1;
737 int qoid[CTL_MAXNAME+2];
738 uintmax_t umv;
739 intmax_t mv;
740 int i, hexlen, sign, ctltype;
741 size_t intlen;
742 size_t j, len;
743 u_int kind;
744 int (*func)(int, void *);
745
746 /* Silence GCC. */
747 umv = mv = intlen = 0;
748
749 bzero(buf, BUFSIZ);
750 bzero(name, BUFSIZ);
751 qoid[0] = 0;
752 memcpy(qoid + 2, oid, nlen * sizeof(int));
753 fmt = (char *)buf;
754 oidfmt(oid, nlen, fmt, &kind);
755
756 #ifdef __APPLE__
757 if (!show_masked && (kind & CTLFLAG_MASKED)) {
758 return (1);
759 }
760 #endif
761
762 #ifdef __APPLE__
763 // Support for CTL_USER
764 if (nlen >= 1 && oid[0] == CTL_USER) {
765 const char *user_name = "";
766 sep = "";
767 i = oid[1];
768 if (nlen == 2 && i > 0 && i < user_names_count) {
769 user_name = user_names[i].ctl_name;
770 sep = ".";
771 }
772 j = snprintf(name, sizeof(name), "%s%s%s",
773 names[CTL_USER].ctl_name, sep, user_name);
774 i = 0;
775 } else {
776 #endif
777 qoid[1] = 1;
778 j = sizeof(name);
779 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
780 if (i || !j)
781 err(1, "sysctl name %d %zu %d", i, j, errno);
782 #ifdef __APPLE__
783 }
784 #endif
785
786 if (Nflag) {
787 printf("%s", name);
788 return (0);
789 }
790
791 if (eflag)
792 sep = "=";
793 else
794 sep = ": ";
795
796 if (dflag) { /* just print description */
797 qoid[1] = 5;
798 j = sizeof(buf);
799 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
800 if (!nflag)
801 printf("%s%s", name, sep);
802 printf("%s", buf);
803 return (0);
804 }
805 /* find an estimate of how much we need for this var */
806 j = 0;
807 i = sysctl(oid, nlen, 0, &j, 0, 0);
808 j += j; /* we want to be sure :-) */
809
810 val = oval = malloc(j + 1);
811 if (val == NULL) {
812 warnx("malloc failed");
813 return (1);
814 }
815 len = j;
816 i = sysctl(oid, nlen, val, &len, 0, 0);
817 if (i || !len) {
818 free(oval);
819 return (1);
820 }
821
822 if (bflag) {
823 fwrite(val, 1, len, stdout);
824 free(oval);
825 return (0);
826 }
827 val[len] = '\0';
828 p = val;
829 ctltype = (kind & CTLTYPE);
830 sign = ctl_sign[ctltype];
831 intlen = ctl_size[ctltype];
832
833 switch (ctltype) {
834 case CTLTYPE_STRING:
835 if (!nflag)
836 printf("%s%s", name, sep);
837 printf("%.*s", (int)len, p);
838 free(oval);
839 return (0);
840
841 case CTLTYPE_INT:
842 case CTLTYPE_UINT:
843 case CTLTYPE_LONG:
844 case CTLTYPE_ULONG:
845 case CTLTYPE_S64:
846 case CTLTYPE_U64:
847 if (!nflag)
848 printf("%s%s", name, sep);
849 hexlen = (int)(2 + (intlen * CHAR_BIT + 3) / 4);
850 sep1 = "";
851 while (len >= intlen) {
852 switch (kind & CTLTYPE) {
853 case CTLTYPE_INT:
854 case CTLTYPE_UINT:
855 umv = *(u_int *)(void *)p;
856 mv = *(int *)(void *)p;
857 break;
858 case CTLTYPE_LONG:
859 case CTLTYPE_ULONG:
860 umv = *(u_long *)(void *)p;
861 mv = *(long *)(void *)p;
862 break;
863 case CTLTYPE_S64:
864 case CTLTYPE_U64:
865 umv = *(uint64_t *)(void *)p;
866 mv = *(int64_t *)(void *)p;
867 break;
868 }
869 fputs(sep1, stdout);
870 if (xflag)
871 printf("%#0*jx", hexlen, umv);
872 else if (!sign)
873 printf(hflag ? "%'ju" : "%ju", umv);
874 else if (fmt[1] == 'K') {
875 if (mv < 0)
876 printf("%jd", mv);
877 else
878 printf("%.1fC", (mv - 2732.0) / 10);
879 } else
880 printf(hflag ? "%'jd" : "%jd", mv);
881 sep1 = " ";
882 len -= intlen;
883 p += intlen;
884 }
885 free(oval);
886 return (0);
887
888 case CTLTYPE_OPAQUE:
889 i = 0;
890 if (strcmp(fmt, "S,clockinfo") == 0)
891 func = S_clockinfo;
892 else if (strcmp(fmt, "S,timeval") == 0)
893 func = S_timeval;
894 else if (strcmp(fmt, "S,loadavg") == 0)
895 func = S_loadavg;
896 #ifdef __APPLE__
897 else if (!strcmp(fmt, "S,xsw_usage"))
898 func = S_xswusage;
899 else if (!strcmp(fmt, "T,dev_t"))
900 func = T_dev_t;
901 else if (!strcmp(fmt, "Q"))
902 func = S_quads;
903 #else // !__APPLE__
904 else if (strcmp(fmt, "S,vmtotal") == 0)
905 func = S_vmtotal;
906 #endif // !__APPLE__
907 else
908 func = NULL;
909 if (func) {
910 if (!nflag)
911 printf("%s%s", name, sep);
912 i = (*func)((int)len, p);
913 free(oval);
914 return (i);
915 }
916 /* FALLTHROUGH */
917 default:
918 if (!oflag && !xflag) {
919 free(oval);
920 return (1);
921 }
922 if (!nflag)
923 printf("%s%s", name, sep);
924 printf("Format:%s Length:%zu Dump:0x", fmt, len);
925 while (len-- && (xflag || p < val + 16))
926 printf("%02x", *p++);
927 if (!xflag && len > 16)
928 printf("...");
929 free(oval);
930 return (0);
931 }
932 free(oval);
933 return (1);
934 }
935
936 #ifdef __APPLE__
937 // Support for CTL_USER
938 static void
939 sysctl_all_user(int *oid, int len)
940 {
941 int i, j;
942 if (len > 1 || (len == 1 && oid[0] != CTL_USER)) {
943 return;
944 }
945 for (i = 0; i < user_names_count; ++i) {
946 int oid[2] = { CTL_USER, i };
947 j = show_var(oid, 2, 0);
948 if (!j && !bflag) {
949 putchar('\n');
950 }
951 }
952 }
953 #endif
954
955 static int
956 sysctl_all(int *oid, int len)
957 {
958 #ifdef __APPLE__
959 #endif
960
961 int name1[22], name2[22];
962 int i, j;
963 size_t l1, l2;
964
965 #ifdef __APPLE__
966 sysctl_all_user(oid, len);
967 #endif
968
969 name1[0] = 0;
970 name1[1] = 2;
971 l1 = 2;
972 if (len) {
973 memcpy(name1+2, oid, len * sizeof(int));
974 l1 += len;
975 } else {
976 name1[2] = 1;
977 l1++;
978 }
979 for (;;) {
980 l2 = sizeof(name2);
981 j = sysctl(name1, (u_int)l1, name2, &l2, 0, 0);
982 if (j < 0) {
983 if (errno == ENOENT)
984 return (0);
985 else
986 err(1, "sysctl(getnext) %d %zu", j, l2);
987 }
988
989 l2 /= sizeof(int);
990
991 if (len < 0 || l2 < (unsigned int)len)
992 return (0);
993
994 for (i = 0; i < len; i++)
995 if (name2[i] != oid[i])
996 return (0);
997
998 #ifdef __APPLE__
999 i = show_var(name2, (u_int)l2, 0);
1000 #else
1001 i = show_var(name2, (u_int)l2);
1002 #endif
1003 if (!i && !bflag)
1004 putchar('\n');
1005
1006 memcpy(name1+2, name2, l2 * sizeof(int));
1007 l1 = 2 + l2;
1008 }
1009 }