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 366287463Ssbruno if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) { 367264269Ssbruno usage("Error: Missing 'interpreter' argument"); 368264269Ssbruno } 369264269Ssbruno 370264269Ssbruno return (0); 371264269Ssbruno} 372264269Ssbruno 373264269Ssbrunoint 374278961Ssbrunoname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe) 375264269Ssbruno{ 376278961Ssbruno if (argc == 0) 377278961Ssbruno usage("Required argument missing\n"); 378264269Ssbruno if (strlen(argv[0]) > IBE_NAME_MAX) 379264269Ssbruno usage("'%s' string length longer than IBE_NAME_MAX (%d)", 380264269Ssbruno IBE_NAME_MAX); 381264269Ssbruno strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX); 382264269Ssbruno 383264269Ssbruno return (0); 384264269Ssbruno} 385264269Ssbruno 386264269Ssbrunoint 387264269Ssbrunononame_cmd(__unused int argc, __unused char *argv[], 388264269Ssbruno __unused ximgact_binmisc_entry_t *xbe) 389264269Ssbruno{ 390264269Ssbruno 391264269Ssbruno return (0); 392264269Ssbruno} 393264269Ssbruno 394264269Ssbrunoint 395264269Ssbrunomain(int argc, char **argv) 396264269Ssbruno{ 397264269Ssbruno int error = 0, cmd = -1; 398264269Ssbruno ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL; 399264269Ssbruno ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL; 400264269Ssbruno size_t xbe_in_sz = 0; 401264269Ssbruno size_t xbe_out_sz = 0, *xbe_out_szp = NULL; 402264269Ssbruno uint32_t i; 403264269Ssbruno 404264269Ssbruno if (kldfind(KMOD_NAME) == -1) { 405264269Ssbruno if (kldload(KMOD_NAME) == -1) 406264269Ssbruno fatal("Can't load %s kernel module: %s", 407264269Ssbruno KMOD_NAME, strerror(errno)); 408264269Ssbruno } 409264269Ssbruno 410264269Ssbruno bzero(&xbe_in, sizeof(xbe_in)); 411264269Ssbruno bzero(&xbe_out, sizeof(xbe_out)); 412264269Ssbruno xbe_in.xbe_version = IBE_VERSION; 413264269Ssbruno 414264269Ssbruno if (argc < 2) 415264269Ssbruno usage("Error: requires at least one argument"); 416264269Ssbruno 417264269Ssbruno argc--, argv++; 418264269Ssbruno cmd = demux_cmd(argc, argv); 419264269Ssbruno if (cmd == -1) 420264269Ssbruno usage("Error: Unknown command \"%s\"", argv[0]); 421264269Ssbruno argc--, argv++; 422264269Ssbruno 423264269Ssbruno error = (*cmds[cmd].func)(argc, argv, &xbe_in); 424264269Ssbruno if (error) 425264269Ssbruno usage("Can't parse command-line for '%s' command", 426264269Ssbruno cmds[cmd].name); 427264269Ssbruno 428264269Ssbruno if (cmd != CMD_LIST) { 429264269Ssbruno xbe_inp = &xbe_in; 430264269Ssbruno xbe_in_sz = sizeof(xbe_in); 431264269Ssbruno } else 432264269Ssbruno xbe_out_szp = &xbe_out_sz; 433264269Ssbruno if (cmd == CMD_LOOKUP) { 434264269Ssbruno xbe_out_sz = sizeof(xbe_out); 435264269Ssbruno xbe_outp = &xbe_out; 436264269Ssbruno xbe_out_szp = &xbe_out_sz; 437264269Ssbruno } 438264269Ssbruno 439264269Ssbruno error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp, 440264269Ssbruno xbe_inp, xbe_in_sz); 441264269Ssbruno 442264269Ssbruno if (error) 443264269Ssbruno switch(errno) { 444264269Ssbruno case EINVAL: 445264269Ssbruno usage("Invalid interpreter name or --interpreter, " 446264269Ssbruno "--magic, --mask, or --size argument value"); 447264269Ssbruno break; 448264269Ssbruno 449264269Ssbruno case EEXIST: 450264269Ssbruno usage("'%s' is not unique in activator list", 451264269Ssbruno xbe_in.xbe_name); 452264269Ssbruno break; 453264269Ssbruno 454264269Ssbruno case ENOENT: 455264269Ssbruno usage("'%s' is not found in activator list", 456264269Ssbruno xbe_in.xbe_name); 457264269Ssbruno break; 458264269Ssbruno 459264269Ssbruno case ENOSPC: 460264269Ssbruno fatal("Fatal: no more room in the activator list " 461264269Ssbruno "(limited to %d enties)", IBE_MAX_ENTRIES); 462264269Ssbruno break; 463264269Ssbruno 464264269Ssbruno case EPERM: 465264269Ssbruno usage("Insufficient privileges for '%s' command", 466264269Ssbruno cmds[cmd].name); 467264269Ssbruno break; 468264269Ssbruno 469264269Ssbruno default: 470264269Ssbruno fatal("Fatal: sysctlbyname() returned: %s", 471264269Ssbruno strerror(errno)); 472264269Ssbruno break; 473264269Ssbruno } 474264269Ssbruno 475264269Ssbruno 476264269Ssbruno if (cmd == CMD_LOOKUP) 477264269Ssbruno printxbe(xbe_outp); 478264269Ssbruno 479264269Ssbruno if (cmd == CMD_LIST && xbe_out_sz > 0) { 480264269Ssbruno xbe_outp = malloc(xbe_out_sz); 481264269Ssbruno if (!xbe_outp) 482264269Ssbruno fatal("Fatal: out of memory"); 483264269Ssbruno while(1) { 484264269Ssbruno size_t osize = xbe_out_sz; 485264269Ssbruno error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, 486264269Ssbruno &xbe_out_sz, NULL, 0); 487264269Ssbruno 488264269Ssbruno if (error == -1 && errno == ENOMEM && 489264269Ssbruno xbe_out_sz == osize) { 490264269Ssbruno /* 491264269Ssbruno * Buffer too small. Increase it by one 492264269Ssbruno * entry. 493264269Ssbruno */ 494264269Ssbruno xbe_out_sz += sizeof(xbe_out); 495264269Ssbruno xbe_outp = realloc(xbe_outp, xbe_out_sz); 496264269Ssbruno if (!xbe_outp) 497264269Ssbruno fatal("Fatal: out of memory"); 498264269Ssbruno } else 499264269Ssbruno break; 500264269Ssbruno } 501264269Ssbruno if (error) { 502264269Ssbruno free(xbe_outp); 503264269Ssbruno fatal("Fatal: %s", strerror(errno)); 504264269Ssbruno } 505264269Ssbruno for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++) 506264269Ssbruno printxbe(&xbe_outp[i]); 507264269Ssbruno } 508264269Ssbruno 509264269Ssbruno return (error); 510264269Ssbruno} 511