1264269Ssbruno/*-
2264269Ssbruno * Copyright (c) 2013 Stacey D. Son
3264269Ssbruno * All rights reserved.
4264269Ssbruno *
5264269Ssbruno * Redistribution and use in source and binary forms, with or without
6264269Ssbruno * modification, are permitted provided that the following conditions
7264269Ssbruno * are met:
8264269Ssbruno * 1. Redistributions of source code must retain the above copyright
9264269Ssbruno *    notice, this list of conditions and the following disclaimer.
10264269Ssbruno * 2. Redistributions in binary form must reproduce the above copyright
11264269Ssbruno *    notice, this list of conditions and the following disclaimer in the
12264269Ssbruno *    documentation and/or other materials provided with the distribution.
13264269Ssbruno *
14264269Ssbruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15264269Ssbruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16264269Ssbruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17264269Ssbruno * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18264269Ssbruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19264269Ssbruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20264269Ssbruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21264269Ssbruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22264269Ssbruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23264269Ssbruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24264269Ssbruno * SUCH DAMAGE.
25264269Ssbruno *
26264269Ssbruno */
27264269Ssbruno
28264269Ssbruno#include <sys/cdefs.h>
29264269Ssbruno__FBSDID("$FreeBSD$");
30264269Ssbruno
31264269Ssbruno#include <ctype.h>
32264269Ssbruno#include <errno.h>
33264269Ssbruno#include <getopt.h>
34264269Ssbruno#include <stdio.h>
35264269Ssbruno#include <stdarg.h>
36264269Ssbruno#include <stdint.h>
37264269Ssbruno#include <stdlib.h>
38264269Ssbruno#include <string.h>
39264269Ssbruno
40264269Ssbruno#include <sys/types.h>
41264269Ssbruno#include <sys/imgact_binmisc.h>
42264269Ssbruno#include <sys/linker.h>
43264269Ssbruno#include <sys/sysctl.h>
44264269Ssbruno
45264269Ssbrunoenum cmd {
46264269Ssbruno	CMD_ADD = 0,
47264269Ssbruno	CMD_REMOVE,
48264269Ssbruno	CMD_DISABLE,
49264269Ssbruno	CMD_ENABLE,
50264269Ssbruno	CMD_LOOKUP,
51264269Ssbruno	CMD_LIST,
52264269Ssbruno};
53264269Ssbruno
54264269Ssbrunoextern char *__progname;
55264269Ssbruno
56264269Ssbrunotypedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
57264269Ssbruno
58264269Ssbrunoint add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
59264269Ssbrunoint name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
60264269Ssbrunoint noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
61264269Ssbruno
62264269Ssbrunostatic const struct {
63264269Ssbruno	const int token;
64264269Ssbruno	const char *name;
65264269Ssbruno	cmd_func_t func;
66264269Ssbruno	const char *desc;
67264269Ssbruno	const char *args;
68264269Ssbruno} cmds[] = {
69264269Ssbruno	{
70264269Ssbruno		CMD_ADD,
71264269Ssbruno		"add",
72264269Ssbruno		add_cmd,
73264269Ssbruno		"Add a new binary image activator (requires 'root' privilege)",
74264269Ssbruno		"<name> --interpreter <path_and_arguments> \\\n"
75264269Ssbruno		"\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
76264269Ssbruno		"\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
77264269Ssbruno		"\t\t[--set-enabled]"
78264269Ssbruno	},
79264269Ssbruno	{
80264269Ssbruno		CMD_REMOVE,
81264269Ssbruno		"remove",
82264269Ssbruno		name_cmd,
83264269Ssbruno		"Remove a binary image activator (requires 'root' privilege)",
84264269Ssbruno		"<name>"
85264269Ssbruno	},
86264269Ssbruno	{
87264269Ssbruno		CMD_DISABLE,
88264269Ssbruno		"disable",
89264269Ssbruno		name_cmd,
90264269Ssbruno		"Disable a binary image activator (requires 'root' privilege)",
91264269Ssbruno		"<name>"
92264269Ssbruno	},
93264269Ssbruno	{
94264269Ssbruno		CMD_ENABLE,
95264269Ssbruno		"enable",
96264269Ssbruno		name_cmd,
97264269Ssbruno		"Enable a binary image activator (requires 'root' privilege)",
98264269Ssbruno		"<name>"
99264269Ssbruno	},
100264269Ssbruno	{
101264269Ssbruno		CMD_LOOKUP,
102264269Ssbruno		"lookup",
103264269Ssbruno		name_cmd,
104264269Ssbruno		"Lookup a binary image activator",
105264269Ssbruno		"<name>"
106264269Ssbruno	},
107264269Ssbruno	{
108264269Ssbruno		CMD_LIST,
109264269Ssbruno		"list",
110264269Ssbruno		noname_cmd,
111264269Ssbruno		"List all the binary image activators",
112264269Ssbruno		""
113264269Ssbruno	},
114264269Ssbruno};
115264269Ssbruno
116264269Ssbrunostatic const struct option
117264269Ssbrunoadd_opts[] = {
118264269Ssbruno	{ "set-enabled",	no_argument,		NULL,	'e' },
119264269Ssbruno	{ "interpreter",	required_argument,	NULL,	'i' },
120264269Ssbruno	{ "mask",		required_argument,	NULL,	'M' },
121264269Ssbruno	{ "magic",		required_argument,	NULL,	'm' },
122264269Ssbruno	{ "offset",		required_argument,	NULL,	'o' },
123264269Ssbruno	{ "size",		required_argument,	NULL,	's' },
124264269Ssbruno	{ NULL,			0,			NULL,	0   }
125264269Ssbruno};
126264269Ssbruno
127264269Ssbrunostatic char const *cmd_sysctl_name[] = {
128264269Ssbruno	IBE_SYSCTL_NAME_ADD,
129264269Ssbruno	IBE_SYSCTL_NAME_REMOVE,
130264269Ssbruno	IBE_SYSCTL_NAME_DISABLE,
131264269Ssbruno	IBE_SYSCTL_NAME_ENABLE,
132264269Ssbruno	IBE_SYSCTL_NAME_LOOKUP,
133264269Ssbruno	IBE_SYSCTL_NAME_LIST
134264269Ssbruno};
135264269Ssbruno
136264269Ssbrunostatic void
137264269Ssbrunousage(const char *format, ...)
138264269Ssbruno{
139264269Ssbruno	va_list args;
140264269Ssbruno	size_t i;
141264269Ssbruno	int error = 0;
142264269Ssbruno
143264269Ssbruno	va_start(args, format);
144264269Ssbruno	if (format) {
145264269Ssbruno		vfprintf(stderr, format, args);
146264269Ssbruno		error = -1;
147264269Ssbruno	}
148264269Ssbruno	va_end(args);
149264269Ssbruno	fprintf(stderr, "\n");
150264269Ssbruno	fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
151264269Ssbruno
152264269Ssbruno	for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
153264269Ssbruno		fprintf(stderr, "%s:\n", cmds[i].desc);
154264269Ssbruno		fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
155264269Ssbruno		    cmds[i].args);
156264269Ssbruno	}
157264269Ssbruno
158264269Ssbruno	exit (error);
159264269Ssbruno}
160264269Ssbruno
161264269Ssbrunostatic void
162264269Ssbrunofatal(const char *format, ...)
163264269Ssbruno{
164264269Ssbruno	va_list args;
165264269Ssbruno
166264269Ssbruno	va_start(args, format);
167264269Ssbruno	if (format)
168264269Ssbruno		vfprintf(stderr, format, args);
169264269Ssbruno	fprintf(stderr, "\n");
170264269Ssbruno
171264269Ssbruno	exit(-1);
172264269Ssbruno}
173264269Ssbruno
174264269Ssbrunostatic void
175264269Ssbrunogetoptstr(char *str, size_t size, const char *argname)
176264269Ssbruno{
177264269Ssbruno	if (strlen(optarg) > size)
178264269Ssbruno		usage("'%s' too large", argname);
179264269Ssbruno	strlcpy(str, optarg, size);
180264269Ssbruno}
181264269Ssbruno
182264269Ssbrunostatic void
183264269Ssbrunoprintxbe(ximgact_binmisc_entry_t *xbe)
184264269Ssbruno{
185264269Ssbruno	uint32_t i, flags = xbe->xbe_flags;
186264269Ssbruno
187264269Ssbruno	if (xbe->xbe_version != IBE_VERSION) {
188264269Ssbruno		fprintf(stderr, "Error: XBE version mismatch\n");
189264269Ssbruno		return;
190264269Ssbruno	}
191264269Ssbruno
192264269Ssbruno	printf("name: %s\n", xbe->xbe_name);
193264269Ssbruno	printf("interpreter: %s\n", xbe->xbe_interpreter);
194264269Ssbruno	printf("flags: %s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
195264269Ssbruno	    (flags & IBF_USE_MASK) ? "USE_MASK " : "");
196264269Ssbruno	printf("magic size: %u\n", xbe->xbe_msize);
197264269Ssbruno	printf("magic offset: %u\n", xbe->xbe_moffset);
198264269Ssbruno
199264269Ssbruno	printf("magic: ");
200264269Ssbruno	for(i = 0; i < xbe->xbe_msize;  i++) {
201264269Ssbruno		if (i && !(i % 12))
202264269Ssbruno			printf("\n       ");
203264269Ssbruno		else
204264269Ssbruno			if (i && !(i % 4))
205264269Ssbruno				printf(" ");
206264269Ssbruno		printf("0x%02x ", xbe->xbe_magic[i]);
207264269Ssbruno	}
208264269Ssbruno	printf("\n");
209264269Ssbruno
210264269Ssbruno	if (flags & IBF_USE_MASK) {
211264269Ssbruno		printf("mask:  ");
212264269Ssbruno		for(i = 0; i < xbe->xbe_msize;  i++) {
213264269Ssbruno			if (i && !(i % 12))
214264269Ssbruno				printf("\n       ");
215264269Ssbruno			else
216264269Ssbruno				if (i && !(i % 4))
217264269Ssbruno					printf(" ");
218264269Ssbruno			printf("0x%02x ", xbe->xbe_mask[i]);
219264269Ssbruno		}
220264269Ssbruno		printf("\n");
221264269Ssbruno	}
222264269Ssbruno
223264269Ssbruno	printf("\n");
224264269Ssbruno}
225264269Ssbruno
226264269Ssbrunostatic int
227264269Ssbrunodemux_cmd(__unused int argc, char *const argv[])
228264269Ssbruno{
229264269Ssbruno	size_t i;
230264269Ssbruno
231264269Ssbruno	optind = 1;
232264269Ssbruno	optreset = 1;
233264269Ssbruno
234264269Ssbruno	for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
235264269Ssbruno		if (!strcasecmp(cmds[i].name, argv[0])) {
236264269Ssbruno			return (i);
237264269Ssbruno		}
238264269Ssbruno	}
239264269Ssbruno
240264269Ssbruno	/* Unknown command */
241264269Ssbruno	return (-1);
242264269Ssbruno}
243264269Ssbruno
244264269Ssbrunostatic int
245264269Ssbrunostrlit2bin_cpy(uint8_t *d, char *s, size_t size)
246264269Ssbruno{
247264269Ssbruno	int c;
248264269Ssbruno	size_t cnt = 0;
249264269Ssbruno
250264269Ssbruno	while((c = *s++) != '\0') {
251264269Ssbruno		if (c == '\\') {
252264269Ssbruno			/* Do '\' escapes. */
253264269Ssbruno			switch (*s) {
254264269Ssbruno			case '\\':
255264269Ssbruno				*d++ = '\\';
256264269Ssbruno				break;
257264269Ssbruno
258264269Ssbruno			case 'x':
259264269Ssbruno				s++;
260264269Ssbruno				c = toupper(*s++);
261264269Ssbruno				*d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
262264269Ssbruno				c = toupper(*s++);
263264269Ssbruno				*d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
264264269Ssbruno				break;
265264269Ssbruno
266264269Ssbruno			default:
267264269Ssbruno				return (-1);
268264269Ssbruno			}
269264269Ssbruno		} else
270264269Ssbruno			*d++ = c;
271264269Ssbruno
272264269Ssbruno		if (++cnt > size)
273264269Ssbruno			return (-1);
274264269Ssbruno	}
275264269Ssbruno
276264269Ssbruno	return (cnt);
277264269Ssbruno}
278264269Ssbruno
279264269Ssbrunoint
280264269Ssbrunoadd_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
281264269Ssbruno{
282264269Ssbruno	int ch;
283264269Ssbruno	char *magic = NULL, *mask = NULL;
284264269Ssbruno	int sz;
285264269Ssbruno
286264269Ssbruno	if (strlen(argv[0]) > IBE_NAME_MAX)
287264269Ssbruno		usage("'%s' string length longer than IBE_NAME_MAX (%d)",
288264269Ssbruno		    IBE_NAME_MAX);
289264269Ssbruno	strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
290264269Ssbruno
291264269Ssbruno	while ((ch = getopt_long(argc, argv, "ei:m:M:o:s:", add_opts, NULL))
292264269Ssbruno	    != -1) {
293264269Ssbruno
294264269Ssbruno		switch(ch) {
295264269Ssbruno		case 'i':
296264269Ssbruno			getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
297264269Ssbruno			    "interpreter");
298264269Ssbruno			break;
299264269Ssbruno
300264269Ssbruno		case 'm':
301264269Ssbruno			magic = strdup(optarg);
302264269Ssbruno			break;
303264269Ssbruno
304264269Ssbruno		case 'M':
305264269Ssbruno			mask = strdup(optarg);
306264269Ssbruno			xbe->xbe_flags |= IBF_USE_MASK;
307264269Ssbruno			break;
308264269Ssbruno
309264269Ssbruno		case 'e':
310264269Ssbruno			xbe->xbe_flags |= IBF_ENABLED;
311264269Ssbruno			break;
312264269Ssbruno
313264269Ssbruno		case 'o':
314264269Ssbruno			xbe->xbe_moffset = atol(optarg);
315264269Ssbruno			break;
316264269Ssbruno
317264269Ssbruno		case 's':
318264269Ssbruno			xbe->xbe_msize = atol(optarg);
319264269Ssbruno			if (xbe->xbe_msize == 0 ||
320264269Ssbruno			    xbe->xbe_msize > IBE_MAGIC_MAX)
321264269Ssbruno				usage("Error: Not valid '--size' value. "
322264269Ssbruno				    "(Must be > 0 and < %u.)\n",
323264269Ssbruno				    xbe->xbe_msize);
324264269Ssbruno			break;
325264269Ssbruno
326264269Ssbruno		default:
327264269Ssbruno			usage("Unknown argument: '%c'", ch);
328264269Ssbruno		}
329264269Ssbruno	}
330264269Ssbruno
331264269Ssbruno	if (xbe->xbe_msize == 0) {
332264269Ssbruno		if (NULL != magic)
333264269Ssbruno			free(magic);
334264269Ssbruno		if (NULL != mask)
335264269Ssbruno			free(mask);
336264269Ssbruno		usage("Error: Missing '--size' argument");
337264269Ssbruno	}
338264269Ssbruno
339264269Ssbruno	if (NULL != magic) {
340264269Ssbruno		if (xbe->xbe_msize == 0) {
341264269Ssbruno			if (magic)
342264269Ssbruno				free(magic);
343264269Ssbruno			if (mask)
344264269Ssbruno				free(mask);
345264269Ssbruno			usage("Error: Missing magic size argument");
346264269Ssbruno		}
347264269Ssbruno		sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
348264269Ssbruno		free(magic);
349264269Ssbruno		if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
350264269Ssbruno			if (mask)
351264269Ssbruno				free(mask);
352264269Ssbruno			usage("Error: invalid magic argument");
353264269Ssbruno		}
354264269Ssbruno		if (mask) {
355264269Ssbruno			sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
356264269Ssbruno			free(mask);
357264269Ssbruno			if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
358264269Ssbruno				usage("Error: invalid mask argument");
359264269Ssbruno		}
360264269Ssbruno	} else {
361264269Ssbruno		if (mask)
362264269Ssbruno			free(mask);
363264269Ssbruno		usage("Error: Missing magic argument");
364264269Ssbruno	}
365264269Ssbruno
366264269Ssbruno	if (!xbe->xbe_interpreter) {
367264269Ssbruno		usage("Error: Missing 'interpreter' argument");
368264269Ssbruno	}
369264269Ssbruno
370264269Ssbruno	return (0);
371264269Ssbruno}
372264269Ssbruno
373264269Ssbrunoint
374264269Ssbrunoname_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
375264269Ssbruno{
376264269Ssbruno	if (strlen(argv[0]) > IBE_NAME_MAX)
377264269Ssbruno		usage("'%s' string length longer than IBE_NAME_MAX (%d)",
378264269Ssbruno		    IBE_NAME_MAX);
379264269Ssbruno	strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
380264269Ssbruno
381264269Ssbruno	return (0);
382264269Ssbruno}
383264269Ssbruno
384264269Ssbrunoint
385264269Ssbrunononame_cmd(__unused int argc, __unused char *argv[],
386264269Ssbruno    __unused ximgact_binmisc_entry_t *xbe)
387264269Ssbruno{
388264269Ssbruno
389264269Ssbruno	return (0);
390264269Ssbruno}
391264269Ssbruno
392264269Ssbrunoint
393264269Ssbrunomain(int argc, char **argv)
394264269Ssbruno{
395264269Ssbruno	int error = 0, cmd = -1;
396264269Ssbruno	ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
397264269Ssbruno	ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
398264269Ssbruno	size_t xbe_in_sz = 0;
399264269Ssbruno	size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
400264269Ssbruno	uint32_t i;
401264269Ssbruno
402264269Ssbruno	if (kldfind(KMOD_NAME) == -1) {
403264269Ssbruno		if (kldload(KMOD_NAME) == -1)
404264269Ssbruno			fatal("Can't load %s kernel module: %s",
405264269Ssbruno			    KMOD_NAME, strerror(errno));
406264269Ssbruno	}
407264269Ssbruno
408264269Ssbruno	bzero(&xbe_in, sizeof(xbe_in));
409264269Ssbruno	bzero(&xbe_out, sizeof(xbe_out));
410264269Ssbruno	xbe_in.xbe_version = IBE_VERSION;
411264269Ssbruno
412264269Ssbruno	if (argc < 2)
413264269Ssbruno		usage("Error: requires at least one argument");
414264269Ssbruno
415264269Ssbruno	argc--, argv++;
416264269Ssbruno	cmd = demux_cmd(argc, argv);
417264269Ssbruno	if (cmd == -1)
418264269Ssbruno		usage("Error: Unknown command \"%s\"", argv[0]);
419264269Ssbruno	argc--, argv++;
420264269Ssbruno
421264269Ssbruno	error = (*cmds[cmd].func)(argc, argv, &xbe_in);
422264269Ssbruno	if (error)
423264269Ssbruno		usage("Can't parse command-line for '%s' command",
424264269Ssbruno		    cmds[cmd].name);
425264269Ssbruno
426264269Ssbruno	if (cmd != CMD_LIST) {
427264269Ssbruno		xbe_inp = &xbe_in;
428264269Ssbruno		xbe_in_sz = sizeof(xbe_in);
429264269Ssbruno	} else
430264269Ssbruno		xbe_out_szp = &xbe_out_sz;
431264269Ssbruno	if (cmd == CMD_LOOKUP) {
432264269Ssbruno		xbe_out_sz = sizeof(xbe_out);
433264269Ssbruno		xbe_outp = &xbe_out;
434264269Ssbruno		xbe_out_szp = &xbe_out_sz;
435264269Ssbruno	}
436264269Ssbruno
437264269Ssbruno	error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
438264269Ssbruno	    xbe_inp, xbe_in_sz);
439264269Ssbruno
440264269Ssbruno	if (error)
441264269Ssbruno		switch(errno) {
442264269Ssbruno		case EINVAL:
443264269Ssbruno			usage("Invalid interpreter name or --interpreter, "
444264269Ssbruno			    "--magic, --mask, or --size argument value");
445264269Ssbruno			break;
446264269Ssbruno
447264269Ssbruno		case EEXIST:
448264269Ssbruno			usage("'%s' is not unique in activator list",
449264269Ssbruno			    xbe_in.xbe_name);
450264269Ssbruno			break;
451264269Ssbruno
452264269Ssbruno		case ENOENT:
453264269Ssbruno			usage("'%s' is not found in activator list",
454264269Ssbruno			    xbe_in.xbe_name);
455264269Ssbruno			break;
456264269Ssbruno
457264269Ssbruno		case ENOSPC:
458264269Ssbruno			fatal("Fatal: no more room in the activator list "
459264269Ssbruno			    "(limited to %d enties)", IBE_MAX_ENTRIES);
460264269Ssbruno			break;
461264269Ssbruno
462264269Ssbruno		case EPERM:
463264269Ssbruno			usage("Insufficient privileges for '%s' command",
464264269Ssbruno			    cmds[cmd].name);
465264269Ssbruno			break;
466264269Ssbruno
467264269Ssbruno		default:
468264269Ssbruno			fatal("Fatal: sysctlbyname() returned: %s",
469264269Ssbruno			    strerror(errno));
470264269Ssbruno			break;
471264269Ssbruno		}
472264269Ssbruno
473264269Ssbruno
474264269Ssbruno	if (cmd == CMD_LOOKUP)
475264269Ssbruno		printxbe(xbe_outp);
476264269Ssbruno
477264269Ssbruno	if (cmd == CMD_LIST && xbe_out_sz > 0) {
478264269Ssbruno		xbe_outp = malloc(xbe_out_sz);
479264269Ssbruno		if (!xbe_outp)
480264269Ssbruno			fatal("Fatal: out of memory");
481264269Ssbruno		while(1) {
482264269Ssbruno			size_t osize = xbe_out_sz;
483264269Ssbruno			error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
484264269Ssbruno			    &xbe_out_sz, NULL, 0);
485264269Ssbruno
486264269Ssbruno			if (error == -1 && errno == ENOMEM &&
487264269Ssbruno			    xbe_out_sz == osize) {
488264269Ssbruno				/*
489264269Ssbruno				 * Buffer too small. Increase it by one
490264269Ssbruno				 * entry.
491264269Ssbruno				 */
492264269Ssbruno				xbe_out_sz += sizeof(xbe_out);
493264269Ssbruno				xbe_outp = realloc(xbe_outp, xbe_out_sz);
494264269Ssbruno				if (!xbe_outp)
495264269Ssbruno					fatal("Fatal: out of memory");
496264269Ssbruno			} else
497264269Ssbruno				break;
498264269Ssbruno		}
499264269Ssbruno		if (error) {
500264269Ssbruno			free(xbe_outp);
501264269Ssbruno			fatal("Fatal: %s", strerror(errno));
502264269Ssbruno		}
503264269Ssbruno		for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++)
504264269Ssbruno			printxbe(&xbe_outp[i]);
505264269Ssbruno	}
506264269Ssbruno
507264269Ssbruno	return (error);
508264269Ssbruno}
509