]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/sysctl/sysctl.c
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
[FreeBSD/FreeBSD.git] / sbin / sysctl / sysctl.c
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 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1993\n\
35         The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)from: sysctl.c      8.1 (Berkeley) 6/6/93";
41 #endif
42 static const char rcsid[] =
43   "$FreeBSD$";
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <sys/stat.h>
50 #include <sys/sysctl.h>
51 #include <sys/vmmeter.h>
52
53 #ifdef __amd64__
54 #include <sys/efi.h>
55 #include <machine/metadata.h>
56 #endif
57
58 #if defined(__amd64__) || defined(__i386__)
59 #include <machine/pc/bios.h>
60 #endif
61
62 #include <assert.h>
63 #include <ctype.h>
64 #include <err.h>
65 #include <errno.h>
66 #include <inttypes.h>
67 #include <locale.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <sysexits.h>
72 #include <unistd.h>
73
74 static const char *conffile;
75
76 static int      aflag, bflag, Bflag, dflag, eflag, hflag, iflag;
77 static int      Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag;
78
79 static int      oidfmt(int *, int, char *, u_int *);
80 static int      parsefile(const char *);
81 static int      parse(const char *, int);
82 static int      show_var(int *, int);
83 static int      sysctl_all(int *oid, int len);
84 static int      name2oid(const char *, int *);
85
86 static int      strIKtoi(const char *, char **, const char *);
87
88 static int ctl_sign[CTLTYPE+1] = {
89         [CTLTYPE_INT] = 1,
90         [CTLTYPE_LONG] = 1,
91         [CTLTYPE_S8] = 1,
92         [CTLTYPE_S16] = 1,
93         [CTLTYPE_S32] = 1,
94         [CTLTYPE_S64] = 1,
95 };
96
97 static int ctl_size[CTLTYPE+1] = {
98         [CTLTYPE_INT] = sizeof(int),
99         [CTLTYPE_UINT] = sizeof(u_int),
100         [CTLTYPE_LONG] = sizeof(long),
101         [CTLTYPE_ULONG] = sizeof(u_long),
102         [CTLTYPE_S8] = sizeof(int8_t),
103         [CTLTYPE_S16] = sizeof(int16_t),
104         [CTLTYPE_S32] = sizeof(int32_t),
105         [CTLTYPE_S64] = sizeof(int64_t),
106         [CTLTYPE_U8] = sizeof(uint8_t),
107         [CTLTYPE_U16] = sizeof(uint16_t),
108         [CTLTYPE_U32] = sizeof(uint32_t),
109         [CTLTYPE_U64] = sizeof(uint64_t),
110 };
111
112 static const char *ctl_typename[CTLTYPE+1] = {
113         [CTLTYPE_INT] = "integer",
114         [CTLTYPE_UINT] = "unsigned integer",
115         [CTLTYPE_LONG] = "long integer",
116         [CTLTYPE_ULONG] = "unsigned long",
117         [CTLTYPE_U8] = "uint8_t",
118         [CTLTYPE_U16] = "uint16_t",
119         [CTLTYPE_U32] = "uint32_t",
120         [CTLTYPE_U64] = "uint64_t",
121         [CTLTYPE_S8] = "int8_t",
122         [CTLTYPE_S16] = "int16_t",
123         [CTLTYPE_S32] = "int32_t",
124         [CTLTYPE_S64] = "int64_t",
125         [CTLTYPE_NODE] = "node",
126         [CTLTYPE_STRING] = "string",
127         [CTLTYPE_OPAQUE] = "opaque",
128 };
129
130 static void
131 usage(void)
132 {
133
134         (void)fprintf(stderr, "%s\n%s\n",
135             "usage: sysctl [-bdehiNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...",
136             "       sysctl [-bdehNnoqTtWx] [ -B <bufsize> ] -a");
137         exit(1);
138 }
139
140 int
141 main(int argc, char **argv)
142 {
143         int ch;
144         int warncount = 0;
145
146         setlocale(LC_NUMERIC, "");
147         setbuf(stdout,0);
148         setbuf(stderr,0);
149
150         while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) {
151                 switch (ch) {
152                 case 'A':
153                         /* compatibility */
154                         aflag = oflag = 1;
155                         break;
156                 case 'a':
157                         aflag = 1;
158                         break;
159                 case 'b':
160                         bflag = 1;
161                         break;
162                 case 'B':
163                         Bflag = strtol(optarg, NULL, 0);
164                         break;
165                 case 'd':
166                         dflag = 1;
167                         break;
168                 case 'e':
169                         eflag = 1;
170                         break;
171                 case 'f':
172                         conffile = optarg;
173                         break;
174                 case 'h':
175                         hflag = 1;
176                         break;
177                 case 'i':
178                         iflag = 1;
179                         break;
180                 case 'N':
181                         Nflag = 1;
182                         break;
183                 case 'n':
184                         nflag = 1;
185                         break;
186                 case 'o':
187                         oflag = 1;
188                         break;
189                 case 'q':
190                         qflag = 1;
191                         break;
192                 case 't':
193                         tflag = 1;
194                         break;
195                 case 'T':
196                         Tflag = 1;
197                         break;
198                 case 'w':
199                         /* compatibility */
200                         /* ignored */
201                         break;
202                 case 'W':
203                         Wflag = 1;
204                         break;
205                 case 'X':
206                         /* compatibility */
207                         aflag = xflag = 1;
208                         break;
209                 case 'x':
210                         xflag = 1;
211                         break;
212                 default:
213                         usage();
214                 }
215         }
216         argc -= optind;
217         argv += optind;
218
219         if (Nflag && nflag)
220                 usage();
221         if (aflag && argc == 0)
222                 exit(sysctl_all(0, 0));
223         if (argc == 0 && conffile == NULL)
224                 usage();
225
226         warncount = 0;
227         if (conffile != NULL)
228                 warncount += parsefile(conffile);
229
230         while (argc-- > 0)
231                 warncount += parse(*argv++, 0);
232
233         return (warncount);
234 }
235
236 /*
237  * Parse a name into a MIB entry.
238  * Lookup and print out the MIB entry if it exists.
239  * Set a new value if requested.
240  */
241 static int
242 parse(const char *string, int lineno)
243 {
244         int len, i, j;
245         const void *newval;
246         const char *newvalstr = NULL;
247         int8_t i8val;
248         uint8_t u8val;
249         int16_t i16val;
250         uint16_t u16val;
251         int32_t i32val;
252         uint32_t u32val;
253         int intval;
254         unsigned int uintval;
255         long longval;
256         unsigned long ulongval;
257         size_t newsize = Bflag;
258         int64_t i64val;
259         uint64_t u64val;
260         int mib[CTL_MAXNAME];
261         char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
262         u_int kind;
263
264         if (lineno)
265                 snprintf(line, sizeof(line), " at line %d", lineno);
266         else
267                 line[0] = '\0';
268
269         cp = buf;
270         if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
271                 warnx("oid too long: '%s'%s", string, line);
272                 return (1);
273         }
274         bufp = strsep(&cp, "=:");
275         if (cp != NULL) {
276                 /* Tflag just lists tunables, do not allow assignment */
277                 if (Tflag || Wflag) {
278                         warnx("Can't set variables when using -T or -W");
279                         usage();
280                 }
281                 while (isspace(*cp))
282                         cp++;
283                 /* Strip a pair of " or ' if any. */
284                 switch (*cp) {
285                 case '\"':
286                 case '\'':
287                         if (cp[strlen(cp) - 1] == *cp)
288                                 cp[strlen(cp) - 1] = '\0';
289                         cp++;
290                 }
291                 newvalstr = cp;
292                 newsize = strlen(cp);
293         }
294         /* Trim spaces */
295         cp = bufp + strlen(bufp) - 1;
296         while (cp >= bufp && isspace((int)*cp)) {
297                 *cp = '\0';
298                 cp--;
299         }
300         len = name2oid(bufp, mib);
301
302         if (len < 0) {
303                 if (iflag)
304                         return (0);
305                 if (qflag)
306                         return (1);
307                 else {
308                         if (errno == ENOENT) {
309                                 warnx("unknown oid '%s'%s", bufp, line);
310                         } else {
311                                 warn("unknown oid '%s'%s", bufp, line);
312                         }
313                         return (1);
314                 }
315         }
316
317         if (oidfmt(mib, len, fmt, &kind)) {
318                 warn("couldn't find format of oid '%s'%s", bufp, line);
319                 if (iflag)
320                         return (1);
321                 else
322                         exit(1);
323         }
324
325         if (newvalstr == NULL || dflag) {
326                 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
327                         if (dflag) {
328                                 i = show_var(mib, len);
329                                 if (!i && !bflag)
330                                         putchar('\n');
331                         }
332                         sysctl_all(mib, len);
333                 } else {
334                         i = show_var(mib, len);
335                         if (!i && !bflag)
336                                 putchar('\n');
337                 }
338         } else {
339                 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
340                         warnx("oid '%s' isn't a leaf node%s", bufp, line);
341                         return (1);
342                 }
343
344                 if (!(kind & CTLFLAG_WR)) {
345                         if (kind & CTLFLAG_TUN) {
346                                 warnx("oid '%s' is a read only tunable%s", bufp, line);
347                                 warnx("Tunable values are set in /boot/loader.conf");
348                         } else
349                                 warnx("oid '%s' is read only%s", bufp, line);
350                         return (1);
351                 }
352
353                 switch (kind & CTLTYPE) {
354                 case CTLTYPE_INT:
355                 case CTLTYPE_UINT:
356                 case CTLTYPE_LONG:
357                 case CTLTYPE_ULONG:
358                 case CTLTYPE_S8:
359                 case CTLTYPE_S16:
360                 case CTLTYPE_S32:
361                 case CTLTYPE_S64:
362                 case CTLTYPE_U8:
363                 case CTLTYPE_U16:
364                 case CTLTYPE_U32:
365                 case CTLTYPE_U64:
366                         if (strlen(newvalstr) == 0) {
367                                 warnx("empty numeric value");
368                                 return (1);
369                         }
370                         /* FALLTHROUGH */
371                 case CTLTYPE_STRING:
372                         break;
373                 default:
374                         warnx("oid '%s' is type %d,"
375                                 " cannot set that%s", bufp,
376                                 kind & CTLTYPE, line);
377                         return (1);
378                 }
379
380                 errno = 0;
381
382                 switch (kind & CTLTYPE) {
383                         case CTLTYPE_INT:
384                                 if (strncmp(fmt, "IK", 2) == 0)
385                                         intval = strIKtoi(newvalstr, &endptr, fmt);
386                                 else
387                                         intval = (int)strtol(newvalstr, &endptr,
388                                             0);
389                                 newval = &intval;
390                                 newsize = sizeof(intval);
391                                 break;
392                         case CTLTYPE_UINT:
393                                 uintval = (int) strtoul(newvalstr, &endptr, 0);
394                                 newval = &uintval;
395                                 newsize = sizeof(uintval);
396                                 break;
397                         case CTLTYPE_LONG:
398                                 longval = strtol(newvalstr, &endptr, 0);
399                                 newval = &longval;
400                                 newsize = sizeof(longval);
401                                 break;
402                         case CTLTYPE_ULONG:
403                                 ulongval = strtoul(newvalstr, &endptr, 0);
404                                 newval = &ulongval;
405                                 newsize = sizeof(ulongval);
406                                 break;
407                         case CTLTYPE_STRING:
408                                 newval = newvalstr;
409                                 break;
410                         case CTLTYPE_S8:
411                                 i8val = (int8_t)strtol(newvalstr, &endptr, 0);
412                                 newval = &i8val;
413                                 newsize = sizeof(i8val);
414                                 break;
415                         case CTLTYPE_S16:
416                                 i16val = (int16_t)strtol(newvalstr, &endptr,
417                                     0);
418                                 newval = &i16val;
419                                 newsize = sizeof(i16val);
420                                 break;
421                         case CTLTYPE_S32:
422                                 i32val = (int32_t)strtol(newvalstr, &endptr,
423                                     0);
424                                 newval = &i32val;
425                                 newsize = sizeof(i32val);
426                                 break;
427                         case CTLTYPE_S64:
428                                 i64val = strtoimax(newvalstr, &endptr, 0);
429                                 newval = &i64val;
430                                 newsize = sizeof(i64val);
431                                 break;
432                         case CTLTYPE_U8:
433                                 u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
434                                 newval = &u8val;
435                                 newsize = sizeof(u8val);
436                                 break;
437                         case CTLTYPE_U16:
438                                 u16val = (uint16_t)strtoul(newvalstr, &endptr,
439                                     0);
440                                 newval = &u16val;
441                                 newsize = sizeof(u16val);
442                                 break;
443                         case CTLTYPE_U32:
444                                 u32val = (uint32_t)strtoul(newvalstr, &endptr,
445                                     0);
446                                 newval = &u32val;
447                                 newsize = sizeof(u32val);
448                                 break;
449                         case CTLTYPE_U64:
450                                 u64val = strtoumax(newvalstr, &endptr, 0);
451                                 newval = &u64val;
452                                 newsize = sizeof(u64val);
453                                 break;
454                         default:
455                                 /* NOTREACHED */
456                                 abort();
457                 }
458
459                 if (errno != 0 || endptr == newvalstr ||
460                     (endptr != NULL && *endptr != '\0')) {
461                         warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
462                             newvalstr, line);
463                         return (1);
464                 }
465
466                 i = show_var(mib, len);
467                 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
468                         if (!i && !bflag)
469                                 putchar('\n');
470                         switch (errno) {
471                         case EOPNOTSUPP:
472                                 warnx("%s: value is not available%s",
473                                         string, line);
474                                 return (1);
475                         case ENOTDIR:
476                                 warnx("%s: specification is incomplete%s",
477                                         string, line);
478                                 return (1);
479                         case ENOMEM:
480                                 warnx("%s: type is unknown to this program%s",
481                                         string, line);
482                                 return (1);
483                         default:
484                                 warn("%s%s", string, line);
485                                 return (1);
486                         }
487                 }
488                 if (!bflag)
489                         printf(" -> ");
490                 i = nflag;
491                 nflag = 1;
492                 j = show_var(mib, len);
493                 if (!j && !bflag)
494                         putchar('\n');
495                 nflag = i;
496         }
497
498         return (0);
499 }
500
501 static int
502 parsefile(const char *filename)
503 {
504         FILE *file;
505         char line[BUFSIZ], *p, *pq, *pdq;
506         int warncount = 0, lineno = 0;
507
508         file = fopen(filename, "r");
509         if (file == NULL)
510                 err(EX_NOINPUT, "%s", filename);
511         while (fgets(line, sizeof(line), file) != NULL) {
512                 lineno++;
513                 p = line;
514                 pq = strchr(line, '\'');
515                 pdq = strchr(line, '\"');
516                 /* Replace the first # with \0. */
517                 while((p = strchr(p, '#')) != NULL) {
518                         if (pq != NULL && p > pq) {
519                                 if ((p = strchr(pq+1, '\'')) != NULL)
520                                         *(++p) = '\0';
521                                 break;
522                         } else if (pdq != NULL && p > pdq) {
523                                 if ((p = strchr(pdq+1, '\"')) != NULL)
524                                         *(++p) = '\0';
525                                 break;
526                         } else if (p == line || *(p-1) != '\\') {
527                                 *p = '\0';
528                                 break;
529                         }
530                         p++;
531                 }
532                 /* Trim spaces */
533                 p = line + strlen(line) - 1;
534                 while (p >= line && isspace((int)*p)) {
535                         *p = '\0';
536                         p--;
537                 }
538                 p = line;
539                 while (isspace((int)*p))
540                         p++;
541                 if (*p == '\0')
542                         continue;
543                 else
544                         warncount += parse(p, lineno);
545         }
546         fclose(file);
547
548         return (warncount);
549 }
550
551 /* These functions will dump out various interesting structures. */
552
553 static int
554 S_clockinfo(size_t l2, void *p)
555 {
556         struct clockinfo *ci = (struct clockinfo*)p;
557
558         if (l2 != sizeof(*ci)) {
559                 warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
560                 return (1);
561         }
562         printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
563                 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
564                 ci->hz, ci->tick, ci->profhz, ci->stathz);
565         return (0);
566 }
567
568 static int
569 S_loadavg(size_t l2, void *p)
570 {
571         struct loadavg *tv = (struct loadavg*)p;
572
573         if (l2 != sizeof(*tv)) {
574                 warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
575                 return (1);
576         }
577         printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
578                 (double)tv->ldavg[0]/(double)tv->fscale,
579                 (double)tv->ldavg[1]/(double)tv->fscale,
580                 (double)tv->ldavg[2]/(double)tv->fscale);
581         return (0);
582 }
583
584 static int
585 S_timeval(size_t l2, void *p)
586 {
587         struct timeval *tv = (struct timeval*)p;
588         time_t tv_sec;
589         char *p1, *p2;
590
591         if (l2 != sizeof(*tv)) {
592                 warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
593                 return (1);
594         }
595         printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
596                 "{ sec = %jd, usec = %ld } ",
597                 (intmax_t)tv->tv_sec, tv->tv_usec);
598         tv_sec = tv->tv_sec;
599         p1 = strdup(ctime(&tv_sec));
600         for (p2=p1; *p2 ; p2++)
601                 if (*p2 == '\n')
602                         *p2 = '\0';
603         fputs(p1, stdout);
604         free(p1);
605         return (0);
606 }
607
608 static int
609 S_vmtotal(size_t l2, void *p)
610 {
611         struct vmtotal *v;
612         int pageKilo;
613
614         if (l2 != sizeof(*v)) {
615                 warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
616                 return (1);
617         }
618
619         v = p;
620         pageKilo = getpagesize() / 1024;
621
622 #define pg2k(a) ((uintmax_t)(a) * pageKilo)
623         printf("\nSystem wide totals computed every five seconds:"
624             " (values in kilobytes)\n");
625         printf("===============================================\n");
626         printf("Processes:\t\t(RUNQ: %d Disk Wait: %d Page Wait: "
627             "%d Sleep: %d)\n",
628             v->t_rq, v->t_dw, v->t_pw, v->t_sl);
629         printf("Virtual Memory:\t\t(Total: %juK Active: %juK)\n",
630             pg2k(v->t_vm), pg2k(v->t_avm));
631         printf("Real Memory:\t\t(Total: %juK Active: %juK)\n",
632             pg2k(v->t_rm), pg2k(v->t_arm));
633         printf("Shared Virtual Memory:\t(Total: %juK Active: %juK)\n",
634             pg2k(v->t_vmshr), pg2k(v->t_avmshr));
635         printf("Shared Real Memory:\t(Total: %juK Active: %juK)\n",
636             pg2k(v->t_rmshr), pg2k(v->t_armshr));
637         printf("Free Memory:\t%juK", pg2k(v->t_free));
638         return (0);
639 }
640
641 #ifdef __amd64__
642 static int
643 S_efi_map(size_t l2, void *p)
644 {
645         struct efi_map_header *efihdr;
646         struct efi_md *map;
647         const char *type;
648         size_t efisz;
649         int ndesc, i;
650
651         static const char *types[] = {
652                 "Reserved",
653                 "LoaderCode",
654                 "LoaderData",
655                 "BootServicesCode",
656                 "BootServicesData",
657                 "RuntimeServicesCode",
658                 "RuntimeServicesData",
659                 "ConventionalMemory",
660                 "UnusableMemory",
661                 "ACPIReclaimMemory",
662                 "ACPIMemoryNVS",
663                 "MemoryMappedIO",
664                 "MemoryMappedIOPortSpace",
665                 "PalCode"
666         };
667
668         /*
669          * Memory map data provided by UEFI via the GetMemoryMap
670          * Boot Services API.
671          */
672         if (l2 < sizeof(*efihdr)) {
673                 warnx("S_efi_map length less than header");
674                 return (1);
675         }
676         efihdr = p;
677         efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
678         map = (struct efi_md *)((uint8_t *)efihdr + efisz); 
679
680         if (efihdr->descriptor_size == 0)
681                 return (0);
682         if (l2 != efisz + efihdr->memory_size) {
683                 warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
684                     efihdr->memory_size);
685                 return (1);
686         }               
687         ndesc = efihdr->memory_size / efihdr->descriptor_size;
688
689         printf("\n%23s %12s %12s %8s %4s",
690             "Type", "Physical", "Virtual", "#Pages", "Attr");
691
692         for (i = 0; i < ndesc; i++,
693             map = efi_next_descriptor(map, efihdr->descriptor_size)) {
694                 if (map->md_type <= EFI_MD_TYPE_PALCODE)
695                         type = types[map->md_type];
696                 else
697                         type = "<INVALID>";
698                 printf("\n%23s %012jx %12p %08jx ", type,
699                     (uintmax_t)map->md_phys, map->md_virt,
700                     (uintmax_t)map->md_pages);
701                 if (map->md_attr & EFI_MD_ATTR_UC)
702                         printf("UC ");
703                 if (map->md_attr & EFI_MD_ATTR_WC)
704                         printf("WC ");
705                 if (map->md_attr & EFI_MD_ATTR_WT)
706                         printf("WT ");
707                 if (map->md_attr & EFI_MD_ATTR_WB)
708                         printf("WB ");
709                 if (map->md_attr & EFI_MD_ATTR_UCE)
710                         printf("UCE ");
711                 if (map->md_attr & EFI_MD_ATTR_WP)
712                         printf("WP ");
713                 if (map->md_attr & EFI_MD_ATTR_RP)
714                         printf("RP ");
715                 if (map->md_attr & EFI_MD_ATTR_XP)
716                         printf("XP ");
717                 if (map->md_attr & EFI_MD_ATTR_RT)
718                         printf("RUNTIME");
719         }
720         return (0);
721 }
722 #endif
723
724 #if defined(__amd64__) || defined(__i386__)
725 static int
726 S_bios_smap_xattr(size_t l2, void *p)
727 {
728         struct bios_smap_xattr *smap, *end;
729
730         if (l2 % sizeof(*smap) != 0) {
731                 warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
732                     sizeof(*smap));
733                 return (1);
734         }
735
736         end = (struct bios_smap_xattr *)((char *)p + l2);
737         for (smap = p; smap < end; smap++)
738                 printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
739                     smap->type, smap->xattr, (uintmax_t)smap->base,
740                     (uintmax_t)smap->length);
741         return (0);
742 }
743 #endif
744
745 static int
746 strIKtoi(const char *str, char **endptrp, const char *fmt)
747 {
748         int kelv;
749         float temp;
750         size_t len;
751         const char *p;
752         int prec, i;
753
754         assert(errno == 0);
755
756         len = strlen(str);
757         /* caller already checked this */
758         assert(len > 0);
759
760         /*
761          * A format of "IK" is in deciKelvin. A format of "IK3" is in
762          * milliKelvin. The single digit following IK is log10 of the
763          * multiplying factor to convert Kelvin into the untis of this sysctl,
764          * or the dividing factor to convert the sysctl value to Kelvin. Numbers
765          * larger than 6 will run into precision issues with 32-bit integers.
766          * Characters that aren't ASCII digits after the 'K' are ignored. No
767          * localization is present because this is an interface from the kernel
768          * to this program (eg not an end-user interface), so isdigit() isn't
769          * used here.
770          */
771         if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
772                 prec = fmt[2] - '0';
773         else
774                 prec = 1;
775         p = &str[len - 1];
776         if (*p == 'C' || *p == 'F' || *p == 'K') {
777                 temp = strtof(str, endptrp);
778                 if (*endptrp != str && *endptrp == p && errno == 0) {
779                         if (*p == 'F')
780                                 temp = (temp - 32) * 5 / 9;
781                         *endptrp = NULL;
782                         if (*p != 'K')
783                                 temp += 273.15;
784                         for (i = 0; i < prec; i++)
785                                 temp *= 10.0;
786                         return ((int)(temp + 0.5));
787                 }
788         } else {
789                 /* No unit specified -> treat it as a raw number */
790                 kelv = (int)strtol(str, endptrp, 10);
791                 if (*endptrp != str && *endptrp == p && errno == 0) {
792                         *endptrp = NULL;
793                         return (kelv);
794                 }
795         }
796
797         errno = ERANGE;
798         return (0);
799 }
800
801 /*
802  * These functions uses a presently undocumented interface to the kernel
803  * to walk the tree and get the type so it can print the value.
804  * This interface is under work and consideration, and should probably
805  * be killed with a big axe by the first person who can find the time.
806  * (be aware though, that the proper interface isn't as obvious as it
807  * may seem, there are various conflicting requirements.
808  */
809
810 static int
811 name2oid(const char *name, int *oidp)
812 {
813         int oid[2];
814         int i;
815         size_t j;
816
817         oid[0] = 0;
818         oid[1] = 3;
819
820         j = CTL_MAXNAME * sizeof(int);
821         i = sysctl(oid, 2, oidp, &j, name, strlen(name));
822         if (i < 0)
823                 return (i);
824         j /= sizeof(int);
825         return (j);
826 }
827
828 static int
829 oidfmt(int *oid, int len, char *fmt, u_int *kind)
830 {
831         int qoid[CTL_MAXNAME+2];
832         u_char buf[BUFSIZ];
833         int i;
834         size_t j;
835
836         qoid[0] = 0;
837         qoid[1] = 4;
838         memcpy(qoid + 2, oid, len * sizeof(int));
839
840         j = sizeof(buf);
841         i = sysctl(qoid, len + 2, buf, &j, 0, 0);
842         if (i)
843                 err(1, "sysctl fmt %d %zu %d", i, j, errno);
844
845         if (kind)
846                 *kind = *(u_int *)buf;
847
848         if (fmt)
849                 strcpy(fmt, (char *)(buf + sizeof(u_int)));
850         return (0);
851 }
852
853 /*
854  * This formats and outputs the value of one variable
855  *
856  * Returns zero if anything was actually output.
857  * Returns one if didn't know what to do with this.
858  * Return minus one if we had errors.
859  */
860 static int
861 show_var(int *oid, int nlen)
862 {
863         u_char buf[BUFSIZ], *val, *oval, *p;
864         char name[BUFSIZ], fmt[BUFSIZ];
865         const char *sep, *sep1, *prntype;
866         int qoid[CTL_MAXNAME+2];
867         uintmax_t umv;
868         intmax_t mv;
869         int i, hexlen, sign, ctltype;
870         size_t intlen;
871         size_t j, len;
872         u_int kind;
873         float base;
874         int (*func)(size_t, void *);
875         int prec;
876
877         /* Silence GCC. */
878         umv = mv = intlen = 0;
879
880         bzero(buf, BUFSIZ);
881         bzero(fmt, BUFSIZ);
882         bzero(name, BUFSIZ);
883         qoid[0] = 0;
884         memcpy(qoid + 2, oid, nlen * sizeof(int));
885
886         qoid[1] = 1;
887         j = sizeof(name);
888         i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
889         if (i || !j)
890                 err(1, "sysctl name %d %zu %d", i, j, errno);
891
892         oidfmt(oid, nlen, fmt, &kind);
893         /* if Wflag then only list sysctls that are writeable and not stats. */
894         if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
895                 return 1;
896
897         /* if Tflag then only list sysctls that are tuneables. */
898         if (Tflag && (kind & CTLFLAG_TUN) == 0)
899                 return 1;
900
901         if (Nflag) {
902                 printf("%s", name);
903                 return (0);
904         }
905
906         if (eflag)
907                 sep = "=";
908         else
909                 sep = ": ";
910
911         ctltype = (kind & CTLTYPE);
912         if (tflag || dflag) {
913                 if (!nflag)
914                         printf("%s%s", name, sep);
915                 if (ctl_typename[ctltype] != NULL)
916                         prntype = ctl_typename[ctltype];
917                 else
918                         prntype = "unknown";
919                 if (tflag && dflag)
920                         printf("%s%s", prntype, sep);
921                 else if (tflag) {
922                         printf("%s", prntype);
923                         return (0);
924                 }
925                 qoid[1] = 5;
926                 j = sizeof(buf);
927                 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
928                 printf("%s", buf);
929                 return (0);
930         }
931
932         /* don't fetch opaques that we don't know how to print */
933         if (ctltype == CTLTYPE_OPAQUE) {
934                 if (strcmp(fmt, "S,clockinfo") == 0)
935                         func = S_clockinfo;
936                 else if (strcmp(fmt, "S,timeval") == 0)
937                         func = S_timeval;
938                 else if (strcmp(fmt, "S,loadavg") == 0)
939                         func = S_loadavg;
940                 else if (strcmp(fmt, "S,vmtotal") == 0)
941                         func = S_vmtotal;
942 #ifdef __amd64__
943                 else if (strcmp(fmt, "S,efi_map_header") == 0)
944                         func = S_efi_map;
945 #endif
946 #if defined(__amd64__) || defined(__i386__)
947                 else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
948                         func = S_bios_smap_xattr;
949 #endif
950                 else {
951                         func = NULL;
952                         if (!bflag && !oflag && !xflag)
953                                 return (1);
954                 }
955         }
956
957         /* find an estimate of how much we need for this var */
958         if (Bflag)
959                 j = Bflag;
960         else {
961                 j = 0;
962                 i = sysctl(oid, nlen, 0, &j, 0, 0);
963                 j += j; /* we want to be sure :-) */
964         }
965
966         val = oval = malloc(j + 1);
967         if (val == NULL) {
968                 warnx("malloc failed");
969                 return (1);
970         }
971         len = j;
972         i = sysctl(oid, nlen, val, &len, 0, 0);
973         if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
974                 free(oval);
975                 return (1);
976         }
977
978         if (bflag) {
979                 fwrite(val, 1, len, stdout);
980                 free(oval);
981                 return (0);
982         }
983         val[len] = '\0';
984         p = val;
985         sign = ctl_sign[ctltype];
986         intlen = ctl_size[ctltype];
987
988         switch (ctltype) {
989         case CTLTYPE_STRING:
990                 if (!nflag)
991                         printf("%s%s", name, sep);
992                 printf("%.*s", (int)len, p);
993                 free(oval);
994                 return (0);
995
996         case CTLTYPE_INT:
997         case CTLTYPE_UINT:
998         case CTLTYPE_LONG:
999         case CTLTYPE_ULONG:
1000         case CTLTYPE_S8:
1001         case CTLTYPE_S16:
1002         case CTLTYPE_S32:
1003         case CTLTYPE_S64:
1004         case CTLTYPE_U8:
1005         case CTLTYPE_U16:
1006         case CTLTYPE_U32:
1007         case CTLTYPE_U64:
1008                 if (!nflag)
1009                         printf("%s%s", name, sep);
1010                 hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
1011                 sep1 = "";
1012                 while (len >= intlen) {
1013                         switch (kind & CTLTYPE) {
1014                         case CTLTYPE_INT:
1015                         case CTLTYPE_UINT:
1016                                 umv = *(u_int *)p;
1017                                 mv = *(int *)p;
1018                                 break;
1019                         case CTLTYPE_LONG:
1020                         case CTLTYPE_ULONG:
1021                                 umv = *(u_long *)p;
1022                                 mv = *(long *)p;
1023                                 break;
1024                         case CTLTYPE_S8:
1025                         case CTLTYPE_U8:
1026                                 umv = *(uint8_t *)p;
1027                                 mv = *(int8_t *)p;
1028                                 break;
1029                         case CTLTYPE_S16:
1030                         case CTLTYPE_U16:
1031                                 umv = *(uint16_t *)p;
1032                                 mv = *(int16_t *)p;
1033                                 break;
1034                         case CTLTYPE_S32:
1035                         case CTLTYPE_U32:
1036                                 umv = *(uint32_t *)p;
1037                                 mv = *(int32_t *)p;
1038                                 break;
1039                         case CTLTYPE_S64:
1040                         case CTLTYPE_U64:
1041                                 umv = *(uint64_t *)p;
1042                                 mv = *(int64_t *)p;
1043                                 break;
1044                         }
1045                         fputs(sep1, stdout);
1046                         if (xflag)
1047                                 printf("%#0*jx", hexlen, umv);
1048                         else if (!sign)
1049                                 printf(hflag ? "%'ju" : "%ju", umv);
1050                         else if (fmt[1] == 'K') {
1051                                 if (mv < 0)
1052                                         printf("%jd", mv);
1053                                 else {
1054                                         /*
1055                                          * See strIKtoi for details on fmt.
1056                                          */
1057                                         prec = 1;
1058                                         if (fmt[2] != '\0')
1059                                                 prec = fmt[2] - '0';
1060                                         base = 1.0;
1061                                         for (int i = 0; i < prec; i++)
1062                                                 base *= 10.0;
1063                                         printf("%.*fC", prec,
1064                                             (float)mv / base - 273.15);
1065                                 }
1066                         } else
1067                                 printf(hflag ? "%'jd" : "%jd", mv);
1068                         sep1 = " ";
1069                         len -= intlen;
1070                         p += intlen;
1071                 }
1072                 free(oval);
1073                 return (0);
1074
1075         case CTLTYPE_OPAQUE:
1076                 i = 0;
1077                 if (func) {
1078                         if (!nflag)
1079                                 printf("%s%s", name, sep);
1080                         i = (*func)(len, p);
1081                         free(oval);
1082                         return (i);
1083                 }
1084                 /* FALLTHROUGH */
1085         default:
1086                 if (!oflag && !xflag) {
1087                         free(oval);
1088                         return (1);
1089                 }
1090                 if (!nflag)
1091                         printf("%s%s", name, sep);
1092                 printf("Format:%s Length:%zu Dump:0x", fmt, len);
1093                 while (len-- && (xflag || p < val + 16))
1094                         printf("%02x", *p++);
1095                 if (!xflag && len > 16)
1096                         printf("...");
1097                 free(oval);
1098                 return (0);
1099         }
1100         free(oval);
1101         return (1);
1102 }
1103
1104 static int
1105 sysctl_all(int *oid, int len)
1106 {
1107         int name1[22], name2[22];
1108         int i, j;
1109         size_t l1, l2;
1110
1111         name1[0] = 0;
1112         name1[1] = 2;
1113         l1 = 2;
1114         if (len) {
1115                 memcpy(name1+2, oid, len * sizeof(int));
1116                 l1 += len;
1117         } else {
1118                 name1[2] = 1;
1119                 l1++;
1120         }
1121         for (;;) {
1122                 l2 = sizeof(name2);
1123                 j = sysctl(name1, l1, name2, &l2, 0, 0);
1124                 if (j < 0) {
1125                         if (errno == ENOENT)
1126                                 return (0);
1127                         else
1128                                 err(1, "sysctl(getnext) %d %zu", j, l2);
1129                 }
1130
1131                 l2 /= sizeof(int);
1132
1133                 if (len < 0 || l2 < (unsigned int)len)
1134                         return (0);
1135
1136                 for (i = 0; i < len; i++)
1137                         if (name2[i] != oid[i])
1138                                 return (0);
1139
1140                 i = show_var(name2, l2);
1141                 if (!i && !bflag)
1142                         putchar('\n');
1143
1144                 memcpy(name1+2, name2, l2 * sizeof(int));
1145                 l1 = 2 + l2;
1146         }
1147 }