14b844f8dSWarner Losh /*- 2*3c0dcbfcSWarner Losh * Copyright (c) 2016-2021 Netflix, Inc. 34b844f8dSWarner Losh * 44b844f8dSWarner Losh * Redistribution and use in source and binary forms, with or without 54b844f8dSWarner Losh * modification, are permitted provided that the following conditions 64b844f8dSWarner Losh * are met: 74b844f8dSWarner Losh * 1. Redistributions of source code must retain the above copyright 84b844f8dSWarner Losh * notice, this list of conditions and the following disclaimer. 94b844f8dSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 104b844f8dSWarner Losh * notice, this list of conditions and the following disclaimer in the 114b844f8dSWarner Losh * documentation and/or other materials provided with the distribution. 124b844f8dSWarner Losh * 13b2a7ac48SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 144b844f8dSWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 154b844f8dSWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16b2a7ac48SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 174b844f8dSWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 184b844f8dSWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 194b844f8dSWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 204b844f8dSWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 214b844f8dSWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 224b844f8dSWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 234b844f8dSWarner Losh * SUCH DAMAGE. 244b844f8dSWarner Losh */ 254b844f8dSWarner Losh 264b844f8dSWarner Losh #include <sys/cdefs.h> 274b844f8dSWarner Losh __FBSDID("$FreeBSD$"); 284b844f8dSWarner Losh 294b844f8dSWarner Losh #include <ctype.h> 304b844f8dSWarner Losh #include <efivar.h> 312f2f5c67SWarner Losh #include <efivar-dp.h> 324b844f8dSWarner Losh #include <err.h> 334b844f8dSWarner Losh #include <errno.h> 34e08bb109SWarner Losh #include <fcntl.h> 354b844f8dSWarner Losh #include <getopt.h> 36*3c0dcbfcSWarner Losh #include <stdarg.h> 37*3c0dcbfcSWarner Losh #include <stdbool.h> 384b844f8dSWarner Losh #include <stddef.h> 394b844f8dSWarner Losh #include <stdio.h> 404b844f8dSWarner Losh #include <stdlib.h> 414b844f8dSWarner Losh #include <string.h> 424b844f8dSWarner Losh #include <unistd.h> 435709a4b5SWarner Losh #include "efiutil.h" 44b0da7c79SWarner Losh #include "efichar.h" 454b844f8dSWarner Losh 464b844f8dSWarner Losh /* options descriptor */ 474b844f8dSWarner Losh static struct option longopts[] = { 484b844f8dSWarner Losh { "append", no_argument, NULL, 'a' }, 494b844f8dSWarner Losh { "ascii", no_argument, NULL, 'A' }, 504b844f8dSWarner Losh { "attributes", required_argument, NULL, 't' }, 514b844f8dSWarner Losh { "binary", no_argument, NULL, 'b' }, 524b844f8dSWarner Losh { "delete", no_argument, NULL, 'D' }, 539e4a51a8SWarner Losh { "device", no_argument, NULL, 'd' }, 549e4a51a8SWarner Losh { "device-path", no_argument, NULL, 'd' }, 554b844f8dSWarner Losh { "fromfile", required_argument, NULL, 'f' }, 5616445670SWarner Losh { "guid", no_argument, NULL, 'g' }, 574b844f8dSWarner Losh { "hex", no_argument, NULL, 'H' }, 584b844f8dSWarner Losh { "list-guids", no_argument, NULL, 'L' }, 594b844f8dSWarner Losh { "list", no_argument, NULL, 'l' }, 605709a4b5SWarner Losh { "load-option", no_argument, NULL, 'O' }, 614b844f8dSWarner Losh { "name", required_argument, NULL, 'n' }, 624b844f8dSWarner Losh { "no-name", no_argument, NULL, 'N' }, 634b844f8dSWarner Losh { "print", no_argument, NULL, 'p' }, 64f9f298a2SWarner Losh // { "print-decimal", no_argument, NULL, 'd' }, /* unimplemnted clash with linux version */ 65*3c0dcbfcSWarner Losh { "quiet", no_argument, NULL, 'q' }, 664b844f8dSWarner Losh { "raw-guid", no_argument, NULL, 'R' }, 67b0da7c79SWarner Losh { "utf8", no_argument, NULL, 'u' }, 684b844f8dSWarner Losh { "write", no_argument, NULL, 'w' }, 694b844f8dSWarner Losh { NULL, 0, NULL, 0 } 704b844f8dSWarner Losh }; 714b844f8dSWarner Losh 724b844f8dSWarner Losh 7316445670SWarner Losh static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, 745709a4b5SWarner Losh lflag, Lflag, Rflag, wflag, pflag, uflag, load_opt_flag; 75*3c0dcbfcSWarner Losh static bool quiet; 764b844f8dSWarner Losh static char *varname; 77e08bb109SWarner Losh static char *fromfile; 7855ff82c0SWarner Losh static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; 794b844f8dSWarner Losh 804b844f8dSWarner Losh static void 814b844f8dSWarner Losh usage(void) 824b844f8dSWarner Losh { 834b844f8dSWarner Losh 84*3c0dcbfcSWarner Losh errx(1, "efivar [-abdDHlLNpqRtuw] [-n name] [-f file] [--append] [--ascii]\n" 854b844f8dSWarner Losh "\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" 865709a4b5SWarner Losh "\t[--list-guids] [--list] [--load-option] [--name name] [--no-name]\n" 875709a4b5SWarner Losh "\t[--print] [--print-decimal] [--raw-guid] [--utf8] [--write]\n" 88*3c0dcbfcSWarner Losh "\t[--quiet]\n" 895709a4b5SWarner Losh "\tname[=value]"); 904b844f8dSWarner Losh } 914b844f8dSWarner Losh 924b844f8dSWarner Losh static void 93*3c0dcbfcSWarner Losh rep_err(int eval, const char *fmt, ...) 94*3c0dcbfcSWarner Losh { 95*3c0dcbfcSWarner Losh va_list ap; 96*3c0dcbfcSWarner Losh 97*3c0dcbfcSWarner Losh if (quiet) 98*3c0dcbfcSWarner Losh exit(eval); 99*3c0dcbfcSWarner Losh 100*3c0dcbfcSWarner Losh va_start(ap, fmt); 101*3c0dcbfcSWarner Losh verr(eval, fmt, ap); 102*3c0dcbfcSWarner Losh va_end(ap); 103*3c0dcbfcSWarner Losh } 104*3c0dcbfcSWarner Losh 105*3c0dcbfcSWarner Losh static void 106*3c0dcbfcSWarner Losh rep_errx(int eval, const char *fmt, ...) 107*3c0dcbfcSWarner Losh { 108*3c0dcbfcSWarner Losh va_list ap; 109*3c0dcbfcSWarner Losh 110*3c0dcbfcSWarner Losh if (quiet) 111*3c0dcbfcSWarner Losh exit(eval); 112*3c0dcbfcSWarner Losh 113*3c0dcbfcSWarner Losh va_start(ap, fmt); 114*3c0dcbfcSWarner Losh verrx(eval, fmt, ap); 115*3c0dcbfcSWarner Losh va_end(ap); 116*3c0dcbfcSWarner Losh } 117*3c0dcbfcSWarner Losh 118*3c0dcbfcSWarner Losh static void 1194b844f8dSWarner Losh breakdown_name(char *name, efi_guid_t *guid, char **vname) 1204b844f8dSWarner Losh { 1214b844f8dSWarner Losh char *cp; 1224b844f8dSWarner Losh 1234b844f8dSWarner Losh cp = strrchr(name, '-'); 1244b844f8dSWarner Losh if (cp == NULL) 125*3c0dcbfcSWarner Losh rep_errx(1, "Invalid name: %s", name); 1264b844f8dSWarner Losh *vname = cp + 1; 1274b844f8dSWarner Losh *cp = '\0'; 128f2d626abSWarner Losh if (efi_name_to_guid(name, guid) < 0) 129*3c0dcbfcSWarner Losh rep_errx(1, "Invalid guid %s", name); 1304b844f8dSWarner Losh } 1314b844f8dSWarner Losh 1324b844f8dSWarner Losh static uint8_t * 1334b844f8dSWarner Losh get_value(char *val, size_t *datalen) 1344b844f8dSWarner Losh { 1354b844f8dSWarner Losh static char buffer[16*1024]; 1364b844f8dSWarner Losh 1374b844f8dSWarner Losh if (val != NULL) { 1384b844f8dSWarner Losh *datalen = strlen(val); 1394b844f8dSWarner Losh return ((uint8_t *)val); 1404b844f8dSWarner Losh } 1414b844f8dSWarner Losh /* Read from stdin */ 1424b844f8dSWarner Losh *datalen = sizeof(buffer); 1434b844f8dSWarner Losh *datalen = read(0, buffer, *datalen); 1444b844f8dSWarner Losh return ((uint8_t *)buffer); 1454b844f8dSWarner Losh } 1464b844f8dSWarner Losh 1474b844f8dSWarner Losh static void 1484b844f8dSWarner Losh append_variable(char *name, char *val) 1494b844f8dSWarner Losh { 1504b844f8dSWarner Losh char *vname; 1514b844f8dSWarner Losh efi_guid_t guid; 1524b844f8dSWarner Losh size_t datalen; 1534b844f8dSWarner Losh uint8_t *data; 1544b844f8dSWarner Losh 1554b844f8dSWarner Losh breakdown_name(name, &guid, &vname); 1564b844f8dSWarner Losh data = get_value(val, &datalen); 1574b844f8dSWarner Losh if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) 158*3c0dcbfcSWarner Losh rep_err(1, "efi_append_variable"); 1594b844f8dSWarner Losh } 1604b844f8dSWarner Losh 1614b844f8dSWarner Losh static void 1624b844f8dSWarner Losh delete_variable(char *name) 1634b844f8dSWarner Losh { 1644b844f8dSWarner Losh char *vname; 1654b844f8dSWarner Losh efi_guid_t guid; 1664b844f8dSWarner Losh 1674b844f8dSWarner Losh breakdown_name(name, &guid, &vname); 1684b844f8dSWarner Losh if (efi_del_variable(guid, vname) < 0) 169*3c0dcbfcSWarner Losh rep_err(1, "efi_del_variable"); 1704b844f8dSWarner Losh } 1714b844f8dSWarner Losh 1724b844f8dSWarner Losh static void 1734b844f8dSWarner Losh write_variable(char *name, char *val) 1744b844f8dSWarner Losh { 1754b844f8dSWarner Losh char *vname; 1764b844f8dSWarner Losh efi_guid_t guid; 1774b844f8dSWarner Losh size_t datalen; 1784b844f8dSWarner Losh uint8_t *data; 1794b844f8dSWarner Losh 1804b844f8dSWarner Losh breakdown_name(name, &guid, &vname); 1814b844f8dSWarner Losh data = get_value(val, &datalen); 182831bec11SWarner Losh if (efi_set_variable(guid, vname, data, datalen, attrib) < 0) 183*3c0dcbfcSWarner Losh rep_err(1, "efi_set_variable"); 1844b844f8dSWarner Losh } 1854b844f8dSWarner Losh 1864b844f8dSWarner Losh static void 1879e4a51a8SWarner Losh devpath_dump(uint8_t *data, size_t datalen) 1889e4a51a8SWarner Losh { 1892f2f5c67SWarner Losh char buffer[1024]; 1909e4a51a8SWarner Losh 1912f2f5c67SWarner Losh efidp_format_device_path(buffer, sizeof(buffer), 1922f2f5c67SWarner Losh (const_efidp)data, datalen); 1932f2f5c67SWarner Losh if (!Nflag) 1942f2f5c67SWarner Losh printf(": "); 1952f2f5c67SWarner Losh printf("%s\n", buffer); 1969e4a51a8SWarner Losh } 1979e4a51a8SWarner Losh 1989e4a51a8SWarner Losh static void 19916445670SWarner Losh pretty_guid(efi_guid_t *guid, char **gname) 20016445670SWarner Losh { 20116445670SWarner Losh char *pretty = NULL; 20216445670SWarner Losh 20316445670SWarner Losh if (gflag) 20416445670SWarner Losh efi_guid_to_name(guid, &pretty); 20516445670SWarner Losh 20616445670SWarner Losh if (pretty == NULL) 20716445670SWarner Losh efi_guid_to_str(guid, gname); 20816445670SWarner Losh else 20916445670SWarner Losh *gname = pretty; 21016445670SWarner Losh } 21116445670SWarner Losh 21216445670SWarner Losh static void 2134b844f8dSWarner Losh print_var(efi_guid_t *guid, char *name) 2144b844f8dSWarner Losh { 2154b844f8dSWarner Losh uint32_t att; 2164b844f8dSWarner Losh uint8_t *data; 2174b844f8dSWarner Losh size_t datalen; 218e08bb109SWarner Losh char *gname = NULL; 2194b844f8dSWarner Losh int rv; 2204b844f8dSWarner Losh 221e08bb109SWarner Losh if (guid) 22216445670SWarner Losh pretty_guid(guid, &gname); 223e08bb109SWarner Losh if (pflag || fromfile) { 224e08bb109SWarner Losh if (fromfile) { 225e08bb109SWarner Losh int fd; 2264b844f8dSWarner Losh 227e08bb109SWarner Losh fd = open(fromfile, O_RDONLY); 228e08bb109SWarner Losh if (fd < 0) 229*3c0dcbfcSWarner Losh rep_err(1, "open %s", fromfile); 230e08bb109SWarner Losh data = malloc(64 * 1024); 231e08bb109SWarner Losh if (data == NULL) 232*3c0dcbfcSWarner Losh rep_err(1, "malloc"); 233e08bb109SWarner Losh datalen = read(fd, data, 64 * 1024); 234e08bb109SWarner Losh if (datalen <= 0) 235*3c0dcbfcSWarner Losh rep_err(1, "read"); 236e08bb109SWarner Losh close(fd); 237e08bb109SWarner Losh } else { 238e08bb109SWarner Losh rv = efi_get_variable(*guid, name, &data, &datalen, &att); 2394b844f8dSWarner Losh if (rv < 0) 240*3c0dcbfcSWarner Losh rep_err(1, "fetching %s-%s", gname, name); 241e08bb109SWarner Losh } 242e08bb109SWarner Losh 24335a419a2SWarner Losh 24435a419a2SWarner Losh if (!Nflag) 2455709a4b5SWarner Losh printf("%s-%s\n", gname, name); 2465709a4b5SWarner Losh if (load_opt_flag) 2475709a4b5SWarner Losh efi_print_load_option(data, datalen, Aflag, bflag, uflag); 2485709a4b5SWarner Losh else if (Aflag) 2494b844f8dSWarner Losh asciidump(data, datalen); 250b0da7c79SWarner Losh else if (uflag) 251b0da7c79SWarner Losh utf8dump(data, datalen); 2524b844f8dSWarner Losh else if (bflag) 2534b844f8dSWarner Losh bindump(data, datalen); 2549e4a51a8SWarner Losh else if (dflag) 2559e4a51a8SWarner Losh devpath_dump(data, datalen); 2564b844f8dSWarner Losh else 2574b844f8dSWarner Losh hexdump(data, datalen); 258902af7c6SWarner Losh } else { 259902af7c6SWarner Losh printf("%s-%s", gname, name); 2604b844f8dSWarner Losh } 2614b844f8dSWarner Losh free(gname); 2624b844f8dSWarner Losh if (!Nflag) 2634b844f8dSWarner Losh printf("\n"); 2644b844f8dSWarner Losh } 2654b844f8dSWarner Losh 2664b844f8dSWarner Losh static void 2674b844f8dSWarner Losh print_variable(char *name) 2684b844f8dSWarner Losh { 2694b844f8dSWarner Losh char *vname; 2704b844f8dSWarner Losh efi_guid_t guid; 2714b844f8dSWarner Losh 2724b844f8dSWarner Losh breakdown_name(name, &guid, &vname); 2734b844f8dSWarner Losh print_var(&guid, vname); 2744b844f8dSWarner Losh } 2754b844f8dSWarner Losh 2764b844f8dSWarner Losh static void 2774b844f8dSWarner Losh print_variables(void) 2784b844f8dSWarner Losh { 2794b844f8dSWarner Losh int rv; 2804b844f8dSWarner Losh char *name = NULL; 2814b844f8dSWarner Losh efi_guid_t *guid = NULL; 2824b844f8dSWarner Losh 2834b844f8dSWarner Losh while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) 2844b844f8dSWarner Losh print_var(guid, name); 2854b844f8dSWarner Losh 2864b844f8dSWarner Losh if (rv < 0) 287*3c0dcbfcSWarner Losh rep_err(1, "Error listing names"); 2884b844f8dSWarner Losh } 2894b844f8dSWarner Losh 2904b844f8dSWarner Losh static void 2914a110fbfSWarner Losh print_known_guid(void) 2924a110fbfSWarner Losh { 2934a110fbfSWarner Losh struct uuid_table *tbl; 2944a110fbfSWarner Losh int i, n; 2954a110fbfSWarner Losh 2964a110fbfSWarner Losh n = efi_known_guid(&tbl); 2974a110fbfSWarner Losh for (i = 0; i < n; i++) 2984a110fbfSWarner Losh printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); 2994a110fbfSWarner Losh } 3004a110fbfSWarner Losh 3014a110fbfSWarner Losh static void 3024b844f8dSWarner Losh parse_args(int argc, char **argv) 3034b844f8dSWarner Losh { 3044b844f8dSWarner Losh int ch, i; 3054b844f8dSWarner Losh 306*3c0dcbfcSWarner Losh while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:OpqRt:uw", 3074b844f8dSWarner Losh longopts, NULL)) != -1) { 3084b844f8dSWarner Losh switch (ch) { 3094b844f8dSWarner Losh case 'a': 3104b844f8dSWarner Losh aflag++; 3114b844f8dSWarner Losh break; 3124b844f8dSWarner Losh case 'A': 3134b844f8dSWarner Losh Aflag++; 3144b844f8dSWarner Losh break; 3154b844f8dSWarner Losh case 'b': 3164b844f8dSWarner Losh bflag++; 3174b844f8dSWarner Losh break; 3184b844f8dSWarner Losh case 'd': 3194b844f8dSWarner Losh dflag++; 3204b844f8dSWarner Losh break; 3214b844f8dSWarner Losh case 'D': 3224b844f8dSWarner Losh Dflag++; 3234b844f8dSWarner Losh break; 32416445670SWarner Losh case 'g': 32516445670SWarner Losh gflag++; 32616445670SWarner Losh break; 3274b844f8dSWarner Losh case 'H': 3284b844f8dSWarner Losh Hflag++; 3294b844f8dSWarner Losh break; 3304b844f8dSWarner Losh case 'l': 3314b844f8dSWarner Losh lflag++; 3324b844f8dSWarner Losh break; 3334b844f8dSWarner Losh case 'L': 3344b844f8dSWarner Losh Lflag++; 3354b844f8dSWarner Losh break; 3364b844f8dSWarner Losh case 'n': 3374b844f8dSWarner Losh varname = optarg; 3384b844f8dSWarner Losh break; 3394b844f8dSWarner Losh case 'N': 3404b844f8dSWarner Losh Nflag++; 3414b844f8dSWarner Losh break; 3425709a4b5SWarner Losh case 'O': 3435709a4b5SWarner Losh load_opt_flag++; 3445709a4b5SWarner Losh break; 3454b844f8dSWarner Losh case 'p': 3464b844f8dSWarner Losh pflag++; 3474b844f8dSWarner Losh break; 348*3c0dcbfcSWarner Losh case 'q': 349*3c0dcbfcSWarner Losh quiet = true; 350*3c0dcbfcSWarner Losh break; 3514b844f8dSWarner Losh case 'R': 3524b844f8dSWarner Losh Rflag++; 3534b844f8dSWarner Losh break; 35455ff82c0SWarner Losh case 't': 35555ff82c0SWarner Losh attrib = strtoul(optarg, NULL, 16); 35655ff82c0SWarner Losh break; 357b0da7c79SWarner Losh case 'u': 358b0da7c79SWarner Losh uflag++; 359b0da7c79SWarner Losh break; 3604b844f8dSWarner Losh case 'w': 3614b844f8dSWarner Losh wflag++; 3624b844f8dSWarner Losh break; 3634b844f8dSWarner Losh case 'f': 364e08bb109SWarner Losh free(fromfile); 365e08bb109SWarner Losh fromfile = strdup(optarg); 366e08bb109SWarner Losh break; 3674b844f8dSWarner Losh case 0: 368*3c0dcbfcSWarner Losh rep_errx(1, "unknown or unimplemented option\n"); 3694b844f8dSWarner Losh break; 3704b844f8dSWarner Losh default: 3714b844f8dSWarner Losh usage(); 3724b844f8dSWarner Losh } 3734b844f8dSWarner Losh } 3744b844f8dSWarner Losh argc -= optind; 3754b844f8dSWarner Losh argv += optind; 3764b844f8dSWarner Losh 3774b844f8dSWarner Losh if (argc == 1) 3784b844f8dSWarner Losh varname = argv[0]; 3794b844f8dSWarner Losh 3804b844f8dSWarner Losh if (aflag + Dflag + wflag > 1) { 3814b844f8dSWarner Losh warnx("Can only use one of -a (--append), " 3824b844f8dSWarner Losh "-D (--delete) and -w (--write)"); 3834b844f8dSWarner Losh usage(); 3844b844f8dSWarner Losh } 3854b844f8dSWarner Losh 3864b844f8dSWarner Losh if (aflag + Dflag + wflag > 0 && varname == NULL) { 3874b844f8dSWarner Losh warnx("Must specify a variable for -a (--append), " 3884b844f8dSWarner Losh "-D (--delete) or -w (--write)"); 3894b844f8dSWarner Losh usage(); 3904b844f8dSWarner Losh } 3914b844f8dSWarner Losh 3924b844f8dSWarner Losh if (aflag) 3934b844f8dSWarner Losh append_variable(varname, NULL); 3944b844f8dSWarner Losh else if (Dflag) 3954b844f8dSWarner Losh delete_variable(varname); 3964b844f8dSWarner Losh else if (wflag) 3974b844f8dSWarner Losh write_variable(varname, NULL); 3984a110fbfSWarner Losh else if (Lflag) 3994a110fbfSWarner Losh print_known_guid(); 400e08bb109SWarner Losh else if (fromfile) { 401e08bb109SWarner Losh Nflag = 1; 402e08bb109SWarner Losh print_var(NULL, NULL); 403e08bb109SWarner Losh } else if (varname) { 4044b844f8dSWarner Losh pflag++; 4054b844f8dSWarner Losh print_variable(varname); 4064b844f8dSWarner Losh } else if (argc > 0) { 4074b844f8dSWarner Losh pflag++; 4084b844f8dSWarner Losh for (i = 0; i < argc; i++) 4094b844f8dSWarner Losh print_variable(argv[i]); 4104b844f8dSWarner Losh } else 4114b844f8dSWarner Losh print_variables(); 4124b844f8dSWarner Losh } 4134b844f8dSWarner Losh 4144b844f8dSWarner Losh int 4154b844f8dSWarner Losh main(int argc, char **argv) 4164b844f8dSWarner Losh { 4174b844f8dSWarner Losh 4184b844f8dSWarner Losh parse_args(argc, argv); 4194b844f8dSWarner Losh } 420