Home | History | Annotate | Line # | Download | only in efi
      1  1.5  riastrad /* $NetBSD: showvar.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $ */
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Redistribution and use in source and binary forms, with or without
      5  1.1  christos  * modification, are permitted provided that the following conditions
      6  1.1  christos  * are met:
      7  1.1  christos  * 1. Redistributions of source code must retain the above copyright
      8  1.1  christos  *    notice, this list of conditions and the following disclaimer.
      9  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     10  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     11  1.1  christos  *    documentation and/or other materials provided with the distribution.
     12  1.1  christos  *
     13  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     14  1.1  christos  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  1.1  christos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  1.1  christos  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     17  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     18  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     19  1.1  christos  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     20  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     21  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     22  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     23  1.1  christos  * SUCH DAMAGE.
     24  1.1  christos  */
     25  1.1  christos 
     26  1.1  christos #include <sys/cdefs.h>
     27  1.1  christos #ifndef lint
     28  1.5  riastrad __RCSID("$NetBSD: showvar.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $");
     29  1.1  christos #endif /* not lint */
     30  1.1  christos 
     31  1.1  christos #include <sys/efiio.h>
     32  1.1  christos #include <sys/ioctl.h>
     33  1.1  christos #include <sys/uuid.h>
     34  1.1  christos 
     35  1.1  christos #include <assert.h>
     36  1.1  christos #include <ctype.h>
     37  1.1  christos #include <err.h>
     38  1.1  christos #include <errno.h>
     39  1.1  christos #include <fcntl.h>
     40  1.1  christos #include <getopt.h>
     41  1.1  christos #include <limits.h>
     42  1.1  christos #include <regex.h>
     43  1.1  christos #include <stdarg.h>
     44  1.1  christos #include <stdbool.h>
     45  1.1  christos #include <stddef.h>
     46  1.1  christos #include <stdio.h>
     47  1.1  christos #include <stdlib.h>
     48  1.1  christos #include <string.h>
     49  1.1  christos #include <unistd.h>
     50  1.1  christos #include <util.h>
     51  1.1  christos 
     52  1.1  christos #include "efiio.h"
     53  1.1  christos #include "defs.h"
     54  1.1  christos #include "bootvar.h"
     55  1.1  christos #include "certs.h"
     56  1.1  christos #include "devpath.h"
     57  1.1  christos #include "getvars.h"
     58  1.1  christos #include "showvar.h"
     59  1.1  christos #include "utils.h"
     60  1.1  christos 
     61  1.1  christos #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI		   __BIT(0)
     62  1.1  christos #define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION 	   __BIT(1)
     63  1.1  christos #define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED __BIT(2)
     64  1.1  christos #define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED 	   __BIT(3)
     65  1.1  christos #define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED	   __BIT(4)
     66  1.1  christos #define EFI_OS_INDICATIONS_START_OS_RECOVERY		   __BIT(5)
     67  1.1  christos #define EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY	   __BIT(6)
     68  1.1  christos #define EFI_OS_INDICATIONS_JSON_CONFIG_DATA_REFRESH	   __BIT(7)
     69  1.1  christos #define OS_INDICATIONS_BITS		\
     70  1.1  christos 	"\177\020"			\
     71  1.1  christos 	"b\x0""BootFWui\0"		\
     72  1.1  christos 	"b\x1""TimeStamp\0"		\
     73  1.1  christos 	"b\x2""FileCap\0"		\
     74  1.1  christos 	"b\x3""FMPCap\0"		\
     75  1.1  christos 	"b\x4""CapResVar\0"		\
     76  1.1  christos 	"b\x5""StartOsRecovery\0"	\
     77  1.1  christos 	"b\x6""StartPltformRec\0"	\
     78  1.1  christos 	"b\x7""JSONConfig\0"		\
     79  1.1  christos 
     80  1.1  christos //********************************************************
     81  1.1  christos // Boot Option Attributes
     82  1.1  christos //********************************************************
     83  1.1  christos #define EFI_BOOT_OPTION_SUPPORT_KEY	__BIT(0)	// 0x00000001
     84  1.1  christos #define EFI_BOOT_OPTION_SUPPORT_APP	__BIT(1)	// 0x00000002
     85  1.1  christos #define EFI_BOOT_OPTION_SUPPORT_SYSPREP	__BIT(4)	// 0x00000010
     86  1.1  christos #define EFI_BOOT_OPTION_SUPPORT_COUNT	__BITS(8,9)	// 0x00000300
     87  1.1  christos // All values 0x00000200-0x00001F00 are reserved
     88  1.1  christos #define BOOT_OPTION_SUPPORT_BITS \
     89  1.1  christos 	"\177\020"		\
     90  1.1  christos 	"b\x0""Key\0"		\
     91  1.1  christos 	"b\x1""App\0"		\
     92  1.1  christos 	"b\x4""SysPrep\0"	\
     93  1.1  christos 	"f\x8\x2""Count\0"
     94  1.1  christos 
     95  1.1  christos /************************************************************************/
     96  1.1  christos 
     97  1.1  christos static int
     98  1.1  christos show_filelist_data(efi_var_t *v, bool dbg)
     99  1.1  christos {
    100  1.1  christos 	char *dmsg, *path;
    101  1.1  christos 
    102  1.1  christos 	path = devpath_parse(v->ev.data, v->ev.datasize, dbg ? &dmsg : NULL);
    103  1.1  christos 	printf("%s: %s\n", v->name, path);
    104  1.1  christos 	free(path);
    105  1.1  christos 	if (dbg) {
    106  1.1  christos 		printf("%s", dmsg);
    107  1.1  christos 		free(dmsg);
    108  1.1  christos 	}
    109  1.1  christos 	return 0;
    110  1.1  christos }
    111  1.1  christos 
    112  1.1  christos static int
    113  1.2  christos show_asciiz_data(efi_var_t *v, bool dbg __unused)
    114  1.1  christos {
    115  1.1  christos 	char *cp, *ep;
    116  1.1  christos 
    117  1.1  christos 	printf("%s: ", v->name);
    118  1.1  christos 
    119  1.1  christos 	cp = v->ev.data;
    120  1.1  christos 	ep = cp + v->ev.datasize;
    121  1.1  christos 	for (/*EMPTY*/; cp < ep; cp += strlen(cp) + 1) {
    122  1.1  christos 		printf("%s\n", cp);
    123  1.1  christos 	}
    124  1.1  christos 	if (cp != ep)
    125  1.1  christos 		warnx("short asciiz data\n");
    126  1.1  christos 	return 0;
    127  1.1  christos }
    128  1.1  christos 
    129  1.1  christos static int
    130  1.2  christos show_array8_data(efi_var_t *v, bool dbg __unused)
    131  1.1  christos {
    132  1.1  christos 	size_t cnt, i;
    133  1.1  christos 	uint8_t *array = v->ev.data;
    134  1.1  christos 
    135  1.1  christos 	printf("%s: ", v->name);
    136  1.1  christos 
    137  1.1  christos 	cnt = v->ev.datasize / sizeof(array[0]);
    138  1.1  christos 	i = 0;
    139  1.1  christos 	for (;;) {
    140  1.1  christos 		printf("%02x", array[i]);
    141  1.1  christos 		if (++i == cnt) {
    142  1.1  christos 			printf("\n");
    143  1.1  christos 			break;
    144  1.1  christos 		}
    145  1.1  christos 		printf(",");
    146  1.1  christos 	}
    147  1.1  christos 	return 0;
    148  1.1  christos }
    149  1.1  christos 
    150  1.1  christos static int
    151  1.2  christos show_array16_data(efi_var_t *v, bool dbg __unused)
    152  1.1  christos {
    153  1.1  christos 	size_t cnt, i;
    154  1.1  christos 	uint16_t *array = v->ev.data;
    155  1.1  christos 
    156  1.1  christos 	printf("%s: ", v->name);
    157  1.1  christos 
    158  1.1  christos 	cnt = v->ev.datasize / sizeof(array[0]);
    159  1.1  christos 	i = 0;
    160  1.1  christos 	for (;;) {
    161  1.1  christos 		printf("%04X", array[i]);
    162  1.1  christos 		if (++i == cnt) {
    163  1.1  christos 			printf("\n");
    164  1.1  christos 			break;
    165  1.1  christos 		}
    166  1.1  christos 		printf(",");
    167  1.1  christos 	}
    168  1.1  christos 	return 0;
    169  1.1  christos }
    170  1.1  christos 
    171  1.1  christos static int
    172  1.1  christos show_uuid_array_data(efi_var_t *v, bool dbg)
    173  1.1  christos {
    174  1.1  christos 	size_t cnt, i;
    175  1.1  christos 	uuid_t *array = v->ev.data;
    176  1.1  christos 	const char *name;
    177  1.1  christos 
    178  1.1  christos 	printf("%s: ", v->name);
    179  1.1  christos 
    180  1.1  christos 	cnt = v->ev.datasize / sizeof(array[0]);
    181  1.1  christos 
    182  1.1  christos 	for (i = 0; i < cnt; i++) {
    183  1.1  christos 		name = get_cert_name(&array[i]);
    184  1.1  christos 		printf("%s%c", name, i + 1 < cnt ? ' ' : '\n');
    185  1.1  christos 	}
    186  1.1  christos 
    187  1.1  christos 	if (dbg) {
    188  1.1  christos 		for (i = 0; i < cnt; i++) {
    189  1.1  christos 			printf("  ");
    190  1.1  christos 			uuid_printf(&array[i]);
    191  1.1  christos 			name = get_cert_name(&array[i]);
    192  1.1  christos 			printf("  %s\n", name ? name : "unknown");
    193  1.1  christos 		}
    194  1.1  christos 	}
    195  1.1  christos 	return 0;
    196  1.1  christos }
    197  1.1  christos 
    198  1.1  christos /************************************************************************/
    199  1.1  christos 
    200  1.1  christos static int
    201  1.1  christos show_key_data(efi_var_t *v, bool dbg)
    202  1.1  christos {
    203  1.1  christos 	typedef union {
    204  1.1  christos 		struct {
    205  1.1  christos 			uint32_t	Revision	: 8;
    206  1.1  christos 			uint32_t	ShiftPressed	: 1;
    207  1.1  christos 			uint32_t	ControlPressed	: 1;
    208  1.1  christos 			uint32_t	AltPressed	: 1;
    209  1.1  christos 			uint32_t	LogoPressed	: 1;
    210  1.1  christos 			uint32_t	MenuPressed	: 1;
    211  1.1  christos 			uint32_t	SysReqPressed	: 1;
    212  1.1  christos 			uint32_t	Reserved	: 16;
    213  1.1  christos 			uint32_t	InputKeyCount	: 2;
    214  1.1  christos #define BOOT_KEY_OPTION_BITS \
    215  1.1  christos 	"\177\020"		\
    216  1.1  christos 	"f\x00\x08""Rev\0"	\
    217  1.1  christos 	"b\x08""SHFT\0"		\
    218  1.1  christos 	"b\x09""CTRL\0"		\
    219  1.1  christos 	"b\x0a""ALT\0"		\
    220  1.1  christos 	"b\x0b""LOGO\0"		\
    221  1.1  christos 	"b\x0c""MENU\0"		\
    222  1.1  christos 	"b\x0d""SysReq\0"	\
    223  1.1  christos      /* "f\x0e\x10""Rsvd\0" */	\
    224  1.1  christos 	"f\x1e\x02""KeyCnt\0"
    225  1.1  christos 		} Options;
    226  1.1  christos 		uint32_t		PackedValue;
    227  1.1  christos 	} __packed EFI_BOOT_KEY_DATA;
    228  1.1  christos 	typedef struct {
    229  1.1  christos 		uint16_t		ScanCode;
    230  1.1  christos 		uint16_t		UnicodeChar;
    231  1.1  christos 	} __packed EFI_INPUT_KEY;
    232  1.1  christos 	typedef struct _EFI_KEY_OPTION {
    233  1.1  christos 		EFI_BOOT_KEY_DATA	KeyData;
    234  1.1  christos 		uint32_t		BootOptionCrc;
    235  1.1  christos 		uint16_t		BootOption;
    236  1.1  christos 		EFI_INPUT_KEY		Keys[3];
    237  1.1  christos 		uint16_t		DescLocation; /* XXX: a guess!  Not documented */
    238  1.1  christos 		uint8_t			UndocData[];
    239  1.1  christos 	} __packed EFI_KEY_OPTION;
    240  1.1  christos 	union {
    241  1.1  christos 		EFI_KEY_OPTION *ko;
    242  1.1  christos 		uint8_t        *bp;
    243  1.1  christos 	} u = { .bp = v->ev.data, };
    244  1.1  christos 	char buf[256], c, *cp, *desc;
    245  1.5  riastrad 	uint i;
    246  1.1  christos 
    247  1.1  christos 	printf("%s:", v->name);
    248  1.1  christos 
    249  1.1  christos 	/*
    250  1.1  christos 	 * Note: DescLocation is not documented in the UEFI spec, so
    251  1.1  christos 	 * do some sanity checking before using it.
    252  1.1  christos 	 */
    253  1.1  christos 	desc = NULL;
    254  1.1  christos 	if (offsetof(EFI_KEY_OPTION, UndocData) < v->ev.datasize &&
    255  1.1  christos 	    u.ko->DescLocation + sizeof(uint16_t) < v->ev.datasize) {
    256  1.1  christos 		size_t sz = v->ev.datasize - u.ko->DescLocation;
    257  1.1  christos 		desc = ucs2_to_utf8((uint16_t *)&u.bp[u.ko->DescLocation],
    258  1.1  christos 		    sz, NULL, NULL);
    259  1.1  christos 		printf(" %s", desc);
    260  1.1  christos 	}
    261  1.1  christos 
    262  1.1  christos 	/*
    263  1.1  christos 	 * Parse the KeyData
    264  1.1  christos 	 */
    265  1.1  christos 	snprintb(buf, sizeof(buf), BOOT_KEY_OPTION_BITS,
    266  1.1  christos 	    u.ko->KeyData.PackedValue);
    267  1.1  christos 
    268  1.1  christos 	/*
    269  1.1  christos 	 * Skip over the raw value
    270  1.1  christos 	 */
    271  1.1  christos 	c = '\0';
    272  1.1  christos 	if ((cp = strchr(buf, ',')) || (cp = strchr(buf, '<'))) {
    273  1.1  christos 		c = *cp;
    274  1.1  christos 		*cp = '<';
    275  1.1  christos 	}
    276  1.1  christos 	else
    277  1.1  christos 		cp = buf;
    278  1.1  christos 
    279  1.1  christos 	printf("\tBoot%04X \t%s", u.ko->BootOption, cp);
    280  1.1  christos 
    281  1.1  christos 	if (c != '\0')
    282  1.1  christos 		*cp = c;	/* restore the buffer */
    283  1.4  riastrad 
    284  1.5  riastrad 	for (i = 0; i < u.ko->KeyData.Options.InputKeyCount; i++)
    285  1.1  christos 		printf(" {%04x, %04x}", u.ko->Keys[i].ScanCode,
    286  1.1  christos 		    u.ko->Keys[i].UnicodeChar);
    287  1.1  christos 	printf("\n");
    288  1.1  christos 
    289  1.1  christos 	if (dbg) {
    290  1.1  christos 		printf("  KeyData: %s\n", buf);
    291  1.1  christos 		printf("  BootOptionCrc: 0x%08x\n", u.ko->BootOptionCrc);
    292  1.1  christos 		printf("  BootOption:    Boot%04X\n", u.ko->BootOption);
    293  1.5  riastrad 		for (i = 0; i < u.ko->KeyData.Options.InputKeyCount; i++) {
    294  1.1  christos 			printf("  Keys[%u].ScanCode:    0x%04x\n", i,
    295  1.4  riastrad 			    u.ko->Keys[i].ScanCode);
    296  1.1  christos 			printf("  Keys[%u].UnicodeChar: 0x%04x\n", i,
    297  1.4  riastrad 			    u.ko->Keys[i].UnicodeChar);
    298  1.1  christos 		}
    299  1.1  christos 		if (desc)
    300  1.1  christos 			printf("  Desc: %s\n", desc);
    301  1.1  christos 	}
    302  1.1  christos 	free(desc);
    303  1.1  christos 	return 0;
    304  1.1  christos }
    305  1.1  christos 
    306  1.1  christos /************************************************************************/
    307  1.1  christos 
    308  1.1  christos static char *
    309  1.1  christos format_optional_data(char *od, size_t sz)
    310  1.1  christos {
    311  1.1  christos 	char *bp;
    312  1.1  christos 	size_t i;
    313  1.1  christos 
    314  1.1  christos 	bp = emalloc(sz + 1);
    315  1.1  christos 
    316  1.1  christos 	for (i = 0; i < sz; i++) {
    317  1.1  christos 		char c = od[i];
    318  1.2  christos 		bp[i] = isprint((unsigned char)c) ? c : '.';
    319  1.1  christos 	}
    320  1.1  christos 	bp[i] = '\0';
    321  1.1  christos 	return bp;
    322  1.1  christos }
    323  1.1  christos 
    324  1.1  christos static int
    325  1.3  christos show_boot_data(efi_var_t *v, uint debug, uint max_namelen)
    326  1.1  christos {
    327  1.1  christos 	struct {
    328  1.1  christos 		char *name;
    329  1.1  christos 		uint32_t Attributes;
    330  1.1  christos 		char *Description;
    331  1.1  christos 		devpath_t *devpath;
    332  1.1  christos 		char *OptionalData;
    333  1.1  christos 		size_t OptionalDataSize;
    334  1.1  christos 	} info;
    335  1.1  christos 	union {
    336  1.1  christos 		char *cp;
    337  1.1  christos 		boot_var_t *bb;
    338  1.1  christos 	} u = { .cp = v->ev.data, };
    339  1.1  christos 	char *args, *dmsg, *path;
    340  1.1  christos 	size_t sz;
    341  1.1  christos 	bool dbg = debug & DEBUG_STRUCT_BIT;
    342  1.1  christos 	bool verbose = debug & (DEBUG_MASK | DEBUG_VERBOSE_BIT);
    343  1.1  christos 
    344  1.1  christos 	memset(&info, 0, sizeof(info));
    345  1.1  christos 	info.name = v->name;
    346  1.1  christos 	info.Attributes = u.bb->Attributes;
    347  1.1  christos 	sz = (v->ev.datasize - sizeof(*u.bb)) / sizeof(uint16_t);
    348  1.1  christos 	sz = (ucs2nlen(u.bb->Description, sz) + 1) * sizeof(uint16_t);
    349  1.1  christos 	info.Description = ucs2_to_utf8(u.bb->Description, sz, NULL, NULL);
    350  1.1  christos 	info.devpath = (devpath_t *)((uint8_t *)u.bb->Description + sz);
    351  1.1  christos 	info.OptionalData = (char *)info.devpath + u.bb->FilePathListLength;
    352  1.1  christos 
    353  1.1  christos 	char *ep = u.cp + v->ev.datasize;
    354  1.1  christos 
    355  1.1  christos 	assert(info.OptionalData <= u.cp + v->ev.datasize);
    356  1.1  christos 
    357  1.1  christos 	if (info.OptionalData <= u.cp + v->ev.datasize) {
    358  1.1  christos 		info.OptionalDataSize = (size_t)(ep - info.OptionalData);
    359  1.1  christos 	}
    360  1.1  christos 	else {
    361  1.1  christos 		printf("ARG!!! "
    362  1.1  christos 		    "FilePahList[] extends past end of data by %zd bytes\n",
    363  1.1  christos 		    info.OptionalData - ep);
    364  1.1  christos 		info.OptionalDataSize = 0;
    365  1.1  christos 	}
    366  1.1  christos 	printf("%s%c %-*s", v->name,
    367  1.1  christos 	    IS_ACTIVE(info.Attributes) ? '*' : ' ',
    368  1.1  christos 	    max_namelen, info.Description);
    369  1.1  christos 
    370  1.1  christos 	dmsg = NULL;
    371  1.1  christos 	if (verbose) {
    372  1.1  christos 		path = devpath_parse(info.devpath, u.bb->FilePathListLength,
    373  1.1  christos 		    dbg ? &dmsg : NULL);
    374  1.1  christos 
    375  1.1  christos 		args = format_optional_data(info.OptionalData,
    376  1.1  christos 		    info.OptionalDataSize);
    377  1.4  riastrad 
    378  1.1  christos 		printf("\t%s%s", path, args);/* XXX: make this conditional on verbose? */
    379  1.1  christos 		free(args);
    380  1.1  christos 		free(path);
    381  1.1  christos 	}
    382  1.1  christos 
    383  1.1  christos 	printf("\n");
    384  1.1  christos 
    385  1.1  christos 	if (dbg) {
    386  1.1  christos 		char attr_str[256];
    387  1.4  riastrad 
    388  1.1  christos 		snprintb(attr_str, sizeof(attr_str),
    389  1.1  christos 		    LOAD_OPTION_BITS, info.Attributes);
    390  1.1  christos 		printf("  Attr: %s\n", attr_str);
    391  1.1  christos 		printf("  Description: %s\n", info.Description);
    392  1.1  christos 		assert(dmsg != NULL);
    393  1.1  christos 		printf("%s", dmsg);
    394  1.1  christos 		if (info.OptionalDataSize > 0) {
    395  1.1  christos 			show_data((void *)info.OptionalData,
    396  1.1  christos 			    info.OptionalDataSize, "  ExtraData: ");
    397  1.1  christos 		}
    398  1.1  christos 		free(dmsg);
    399  1.1  christos 	}
    400  1.1  christos 
    401  1.1  christos 	free(info.Description);
    402  1.1  christos 	return 0;
    403  1.4  riastrad }
    404  1.1  christos 
    405  1.1  christos /************************************************************************/
    406  1.1  christos 
    407  1.1  christos static int
    408  1.2  christos show_OsIndications_data(efi_var_t *e, bool dbg __unused)
    409  1.1  christos {
    410  1.1  christos 	uint64_t OsIndications;
    411  1.1  christos 	char buf[256];
    412  1.1  christos 
    413  1.1  christos 	assert(e->ev.datasize == 8);
    414  1.1  christos 	OsIndications = *(uint64_t *)e->ev.data;
    415  1.1  christos 	snprintb(buf, sizeof(buf), OS_INDICATIONS_BITS, OsIndications);
    416  1.1  christos 	printf("%s:\t%s\n", e->name, buf);
    417  1.1  christos 	return 0;
    418  1.1  christos }
    419  1.1  christos 
    420  1.1  christos static int
    421  1.2  christos show_BootOptionSupport_data(efi_var_t *e, bool dbg __unused)
    422  1.1  christos {
    423  1.1  christos 	uint32_t boot_option_support;
    424  1.1  christos 	char buf[256];
    425  1.1  christos 
    426  1.1  christos 	assert(e->ev.datasize == 4);
    427  1.1  christos 	boot_option_support = *(uint32_t *)e->ev.data;
    428  1.1  christos 	snprintb(buf, sizeof(buf), BOOT_OPTION_SUPPORT_BITS,
    429  1.1  christos 	    boot_option_support);
    430  1.1  christos 	printf("%s:\t%s\n", e->name, buf);
    431  1.1  christos 	return 0;
    432  1.1  christos }
    433  1.1  christos 
    434  1.1  christos static int
    435  1.2  christos show_Timeout_data(efi_var_t *e, bool dbg __unused)
    436  1.1  christos {
    437  1.1  christos 	uint16_t *timeout = e->ev.data;
    438  1.1  christos 
    439  1.1  christos 	if (e->ev.datasize != 2)
    440  1.1  christos 		printf("bad timeout datasize: %zu\n", e->ev.datasize);
    441  1.1  christos 	else
    442  1.1  christos 		printf("Timeout: %u seconds\n", *timeout);
    443  1.1  christos 	return 0;
    444  1.1  christos }
    445  1.1  christos 
    446  1.1  christos PUBLIC int
    447  1.1  christos show_generic_data(efi_var_t *e, uint var_width)
    448  1.1  christos {
    449  1.1  christos 	char uuid_str[UUID_STR_LEN];
    450  1.1  christos 	char attr_str[256];
    451  1.1  christos 
    452  1.1  christos 	uuid_snprintf(uuid_str, sizeof(uuid_str), &e->ev.vendor);
    453  1.1  christos 	snprintb(attr_str, sizeof(attr_str), EFI_VAR_ATTR_BITS, e->ev.attrib);
    454  1.1  christos 	printf("%-*s  %s %5zu %s\n", var_width, e->name, uuid_str,
    455  1.1  christos 	    e->ev.datasize, attr_str);
    456  1.1  christos 
    457  1.1  christos 	return 0;
    458  1.1  christos }
    459  1.1  christos 
    460  1.1  christos /************************************************************************/
    461  1.1  christos 
    462  1.1  christos struct vartbl {
    463  1.1  christos 	const char *name;
    464  1.1  christos 	int (*fn)(efi_var_t *, bool);
    465  1.1  christos };
    466  1.1  christos 
    467  1.1  christos static int
    468  1.1  christos varcmpsortfn(const void *a, const void *b)
    469  1.1  christos {
    470  1.1  christos 	const struct vartbl *p = a;
    471  1.1  christos 	const struct vartbl *q = b;
    472  1.1  christos 
    473  1.1  christos 	return strcmp(p->name, q->name);
    474  1.1  christos }
    475  1.1  christos 
    476  1.1  christos static int
    477  1.1  christos varcmpsrchfn(const void *a, const void *b)
    478  1.1  christos {
    479  1.1  christos 	const struct vartbl *q = b;
    480  1.1  christos 
    481  1.1  christos 	return strcmp(a, q->name);
    482  1.1  christos }
    483  1.1  christos 
    484  1.1  christos PUBLIC int
    485  1.3  christos show_variable(efi_var_t *v, uint debug, uint max_namelen)
    486  1.1  christos {
    487  1.1  christos #define REGEXP_BOOTXXXX	"^((Key)|(Boot)|(lBoot)|(Driver)|(SysPrep)|(OsRecovery))[0-9,A-F]{4}$"
    488  1.1  christos 	static regex_t preg = { .re_magic = 0, };
    489  1.1  christos 	static struct vartbl *tp, tbl[] = {
    490  1.1  christos 		{ "AuditMode",			show_array8_data, },
    491  1.1  christos 		{ "BootCurrent",		show_array16_data, },
    492  1.1  christos 		{ "BootNext",			show_array16_data, },
    493  1.1  christos 		{ "BootOptionSupport",		show_BootOptionSupport_data, },
    494  1.1  christos 		{ "BootOrder",			show_array16_data, },
    495  1.1  christos 		{ "BootOrderDefault",		show_array16_data, },
    496  1.1  christos 		{ "db",				show_cert_data, },
    497  1.1  christos 		{ "dbDefault",			show_cert_data, },
    498  1.1  christos 		{ "dbr",			show_cert_data, },
    499  1.1  christos 		{ "dbrDefault",			show_cert_data, },
    500  1.1  christos 		{ "dbt",			show_cert_data, },
    501  1.1  christos 		{ "dbtDefault",			show_cert_data, },
    502  1.1  christos 		{ "dbx",			show_cert_data, },
    503  1.1  christos 		{ "dbxDefault",			show_cert_data, },
    504  1.1  christos 		{ "devdbDefault",		show_cert_data, },
    505  1.1  christos 		{ "ConIn",			show_filelist_data, },
    506  1.1  christos 		{ "ConInDev",			show_filelist_data, },
    507  1.1  christos 		{ "ConOut",			show_filelist_data, },
    508  1.1  christos 		{ "ConOutDev",			show_filelist_data, },
    509  1.1  christos 		{ "DriverOrder",		show_array16_data, },
    510  1.1  christos 		{ "ErrOut",			show_filelist_data, },
    511  1.1  christos 		{ "ErrOutDev",			show_filelist_data, },
    512  1.1  christos 		{ "KEK",			show_cert_data, },
    513  1.1  christos 		{ "KEKDefault",			show_cert_data, },
    514  1.1  christos 		{ "OsIndications",		show_OsIndications_data, },
    515  1.1  christos 		{ "OsIndicationsSupported",	show_OsIndications_data, },
    516  1.1  christos 		{ "PK",				show_cert_data, },
    517  1.1  christos 		{ "PKDefault",			show_cert_data, },
    518  1.1  christos 		{ "PlatformLang",		show_asciiz_data, },
    519  1.1  christos 		{ "PlatformLangCodes",		show_asciiz_data, },
    520  1.1  christos 		{ "ProtectedBootOptions",	show_array16_data, },
    521  1.1  christos 		{ "SecureBoot",			show_array8_data, },
    522  1.1  christos 		{ "SetupMode",			show_array8_data, },
    523  1.1  christos 		{ "SignatureSupport",		show_uuid_array_data, },
    524  1.1  christos 		{ "SysPrepOrder",		show_array16_data, },
    525  1.1  christos 		{ "Timeout",			show_Timeout_data, },
    526  1.1  christos 		{ "VendorKeys",			show_array8_data, },
    527  1.1  christos 	};
    528  1.1  christos 	bool dbg = debug & DEBUG_STRUCT_BIT;
    529  1.1  christos 	int rv;
    530  1.1  christos 
    531  1.1  christos 	if (preg.re_magic == 0) {
    532  1.1  christos 		const char *regexp = REGEXP_BOOTXXXX;
    533  1.1  christos 		if (regcomp(&preg, regexp, REG_EXTENDED) != 0)
    534  1.1  christos 			err(EXIT_FAILURE, "regcomp: %s", regexp);
    535  1.1  christos 
    536  1.1  christos 		qsort(tbl, __arraycount(tbl), sizeof(*tbl), varcmpsortfn);
    537  1.1  christos 	}
    538  1.1  christos 
    539  1.1  christos 	if (debug & DEBUG_EFI_IOC_BIT) {
    540  1.1  christos 		rv = show_generic_data(v, max_namelen);
    541  1.1  christos 		if (debug & DEBUG_VERBOSE_BIT)
    542  1.1  christos 			return rv;
    543  1.1  christos 	}
    544  1.1  christos 
    545  1.1  christos 	if (regexec(&preg, v->name, 0, NULL, 0) == 0) { /* matched */
    546  1.1  christos 		if (v->name[0] == 'K')
    547  1.1  christos 			rv = show_key_data(v, dbg);
    548  1.1  christos 		else
    549  1.1  christos 			rv = show_boot_data(v, debug, max_namelen);
    550  1.1  christos 	}
    551  1.1  christos 	else {
    552  1.1  christos 		tp = bsearch(v->name, tbl, __arraycount(tbl), sizeof(*tbl),
    553  1.1  christos 		    varcmpsrchfn);
    554  1.1  christos 
    555  1.1  christos 		if (tp != NULL)
    556  1.1  christos 			rv = tp->fn(v, dbg);
    557  1.1  christos 		else if(!(debug & DEBUG_EFI_IOC_BIT))
    558  1.1  christos 			rv = show_generic_data(v, max_namelen);
    559  1.1  christos 	}
    560  1.1  christos 	if (debug & DEBUG_DATA_BIT)
    561  1.1  christos 		show_data(v->ev.data, v->ev.datasize, "  ");
    562  1.1  christos 
    563  1.1  christos 	return rv;
    564  1.1  christos }
    565