1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/stat.h>
37 #include <sys/sysctl.h>
38 #include <sys/vmmeter.h>
39 #include <dev/evdev/input.h>
40
41 #ifdef __amd64__
42 #include <sys/efi.h>
43 #include <machine/metadata.h>
44 #endif
45
46 #if defined(__amd64__) || defined(__i386__)
47 #include <machine/pc/bios.h>
48 #endif
49
50 #include <assert.h>
51 #include <ctype.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <inttypes.h>
55 #include <locale.h>
56 #include <stdbool.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <sysexits.h>
61 #include <unistd.h>
62
63 static const char *conffile;
64
65 static int aflag, bflag, Bflag, dflag, eflag, hflag, iflag;
66 static int Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag;
67 static bool Fflag, lflag;
68
69 static int oidfmt(int *, int, char *, u_int *);
70 static int parsefile(const char *);
71 static int parse(const char *, int);
72 static int show_var(int *, int, bool);
73 static int sysctl_all(int *, int);
74 static int name2oid(const char *, int *);
75
76 static int strIKtoi(const char *, char **, const char *);
77
78 static int ctl_sign[CTLTYPE+1] = {
79 [CTLTYPE_INT] = 1,
80 [CTLTYPE_LONG] = 1,
81 [CTLTYPE_S8] = 1,
82 [CTLTYPE_S16] = 1,
83 [CTLTYPE_S32] = 1,
84 [CTLTYPE_S64] = 1,
85 };
86
87 static int ctl_size[CTLTYPE+1] = {
88 [CTLTYPE_INT] = sizeof(int),
89 [CTLTYPE_UINT] = sizeof(u_int),
90 [CTLTYPE_LONG] = sizeof(long),
91 [CTLTYPE_ULONG] = sizeof(u_long),
92 [CTLTYPE_S8] = sizeof(int8_t),
93 [CTLTYPE_S16] = sizeof(int16_t),
94 [CTLTYPE_S32] = sizeof(int32_t),
95 [CTLTYPE_S64] = sizeof(int64_t),
96 [CTLTYPE_U8] = sizeof(uint8_t),
97 [CTLTYPE_U16] = sizeof(uint16_t),
98 [CTLTYPE_U32] = sizeof(uint32_t),
99 [CTLTYPE_U64] = sizeof(uint64_t),
100 };
101
102 static const char *ctl_typename[CTLTYPE+1] = {
103 [CTLTYPE_INT] = "integer",
104 [CTLTYPE_UINT] = "unsigned integer",
105 [CTLTYPE_LONG] = "long integer",
106 [CTLTYPE_ULONG] = "unsigned long",
107 [CTLTYPE_U8] = "uint8_t",
108 [CTLTYPE_U16] = "uint16_t",
109 [CTLTYPE_U32] = "uint32_t",
110 [CTLTYPE_U64] = "uint64_t",
111 [CTLTYPE_S8] = "int8_t",
112 [CTLTYPE_S16] = "int16_t",
113 [CTLTYPE_S32] = "int32_t",
114 [CTLTYPE_S64] = "int64_t",
115 [CTLTYPE_NODE] = "node",
116 [CTLTYPE_STRING] = "string",
117 [CTLTYPE_OPAQUE] = "opaque",
118 };
119
120 static void
usage(void)121 usage(void)
122 {
123
124 (void)fprintf(stderr, "%s\n%s\n",
125 "usage: sysctl [-bdeFhilNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...",
126 " sysctl [-bdeFhlNnoqTtWx] [ -B <bufsize> ] -a");
127 exit(1);
128 }
129
130 int
main(int argc,char ** argv)131 main(int argc, char **argv)
132 {
133 int ch;
134 int warncount = 0;
135
136 setlocale(LC_NUMERIC, "");
137 setbuf(stdout,0);
138 setbuf(stderr,0);
139
140 while ((ch = getopt(argc, argv, "AabB:def:FhilNnoqtTwWxX")) != -1) {
141 switch (ch) {
142 case 'A':
143 /* compatibility */
144 aflag = oflag = 1;
145 break;
146 case 'a':
147 aflag = 1;
148 break;
149 case 'b':
150 bflag = 1;
151 break;
152 case 'B':
153 Bflag = strtol(optarg, NULL, 0);
154 break;
155 case 'd':
156 dflag = 1;
157 break;
158 case 'e':
159 eflag = 1;
160 break;
161 case 'f':
162 conffile = optarg;
163 break;
164 case 'F':
165 Fflag = true;
166 break;
167 case 'h':
168 hflag = 1;
169 break;
170 case 'i':
171 iflag = 1;
172 break;
173 case 'l':
174 lflag = true;
175 break;
176 case 'N':
177 Nflag = 1;
178 break;
179 case 'n':
180 nflag = 1;
181 break;
182 case 'o':
183 oflag = 1;
184 break;
185 case 'q':
186 qflag = 1;
187 break;
188 case 't':
189 tflag = 1;
190 break;
191 case 'T':
192 Tflag = 1;
193 break;
194 case 'w':
195 /* compatibility */
196 /* ignored */
197 break;
198 case 'W':
199 Wflag = 1;
200 break;
201 case 'X':
202 /* compatibility */
203 aflag = xflag = 1;
204 break;
205 case 'x':
206 xflag = 1;
207 break;
208 default:
209 usage();
210 }
211 }
212 argc -= optind;
213 argv += optind;
214
215 /* Nflag is name only and doesn't make sense to combine with these */
216 /* TODO: few other combinations do not make sense but come back later */
217 if (Nflag && (lflag || nflag))
218 usage();
219 if (aflag && argc == 0)
220 exit(sysctl_all(NULL, 0));
221 if (argc == 0 && conffile == NULL)
222 usage();
223
224 if (conffile != NULL)
225 warncount += parsefile(conffile);
226
227 while (argc-- > 0)
228 warncount += parse(*argv++, 0);
229
230 return (warncount);
231 }
232
233 /*
234 * Parse a single numeric value, append it to 'newbuf', and update
235 * 'newsize'. Returns true if the value was parsed and false if the
236 * value was invalid. Non-numeric types (strings) are handled
237 * directly in parse().
238 */
239 static bool
parse_numeric(const char * newvalstr,const char * fmt,u_int kind,void ** newbufp,size_t * newsizep)240 parse_numeric(const char *newvalstr, const char *fmt, u_int kind,
241 void **newbufp, size_t *newsizep)
242 {
243 void *newbuf;
244 const void *newval;
245 int8_t i8val;
246 uint8_t u8val;
247 int16_t i16val;
248 uint16_t u16val;
249 int32_t i32val;
250 uint32_t u32val;
251 int intval;
252 unsigned int uintval;
253 long longval;
254 unsigned long ulongval;
255 int64_t i64val;
256 uint64_t u64val;
257 size_t valsize;
258 char *endptr = NULL;
259
260 errno = 0;
261
262 switch (kind & CTLTYPE) {
263 case CTLTYPE_INT:
264 if (strncmp(fmt, "IK", 2) == 0)
265 intval = strIKtoi(newvalstr, &endptr, fmt);
266 else
267 intval = (int)strtol(newvalstr, &endptr, 0);
268 newval = &intval;
269 valsize = sizeof(intval);
270 break;
271 case CTLTYPE_UINT:
272 uintval = (int) strtoul(newvalstr, &endptr, 0);
273 newval = &uintval;
274 valsize = sizeof(uintval);
275 break;
276 case CTLTYPE_LONG:
277 longval = strtol(newvalstr, &endptr, 0);
278 newval = &longval;
279 valsize = sizeof(longval);
280 break;
281 case CTLTYPE_ULONG:
282 ulongval = strtoul(newvalstr, &endptr, 0);
283 newval = &ulongval;
284 valsize = sizeof(ulongval);
285 break;
286 case CTLTYPE_S8:
287 i8val = (int8_t)strtol(newvalstr, &endptr, 0);
288 newval = &i8val;
289 valsize = sizeof(i8val);
290 break;
291 case CTLTYPE_S16:
292 i16val = (int16_t)strtol(newvalstr, &endptr, 0);
293 newval = &i16val;
294 valsize = sizeof(i16val);
295 break;
296 case CTLTYPE_S32:
297 i32val = (int32_t)strtol(newvalstr, &endptr, 0);
298 newval = &i32val;
299 valsize = sizeof(i32val);
300 break;
301 case CTLTYPE_S64:
302 i64val = strtoimax(newvalstr, &endptr, 0);
303 newval = &i64val;
304 valsize = sizeof(i64val);
305 break;
306 case CTLTYPE_U8:
307 u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
308 newval = &u8val;
309 valsize = sizeof(u8val);
310 break;
311 case CTLTYPE_U16:
312 u16val = (uint16_t)strtoul(newvalstr, &endptr, 0);
313 newval = &u16val;
314 valsize = sizeof(u16val);
315 break;
316 case CTLTYPE_U32:
317 u32val = (uint32_t)strtoul(newvalstr, &endptr, 0);
318 newval = &u32val;
319 valsize = sizeof(u32val);
320 break;
321 case CTLTYPE_U64:
322 u64val = strtoumax(newvalstr, &endptr, 0);
323 newval = &u64val;
324 valsize = sizeof(u64val);
325 break;
326 default:
327 /* NOTREACHED */
328 abort();
329 }
330
331 if (errno != 0 || endptr == newvalstr ||
332 (endptr != NULL && *endptr != '\0'))
333 return (false);
334
335 newbuf = realloc(*newbufp, *newsizep + valsize);
336 if (newbuf == NULL)
337 err(1, "out of memory");
338 memcpy((char *)newbuf + *newsizep, newval, valsize);
339 *newbufp = newbuf;
340 *newsizep += valsize;
341
342 return (true);
343 }
344
345 /*
346 * Parse a name into a MIB entry.
347 * Lookup and print out the MIB entry if it exists.
348 * Set a new value if requested.
349 */
350 static int
parse(const char * string,int lineno)351 parse(const char *string, int lineno)
352 {
353 int len, i, j, save_errno;
354 const void *newval;
355 char *newvalstr = NULL;
356 void *newbuf;
357 size_t newsize = Bflag;
358 int mib[CTL_MAXNAME];
359 char *cp, *bufp, *buf, fmt[BUFSIZ], line[BUFSIZ];
360 u_int kind;
361
362 if (lineno)
363 snprintf(line, sizeof(line), " at line %d", lineno);
364 else
365 line[0] = '\0';
366
367 /*
368 * Split the string into name and value.
369 *
370 * Either = or : may be used as the delimiter.
371 * Whitespace surrounding the delimiter is trimmed.
372 * Quotes around the value are stripped.
373 */
374 cp = buf = strdup(string);
375 bufp = strsep(&cp, "=:");
376 if (cp != NULL) {
377 /* Tflag just lists tunables, do not allow assignment */
378 if (Tflag || Wflag) {
379 warnx("Can't set variables when using -T or -W");
380 usage();
381 }
382 /* Trim whitespace before the value. */
383 while (isspace(*cp))
384 cp++;
385 /* Strip a pair of " or ' if any. */
386 switch (*cp) {
387 case '\"':
388 case '\'':
389 if (cp[strlen(cp) - 1] == *cp)
390 cp[strlen(cp) - 1] = '\0';
391 cp++;
392 }
393 newvalstr = cp;
394 newsize = strlen(cp);
395 }
396 /* Trim whitespace after the name. */
397 cp = bufp + strlen(bufp) - 1;
398 while (cp >= bufp && isspace((int)*cp)) {
399 *cp = '\0';
400 cp--;
401 }
402
403 /*
404 * Check the name is a useable oid.
405 */
406 len = name2oid(bufp, mib);
407 if (len < 0) {
408 if (iflag) {
409 free(buf);
410 return (0);
411 }
412 if (!qflag) {
413 if (errno == ENOENT) {
414 warnx("unknown oid '%s'%s", bufp, line);
415 } else {
416 warn("unknown oid '%s'%s", bufp, line);
417 }
418 }
419 free(buf);
420 return (1);
421 }
422
423 if (oidfmt(mib, len, fmt, &kind)) {
424 warn("couldn't find format of oid '%s'%s", bufp, line);
425 free(buf);
426 if (iflag)
427 return (1);
428 else
429 exit(1);
430 }
431
432 /*
433 * We have a useable oid to work with. If there is no value given,
434 * show the node and its children. Otherwise, set the new value.
435 */
436 if (newvalstr == NULL || dflag) {
437 free(buf);
438 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
439 if (dflag) {
440 i = show_var(mib, len, false);
441 if (!i && !bflag)
442 putchar('\n');
443 }
444 sysctl_all(mib, len);
445 } else {
446 i = show_var(mib, len, false);
447 if (!i && !bflag)
448 putchar('\n');
449 }
450 return (0);
451 }
452
453 /*
454 * We have a new value to set. Check its validity and parse if numeric.
455 */
456 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
457 warnx("oid '%s' isn't a leaf node%s", bufp, line);
458 free(buf);
459 return (1);
460 }
461
462 if (!(kind & CTLFLAG_WR)) {
463 if (kind & CTLFLAG_TUN) {
464 warnx("oid '%s' is a read only tunable%s", bufp, line);
465 warnx("Tunable values are set in /boot/loader.conf");
466 } else
467 warnx("oid '%s' is read only%s", bufp, line);
468 free(buf);
469 return (1);
470 }
471
472 switch (kind & CTLTYPE) {
473 case CTLTYPE_INT:
474 case CTLTYPE_UINT:
475 case CTLTYPE_LONG:
476 case CTLTYPE_ULONG:
477 case CTLTYPE_S8:
478 case CTLTYPE_S16:
479 case CTLTYPE_S32:
480 case CTLTYPE_S64:
481 case CTLTYPE_U8:
482 case CTLTYPE_U16:
483 case CTLTYPE_U32:
484 case CTLTYPE_U64:
485 if (strlen(newvalstr) == 0) {
486 warnx("empty numeric value");
487 free(buf);
488 return (1);
489 }
490 /* FALLTHROUGH */
491 case CTLTYPE_STRING:
492 break;
493 default:
494 warnx("oid '%s' is type %d, cannot set that%s",
495 bufp, kind & CTLTYPE, line);
496 free(buf);
497 return (1);
498 }
499
500 newbuf = NULL;
501
502 switch (kind & CTLTYPE) {
503 case CTLTYPE_STRING:
504 newval = newvalstr;
505 break;
506 default:
507 newsize = 0;
508 while ((cp = strsep(&newvalstr, " ,")) != NULL) {
509 if (*cp == '\0')
510 continue;
511 if (!parse_numeric(cp, fmt, kind, &newbuf, &newsize)) {
512 warnx("invalid %s '%s'%s",
513 ctl_typename[kind & CTLTYPE], cp, line);
514 free(newbuf);
515 free(buf);
516 return (1);
517 }
518 }
519 newval = newbuf;
520 break;
521 }
522
523 /*
524 * Show the current value, then set and show the new value.
525 */
526 i = show_var(mib, len, false);
527 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
528 save_errno = errno;
529 free(newbuf);
530 free(buf);
531 if (!i && !bflag)
532 putchar('\n');
533 switch (save_errno) {
534 case EOPNOTSUPP:
535 warnx("%s: value is not available%s",
536 string, line);
537 return (1);
538 case ENOTDIR:
539 warnx("%s: specification is incomplete%s",
540 string, line);
541 return (1);
542 case ENOMEM:
543 warnx("%s: type is unknown to this program%s",
544 string, line);
545 return (1);
546 default:
547 warnc(save_errno, "%s%s", string, line);
548 return (1);
549 }
550 }
551 free(newbuf);
552 free(buf);
553 if (!bflag)
554 printf(" -> ");
555 i = nflag;
556 nflag = 1;
557 j = show_var(mib, len, false);
558 if (!j && !bflag)
559 putchar('\n');
560 nflag = i;
561
562 return (0);
563 }
564
565 static int
parsefile(const char * filename)566 parsefile(const char *filename)
567 {
568 FILE *file;
569 char line[BUFSIZ], *p, *pq, *pdq;
570 int warncount = 0, lineno = 0;
571
572 file = fopen(filename, "r");
573 if (file == NULL)
574 err(EX_NOINPUT, "%s", filename);
575 while (fgets(line, sizeof(line), file) != NULL) {
576 lineno++;
577 p = line;
578 pq = strchr(line, '\'');
579 pdq = strchr(line, '\"');
580 /* Replace the first # with \0. */
581 while((p = strchr(p, '#')) != NULL) {
582 if (pq != NULL && p > pq) {
583 if ((p = strchr(pq+1, '\'')) != NULL)
584 *(++p) = '\0';
585 break;
586 } else if (pdq != NULL && p > pdq) {
587 if ((p = strchr(pdq+1, '\"')) != NULL)
588 *(++p) = '\0';
589 break;
590 } else if (p == line || *(p-1) != '\\') {
591 *p = '\0';
592 break;
593 }
594 p++;
595 }
596 /* Trim spaces */
597 p = line + strlen(line) - 1;
598 while (p >= line && isspace((int)*p)) {
599 *p = '\0';
600 p--;
601 }
602 p = line;
603 while (isspace((int)*p))
604 p++;
605 if (*p == '\0')
606 continue;
607 else
608 warncount += parse(p, lineno);
609 }
610 fclose(file);
611
612 return (warncount);
613 }
614
615 /* These functions will dump out various interesting structures. */
616
617 static int
S_clockinfo(size_t l2,void * p)618 S_clockinfo(size_t l2, void *p)
619 {
620 struct clockinfo *ci = (struct clockinfo*)p;
621
622 if (l2 != sizeof(*ci)) {
623 warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
624 return (1);
625 }
626 printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
627 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
628 ci->hz, ci->tick, ci->profhz, ci->stathz);
629 return (0);
630 }
631
632 static int
S_loadavg(size_t l2,void * p)633 S_loadavg(size_t l2, void *p)
634 {
635 struct loadavg *tv = (struct loadavg*)p;
636
637 if (l2 != sizeof(*tv)) {
638 warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
639 return (1);
640 }
641 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
642 (double)tv->ldavg[0]/(double)tv->fscale,
643 (double)tv->ldavg[1]/(double)tv->fscale,
644 (double)tv->ldavg[2]/(double)tv->fscale);
645 return (0);
646 }
647
648 static int
S_timeval(size_t l2,void * p)649 S_timeval(size_t l2, void *p)
650 {
651 struct timeval *tv = (struct timeval*)p;
652 time_t tv_sec;
653 char *p1, *p2;
654
655 if (l2 != sizeof(*tv)) {
656 warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
657 return (1);
658 }
659 printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
660 "{ sec = %jd, usec = %ld } ",
661 (intmax_t)tv->tv_sec, tv->tv_usec);
662 tv_sec = tv->tv_sec;
663 p1 = strdup(ctime(&tv_sec));
664 for (p2=p1; *p2 ; p2++)
665 if (*p2 == '\n')
666 *p2 = '\0';
667 fputs(p1, stdout);
668 free(p1);
669 return (0);
670 }
671
672 static int
S_vmtotal(size_t l2,void * p)673 S_vmtotal(size_t l2, void *p)
674 {
675 struct vmtotal *v;
676 int pageKilo;
677
678 if (l2 != sizeof(*v)) {
679 warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
680 return (1);
681 }
682
683 v = p;
684 pageKilo = getpagesize() / 1024;
685
686 #define pg2k(a) ((uintmax_t)(a) * pageKilo)
687 printf("\nSystem wide totals computed every five seconds:"
688 " (values in kilobytes)\n");
689 printf("===============================================\n");
690 printf("Processes:\t\t(RUNQ: %d Disk Wait: %d Page Wait: "
691 "%d Sleep: %d)\n",
692 v->t_rq, v->t_dw, v->t_pw, v->t_sl);
693 printf("Virtual Memory:\t\t(Total: %juK Active: %juK)\n",
694 pg2k(v->t_vm), pg2k(v->t_avm));
695 printf("Real Memory:\t\t(Total: %juK Active: %juK)\n",
696 pg2k(v->t_rm), pg2k(v->t_arm));
697 printf("Shared Virtual Memory:\t(Total: %juK Active: %juK)\n",
698 pg2k(v->t_vmshr), pg2k(v->t_avmshr));
699 printf("Shared Real Memory:\t(Total: %juK Active: %juK)\n",
700 pg2k(v->t_rmshr), pg2k(v->t_armshr));
701 printf("Free Memory:\t%juK", pg2k(v->t_free));
702 return (0);
703 }
704
705 static int
S_input_id(size_t l2,void * p)706 S_input_id(size_t l2, void *p)
707 {
708 struct input_id *id = p;
709
710 if (l2 != sizeof(*id)) {
711 warnx("S_input_id %zu != %zu", l2, sizeof(*id));
712 return (1);
713 }
714
715 printf("{ bustype = 0x%04x, vendor = 0x%04x, "
716 "product = 0x%04x, version = 0x%04x }",
717 id->bustype, id->vendor, id->product, id->version);
718 return (0);
719 }
720
721 static int
S_pagesizes(size_t l2,void * p)722 S_pagesizes(size_t l2, void *p)
723 {
724 char buf[256];
725 u_long *ps;
726 size_t l;
727 int i;
728
729 l = snprintf(buf, sizeof(buf), "{ ");
730 ps = p;
731 for (i = 0; i * sizeof(*ps) < l2 && ps[i] != 0 && l < sizeof(buf);
732 i++) {
733 l += snprintf(&buf[l], sizeof(buf) - l,
734 "%s%lu", i == 0 ? "" : ", ", ps[i]);
735 }
736 if (l < sizeof(buf))
737 (void)snprintf(&buf[l], sizeof(buf) - l, " }");
738
739 printf("%s", buf);
740
741 return (0);
742 }
743
744 #ifdef __amd64__
745 static int
S_efi_map(size_t l2,void * p)746 S_efi_map(size_t l2, void *p)
747 {
748 struct efi_map_header *efihdr;
749 struct efi_md *map;
750 const char *type;
751 size_t efisz;
752 int ndesc, i;
753
754 static const char * const types[] = {
755 [EFI_MD_TYPE_NULL] = "Reserved",
756 [EFI_MD_TYPE_CODE] = "LoaderCode",
757 [EFI_MD_TYPE_DATA] = "LoaderData",
758 [EFI_MD_TYPE_BS_CODE] = "BootServicesCode",
759 [EFI_MD_TYPE_BS_DATA] = "BootServicesData",
760 [EFI_MD_TYPE_RT_CODE] = "RuntimeServicesCode",
761 [EFI_MD_TYPE_RT_DATA] = "RuntimeServicesData",
762 [EFI_MD_TYPE_FREE] = "ConventionalMemory",
763 [EFI_MD_TYPE_BAD] = "UnusableMemory",
764 [EFI_MD_TYPE_RECLAIM] = "ACPIReclaimMemory",
765 [EFI_MD_TYPE_FIRMWARE] = "ACPIMemoryNVS",
766 [EFI_MD_TYPE_IOMEM] = "MemoryMappedIO",
767 [EFI_MD_TYPE_IOPORT] = "MemoryMappedIOPortSpace",
768 [EFI_MD_TYPE_PALCODE] = "PalCode",
769 [EFI_MD_TYPE_PERSISTENT] = "PersistentMemory",
770 };
771
772 /*
773 * Memory map data provided by UEFI via the GetMemoryMap
774 * Boot Services API.
775 */
776 if (l2 < sizeof(*efihdr)) {
777 warnx("S_efi_map length less than header");
778 return (1);
779 }
780 efihdr = p;
781 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
782 map = (struct efi_md *)((uint8_t *)efihdr + efisz);
783
784 if (efihdr->descriptor_size == 0)
785 return (0);
786 if (l2 != efisz + efihdr->memory_size) {
787 warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
788 efihdr->memory_size);
789 return (1);
790 }
791 ndesc = efihdr->memory_size / efihdr->descriptor_size;
792
793 printf("\n%23s %12s %12s %8s %4s",
794 "Type", "Physical", "Virtual", "#Pages", "Attr");
795
796 for (i = 0; i < ndesc; i++,
797 map = efi_next_descriptor(map, efihdr->descriptor_size)) {
798 type = NULL;
799 if (map->md_type < nitems(types))
800 type = types[map->md_type];
801 if (type == NULL)
802 type = "<INVALID>";
803 printf("\n%23s %012jx %012jx %08jx ", type,
804 (uintmax_t)map->md_phys, (uintmax_t)map->md_virt,
805 (uintmax_t)map->md_pages);
806 if (map->md_attr & EFI_MD_ATTR_UC)
807 printf("UC ");
808 if (map->md_attr & EFI_MD_ATTR_WC)
809 printf("WC ");
810 if (map->md_attr & EFI_MD_ATTR_WT)
811 printf("WT ");
812 if (map->md_attr & EFI_MD_ATTR_WB)
813 printf("WB ");
814 if (map->md_attr & EFI_MD_ATTR_UCE)
815 printf("UCE ");
816 if (map->md_attr & EFI_MD_ATTR_WP)
817 printf("WP ");
818 if (map->md_attr & EFI_MD_ATTR_RP)
819 printf("RP ");
820 if (map->md_attr & EFI_MD_ATTR_XP)
821 printf("XP ");
822 if (map->md_attr & EFI_MD_ATTR_RT)
823 printf("RUNTIME");
824 }
825 return (0);
826 }
827 #endif
828
829 #if defined(__amd64__) || defined(__i386__)
830 static int
S_bios_smap_xattr(size_t l2,void * p)831 S_bios_smap_xattr(size_t l2, void *p)
832 {
833 struct bios_smap_xattr *smap, *end;
834
835 if (l2 % sizeof(*smap) != 0) {
836 warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
837 sizeof(*smap));
838 return (1);
839 }
840
841 end = (struct bios_smap_xattr *)((char *)p + l2);
842 for (smap = p; smap < end; smap++)
843 printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
844 smap->type, smap->xattr, (uintmax_t)smap->base,
845 (uintmax_t)smap->length);
846 return (0);
847 }
848 #endif
849
850 static int
strIKtoi(const char * str,char ** endptrp,const char * fmt)851 strIKtoi(const char *str, char **endptrp, const char *fmt)
852 {
853 int kelv;
854 float temp;
855 size_t len;
856 const char *p;
857 int prec, i;
858
859 assert(errno == 0);
860
861 len = strlen(str);
862 /* caller already checked this */
863 assert(len > 0);
864
865 /*
866 * A format of "IK" is in deciKelvin. A format of "IK3" is in
867 * milliKelvin. The single digit following IK is log10 of the
868 * multiplying factor to convert Kelvin into the untis of this sysctl,
869 * or the dividing factor to convert the sysctl value to Kelvin. Numbers
870 * larger than 6 will run into precision issues with 32-bit integers.
871 * Characters that aren't ASCII digits after the 'K' are ignored. No
872 * localization is present because this is an interface from the kernel
873 * to this program (eg not an end-user interface), so isdigit() isn't
874 * used here.
875 */
876 if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
877 prec = fmt[2] - '0';
878 else
879 prec = 1;
880 p = &str[len - 1];
881 if (*p == 'C' || *p == 'F' || *p == 'K') {
882 temp = strtof(str, endptrp);
883 if (*endptrp != str && *endptrp == p && errno == 0) {
884 if (*p == 'F')
885 temp = (temp - 32) * 5 / 9;
886 *endptrp = NULL;
887 if (*p != 'K')
888 temp += 273.15;
889 for (i = 0; i < prec; i++)
890 temp *= 10.0;
891 return ((int)(temp + 0.5));
892 }
893 } else {
894 /* No unit specified -> treat it as a raw number */
895 kelv = (int)strtol(str, endptrp, 10);
896 if (*endptrp != str && *endptrp == p && errno == 0) {
897 *endptrp = NULL;
898 return (kelv);
899 }
900 }
901
902 errno = ERANGE;
903 return (0);
904 }
905
906 /*
907 * These functions uses a presently undocumented interface to the kernel
908 * to walk the tree and get the type so it can print the value.
909 * This interface is under work and consideration, and should probably
910 * be killed with a big axe by the first person who can find the time.
911 * (be aware though, that the proper interface isn't as obvious as it
912 * may seem, there are various conflicting requirements.
913 */
914
915 static int
name2oid(const char * name,int * oidp)916 name2oid(const char *name, int *oidp)
917 {
918 int oid[2];
919 int i;
920 size_t j;
921
922 oid[0] = CTL_SYSCTL;
923 oid[1] = CTL_SYSCTL_NAME2OID;
924
925 j = CTL_MAXNAME * sizeof(int);
926 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
927 if (i < 0)
928 return (i);
929 j /= sizeof(int);
930 return (j);
931 }
932
933 static int
oidfmt(int * oid,int len,char * fmt,u_int * kind)934 oidfmt(int *oid, int len, char *fmt, u_int *kind)
935 {
936 int qoid[CTL_MAXNAME+2];
937 u_char buf[BUFSIZ];
938 int i;
939 size_t j;
940
941 qoid[0] = CTL_SYSCTL;
942 qoid[1] = CTL_SYSCTL_OIDFMT;
943 memcpy(qoid + 2, oid, len * sizeof(int));
944
945 j = sizeof(buf);
946 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
947 if (i)
948 err(1, "sysctl fmt %d %zu %d", i, j, errno);
949
950 if (kind)
951 *kind = *(u_int *)buf;
952
953 if (fmt)
954 strcpy(fmt, (char *)(buf + sizeof(u_int)));
955 return (0);
956 }
957
958 /*
959 * This displays a combination of name, type, format, and/or description.
960 *
961 * Returns zero if anything was actually output.
962 * Returns one if there is an error.
963 */
964 static int
show_info(char * name,const char * sep,int ctltype,char * fmt,int * qoid,int nlen)965 show_info(char *name, const char *sep, int ctltype, char *fmt, int *qoid, int nlen)
966 {
967 u_char buf[BUFSIZ];
968 const char *prntype;
969 int error = 0, i;
970 size_t j;
971
972 if (!nflag)
973 printf("%s%s", name, sep);
974 if (tflag) {
975 if (ctl_typename[ctltype] != NULL)
976 prntype = ctl_typename[ctltype];
977 else {
978 prntype = "unknown";
979 error++;
980 }
981 if (Fflag || dflag)
982 printf("%s%s", prntype, sep);
983 else
984 fputs(prntype, stdout);
985 }
986 if (Fflag) {
987 if (!isprint(fmt[0])) /* Few codes doesn't have formats */
988 fmt = "";
989 if (dflag)
990 printf("%s%s", fmt, sep);
991 else
992 fputs(fmt, stdout);
993 }
994 if (!dflag)
995 return (error);
996
997 qoid[1] = CTL_SYSCTL_OIDDESCR;
998 bzero(buf, BUFSIZ);
999 j = sizeof(buf);
1000 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
1001 if (i < 0) {
1002 putchar('\n');
1003 return (1);
1004 }
1005 fputs(buf, stdout);
1006 return (error);
1007 }
1008
1009 /*
1010 * This formats and outputs the value of one variable
1011 *
1012 * Returns zero if anything was actually output.
1013 * Returns one if didn't know what to do with this.
1014 * Return minus one if we had errors.
1015 */
1016 static int
show_var(int * oid,int nlen,bool honor_skip)1017 show_var(int *oid, int nlen, bool honor_skip)
1018 {
1019 static int skip_len = 0, skip_oid[CTL_MAXNAME];
1020 u_char *val, *oval, *p;
1021 char name[BUFSIZ], fmt[BUFSIZ];
1022 const char *sep, *sep1;
1023 int qoid[CTL_MAXNAME+2];
1024 uintmax_t umv;
1025 intmax_t mv;
1026 int i, hexlen, sign, ctltype;
1027 size_t intlen;
1028 size_t j, len;
1029 u_int kind;
1030 float base;
1031 int (*func)(size_t, void *);
1032 int prec;
1033
1034 /* Silence GCC. */
1035 umv = mv = intlen = 0;
1036
1037 bzero(fmt, BUFSIZ);
1038 bzero(name, BUFSIZ);
1039 qoid[0] = CTL_SYSCTL;
1040 qoid[1] = CTL_SYSCTL_NAME;
1041 memcpy(qoid + 2, oid, nlen * sizeof(int));
1042 j = sizeof(name);
1043 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
1044 if (i || !j)
1045 err(1, "sysctl name %d %zu %d", i, j, errno);
1046
1047 oidfmt(oid, nlen, fmt, &kind);
1048 /* if Wflag then only list sysctls that are writeable and not stats. */
1049 if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
1050 return (1);
1051
1052 /* if Tflag then only list sysctls that are tuneables. */
1053 if (Tflag && (kind & CTLFLAG_TUN) == 0)
1054 return (1);
1055
1056 if (Nflag) {
1057 printf("%s", name);
1058 return (0);
1059 }
1060
1061 if (eflag)
1062 sep = "=";
1063 else
1064 sep = ": ";
1065
1066 ctltype = (kind & CTLTYPE);
1067 if (tflag || Fflag || dflag)
1068 return show_info(name, sep, ctltype, fmt, qoid, nlen);
1069
1070 /* keep track of encountered skip nodes, ignoring descendants */
1071 if ((skip_len == 0 || skip_len >= nlen * (int)sizeof(int)) &&
1072 (kind & CTLFLAG_SKIP) != 0) {
1073 /* Save this oid so we can skip descendants. */
1074 skip_len = nlen * sizeof(int);
1075 memcpy(skip_oid, oid, skip_len);
1076 }
1077
1078 /* bail before fetching the value if we're honoring skip */
1079 if (honor_skip) {
1080 if (0 < skip_len && skip_len <= nlen * (int)sizeof(int) &&
1081 memcmp(skip_oid, oid, skip_len) == 0)
1082 return (1);
1083 /* Not a skip node or descendant of a skip node. */
1084 skip_len = 0;
1085 }
1086
1087 /* don't fetch opaques that we don't know how to print */
1088 if (ctltype == CTLTYPE_OPAQUE) {
1089 if (strcmp(fmt, "S,clockinfo") == 0)
1090 func = S_clockinfo;
1091 else if (strcmp(fmt, "S,timeval") == 0)
1092 func = S_timeval;
1093 else if (strcmp(fmt, "S,loadavg") == 0)
1094 func = S_loadavg;
1095 else if (strcmp(fmt, "S,vmtotal") == 0)
1096 func = S_vmtotal;
1097 else if (strcmp(fmt, "S,input_id") == 0)
1098 func = S_input_id;
1099 else if (strcmp(fmt, "S,pagesizes") == 0)
1100 func = S_pagesizes;
1101 #ifdef __amd64__
1102 else if (strcmp(fmt, "S,efi_map_header") == 0)
1103 func = S_efi_map;
1104 #endif
1105 #if defined(__amd64__) || defined(__i386__)
1106 else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
1107 func = S_bios_smap_xattr;
1108 #endif
1109 else {
1110 func = NULL;
1111 if (!bflag && !oflag && !xflag)
1112 return (1);
1113 }
1114 }
1115
1116 /* find an estimate of how much we need for this var */
1117 if (Bflag)
1118 j = Bflag;
1119 else {
1120 j = 0;
1121 i = sysctl(oid, nlen, 0, &j, 0, 0);
1122 j += j; /* we want to be sure :-) */
1123 }
1124
1125 val = oval = malloc(j + 1);
1126 if (val == NULL) {
1127 warnx("malloc failed");
1128 return (1);
1129 }
1130 len = j;
1131 i = sysctl(oid, nlen, val, &len, 0, 0);
1132 if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
1133 free(oval);
1134 return (1);
1135 }
1136
1137 if (bflag) {
1138 fwrite(val, 1, len, stdout);
1139 free(oval);
1140 return (0);
1141 }
1142 val[len] = '\0';
1143 p = val;
1144 sign = ctl_sign[ctltype];
1145 intlen = ctl_size[ctltype];
1146
1147 switch (ctltype) {
1148 case CTLTYPE_STRING:
1149 if (!nflag)
1150 printf("%s%s", name, sep);
1151 if (lflag)
1152 printf("%zd%s", len, sep);
1153 printf("%.*s", (int)len, p);
1154 free(oval);
1155 return (0);
1156
1157 case CTLTYPE_INT:
1158 case CTLTYPE_UINT:
1159 case CTLTYPE_LONG:
1160 case CTLTYPE_ULONG:
1161 case CTLTYPE_S8:
1162 case CTLTYPE_S16:
1163 case CTLTYPE_S32:
1164 case CTLTYPE_S64:
1165 case CTLTYPE_U8:
1166 case CTLTYPE_U16:
1167 case CTLTYPE_U32:
1168 case CTLTYPE_U64:
1169 if (!nflag)
1170 printf("%s%s", name, sep);
1171 if (lflag)
1172 printf("%zd%s", len, sep);
1173 hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
1174 sep1 = "";
1175 while (len >= intlen) {
1176 switch (kind & CTLTYPE) {
1177 case CTLTYPE_INT:
1178 case CTLTYPE_UINT:
1179 umv = *(u_int *)p;
1180 mv = *(int *)p;
1181 break;
1182 case CTLTYPE_LONG:
1183 case CTLTYPE_ULONG:
1184 umv = *(u_long *)p;
1185 mv = *(long *)p;
1186 break;
1187 case CTLTYPE_S8:
1188 case CTLTYPE_U8:
1189 umv = *(uint8_t *)p;
1190 mv = *(int8_t *)p;
1191 break;
1192 case CTLTYPE_S16:
1193 case CTLTYPE_U16:
1194 umv = *(uint16_t *)p;
1195 mv = *(int16_t *)p;
1196 break;
1197 case CTLTYPE_S32:
1198 case CTLTYPE_U32:
1199 umv = *(uint32_t *)p;
1200 mv = *(int32_t *)p;
1201 break;
1202 case CTLTYPE_S64:
1203 case CTLTYPE_U64:
1204 umv = *(uint64_t *)p;
1205 mv = *(int64_t *)p;
1206 break;
1207 }
1208 fputs(sep1, stdout);
1209 if (xflag)
1210 printf("%#0*jx", hexlen, umv);
1211 else if (!sign)
1212 printf(hflag ? "%'ju" : "%ju", umv);
1213 else if (fmt[1] == 'K') {
1214 if (mv < 0)
1215 printf("%jd", mv);
1216 else {
1217 /*
1218 * See strIKtoi for details on fmt.
1219 */
1220 prec = 1;
1221 if (fmt[2] != '\0')
1222 prec = fmt[2] - '0';
1223 base = 1.0;
1224 for (int i = 0; i < prec; i++)
1225 base *= 10.0;
1226 printf("%.*fC", prec,
1227 (float)mv / base - 273.15);
1228 }
1229 } else
1230 printf(hflag ? "%'jd" : "%jd", mv);
1231 sep1 = " ";
1232 len -= intlen;
1233 p += intlen;
1234 }
1235 free(oval);
1236 return (0);
1237
1238 case CTLTYPE_OPAQUE:
1239 i = 0;
1240 if (func) {
1241 if (!nflag)
1242 printf("%s%s", name, sep);
1243 if (lflag)
1244 printf("%zd%s", len, sep);
1245 i = (*func)(len, p);
1246 free(oval);
1247 return (i);
1248 }
1249 /* FALLTHROUGH */
1250 default:
1251 if (!oflag && !xflag) {
1252 free(oval);
1253 return (1);
1254 }
1255 if (!nflag)
1256 printf("%s%s", name, sep);
1257 if (lflag)
1258 printf("%zd%s", len, sep);
1259 printf("Format:%s Length:%zu Dump:0x", fmt, len);
1260 while (len-- && (xflag || p < val + 16))
1261 printf("%02x", *p++);
1262 if (!xflag && len > 16)
1263 printf("...");
1264 free(oval);
1265 return (0);
1266 }
1267 free(oval);
1268 return (1);
1269 }
1270
1271 static int
sysctl_all(int * oid,int len)1272 sysctl_all(int *oid, int len)
1273 {
1274 int name1[22], name2[22];
1275 int i, j;
1276 size_t l1, l2;
1277
1278 name1[0] = CTL_SYSCTL;
1279 name1[1] = (oid != NULL || Nflag || dflag || tflag) ?
1280 CTL_SYSCTL_NEXTNOSKIP : CTL_SYSCTL_NEXT;
1281 l1 = 2;
1282 if (len) {
1283 memcpy(name1 + 2, oid, len * sizeof(int));
1284 l1 += len;
1285 } else {
1286 name1[2] = CTL_KERN;
1287 l1++;
1288 }
1289 for (;;) {
1290 l2 = sizeof(name2);
1291 j = sysctl(name1, l1, name2, &l2, 0, 0);
1292 if (j < 0) {
1293 if (errno == ENOENT)
1294 return (0);
1295 else
1296 err(1, "sysctl(getnext) %d %zu", j, l2);
1297 }
1298
1299 l2 /= sizeof(int);
1300
1301 if (len < 0 || l2 < (unsigned int)len)
1302 return (0);
1303
1304 if (memcmp(name2, oid, len * sizeof(int)) != 0)
1305 return (0);
1306
1307 i = show_var(name2, l2, true);
1308 if (!i && !bflag)
1309 putchar('\n');
1310
1311 memcpy(name1 + 2, name2, l2 * sizeof(int));
1312 l1 = 2 + l2;
1313 }
1314 }
1315