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