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