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