xref: /freebsd/usr.sbin/efivar/efiutil.c (revision 5709a4b5)
15709a4b5SWarner Losh /*-
25709a4b5SWarner Losh  * Copyright (c) 2017 Netflix, Inc.
35709a4b5SWarner Losh  * All rights reserved.
45709a4b5SWarner Losh  *
55709a4b5SWarner Losh  * Redistribution and use in source and binary forms, with or without
65709a4b5SWarner Losh  * modification, are permitted provided that the following conditions
75709a4b5SWarner Losh  * are met:
85709a4b5SWarner Losh  * 1. Redistributions of source code must retain the above copyright
95709a4b5SWarner Losh  *    notice, this list of conditions and the following disclaimer.
105709a4b5SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
115709a4b5SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
125709a4b5SWarner Losh  *    documentation and/or other materials provided with the distribution.
135709a4b5SWarner Losh  *
145709a4b5SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155709a4b5SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165709a4b5SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175709a4b5SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185709a4b5SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195709a4b5SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205709a4b5SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215709a4b5SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225709a4b5SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235709a4b5SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245709a4b5SWarner Losh  * SUCH DAMAGE.
255709a4b5SWarner Losh  */
265709a4b5SWarner Losh 
275709a4b5SWarner Losh #include <sys/cdefs.h>
285709a4b5SWarner Losh __FBSDID("$FreeBSD$");
295709a4b5SWarner Losh 
305709a4b5SWarner Losh #include <ctype.h>
315709a4b5SWarner Losh #include <efivar.h>
325709a4b5SWarner Losh #include <efivar-dp.h>
335709a4b5SWarner Losh #include <err.h>
345709a4b5SWarner Losh #include <errno.h>
355709a4b5SWarner Losh #include <getopt.h>
365709a4b5SWarner Losh #include <stddef.h>
375709a4b5SWarner Losh #include <stdio.h>
385709a4b5SWarner Losh #include <stdlib.h>
395709a4b5SWarner Losh #include <string.h>
405709a4b5SWarner Losh #include <unistd.h>
415709a4b5SWarner Losh #include "efiutil.h"
425709a4b5SWarner Losh #include "efichar.h"
435709a4b5SWarner Losh #include <efivar-dp.h>
445709a4b5SWarner Losh 
455709a4b5SWarner Losh /*
465709a4b5SWarner Losh  * Dump the data as ASCII data, which is a pretty
475709a4b5SWarner Losh  * printed form
485709a4b5SWarner Losh  */
495709a4b5SWarner Losh void
505709a4b5SWarner Losh asciidump(uint8_t *data, size_t datalen)
515709a4b5SWarner Losh {
525709a4b5SWarner Losh 	size_t i;
535709a4b5SWarner Losh 	int len;
545709a4b5SWarner Losh 
555709a4b5SWarner Losh 	len = 0;
565709a4b5SWarner Losh 	for (i = 0; i < datalen; i++) {
575709a4b5SWarner Losh 		if (isprint(data[i])) {
585709a4b5SWarner Losh 			len++;
595709a4b5SWarner Losh 			if (len > 80) {
605709a4b5SWarner Losh 				len = 0;
615709a4b5SWarner Losh 				printf("\n");
625709a4b5SWarner Losh 			}
635709a4b5SWarner Losh 			printf("%c", data[i]);
645709a4b5SWarner Losh 		} else {
655709a4b5SWarner Losh 			len +=3;
665709a4b5SWarner Losh 			if (len > 80) {
675709a4b5SWarner Losh 				len = 0;
685709a4b5SWarner Losh 				printf("\n");
695709a4b5SWarner Losh 			}
705709a4b5SWarner Losh 			printf("%%%02x", data[i]);
715709a4b5SWarner Losh 		}
725709a4b5SWarner Losh 	}
735709a4b5SWarner Losh 	printf("\n");
745709a4b5SWarner Losh }
755709a4b5SWarner Losh 
765709a4b5SWarner Losh void
775709a4b5SWarner Losh utf8dump(uint8_t *data, size_t datalen)
785709a4b5SWarner Losh {
795709a4b5SWarner Losh 	char *utf8 = NULL;
805709a4b5SWarner Losh 	efi_char *ucs2;
815709a4b5SWarner Losh 
825709a4b5SWarner Losh 	/*
835709a4b5SWarner Losh 	 * NUL terminate the string. Not all strings need it, but some
845709a4b5SWarner Losh 	 * do and an extra NUL won't change what's printed.
855709a4b5SWarner Losh 	 */
865709a4b5SWarner Losh 	ucs2 = malloc(datalen + sizeof(efi_char));
875709a4b5SWarner Losh 	memcpy(ucs2, data, datalen);
885709a4b5SWarner Losh 	ucs2[datalen / sizeof(efi_char)] = 0;
895709a4b5SWarner Losh 	ucs2_to_utf8(ucs2, &utf8);
905709a4b5SWarner Losh 	printf("%s\n", utf8);
915709a4b5SWarner Losh 	free(utf8);
925709a4b5SWarner Losh 	free(ucs2);
935709a4b5SWarner Losh }
945709a4b5SWarner Losh 
955709a4b5SWarner Losh void
965709a4b5SWarner Losh hexdump(uint8_t *data, size_t datalen)
975709a4b5SWarner Losh {
985709a4b5SWarner Losh 	size_t i;
995709a4b5SWarner Losh 
1005709a4b5SWarner Losh 	for (i = 0; i < datalen; i++) {
1015709a4b5SWarner Losh 		if (i % 16 == 0) {
1025709a4b5SWarner Losh 			if (i != 0)
1035709a4b5SWarner Losh 				printf("\n");
1045709a4b5SWarner Losh 			printf("%04x: ", (int)i);
1055709a4b5SWarner Losh 		}
1065709a4b5SWarner Losh 		printf("%02x ", data[i]);
1075709a4b5SWarner Losh 	}
1085709a4b5SWarner Losh 	printf("\n");
1095709a4b5SWarner Losh }
1105709a4b5SWarner Losh 
1115709a4b5SWarner Losh void
1125709a4b5SWarner Losh bindump(uint8_t *data, size_t datalen)
1135709a4b5SWarner Losh {
1145709a4b5SWarner Losh 	write(1, data, datalen);
1155709a4b5SWarner Losh }
1165709a4b5SWarner Losh 
1175709a4b5SWarner Losh #define LOAD_OPTION_ACTIVE 1
1185709a4b5SWarner Losh 
1195709a4b5SWarner Losh void
1205709a4b5SWarner Losh efi_print_load_option(uint8_t *data, size_t datalen, int Aflag, int bflag, int uflag)
1215709a4b5SWarner Losh {
1225709a4b5SWarner Losh 	uint8_t *ep = data + datalen;
1235709a4b5SWarner Losh 	uint8_t *walker = data;
1245709a4b5SWarner Losh 	uint32_t attr;
1255709a4b5SWarner Losh 	uint16_t fplen;
1265709a4b5SWarner Losh 	efi_char *descr;
1275709a4b5SWarner Losh 	efidp dp, edp;
1285709a4b5SWarner Losh 	char *str;
1295709a4b5SWarner Losh 	char buf[1024];
1305709a4b5SWarner Losh 	int len;
1315709a4b5SWarner Losh 	void *opt;
1325709a4b5SWarner Losh 	int optlen;
1335709a4b5SWarner Losh 
1345709a4b5SWarner Losh 	if (datalen < sizeof(attr) + sizeof(fplen) + sizeof(efi_char))
1355709a4b5SWarner Losh 		return;
1365709a4b5SWarner Losh 	// First 4 bytes are attribute flags
1375709a4b5SWarner Losh 	attr = le32dec(walker);
1385709a4b5SWarner Losh 	walker += sizeof(attr);
1395709a4b5SWarner Losh 	// Next two bytes are length of the file paths
1405709a4b5SWarner Losh 	fplen = le16dec(walker);
1415709a4b5SWarner Losh 	walker += sizeof(fplen);
1425709a4b5SWarner Losh 	// Next we have a 0 terminated UCS2 string that we know to be aligned
1435709a4b5SWarner Losh 	descr = (efi_char *)(intptr_t)(void *)walker;
1445709a4b5SWarner Losh 	len = ucs2len(descr); // XXX need to sanity check that len < (datalen - (ep - walker) / 2)
1455709a4b5SWarner Losh 	walker += (len + 1) * sizeof(efi_char);
1465709a4b5SWarner Losh 	if (walker > ep)
1475709a4b5SWarner Losh 		return;
1485709a4b5SWarner Losh 	// Now we have fplen bytes worth of file path stuff
1495709a4b5SWarner Losh 	dp = (efidp)walker;
1505709a4b5SWarner Losh 	walker += fplen;
1515709a4b5SWarner Losh 	if (walker > ep)
1525709a4b5SWarner Losh 		return;
1535709a4b5SWarner Losh 	edp = (efidp)walker;
1545709a4b5SWarner Losh 	// Everything left is the binary option args
1555709a4b5SWarner Losh 	opt = walker;
1565709a4b5SWarner Losh 	optlen = ep - walker;
1575709a4b5SWarner Losh 	// We got to here, everything is good
1585709a4b5SWarner Losh 	printf("%c ", attr & LOAD_OPTION_ACTIVE ? '*' : ' ');
1595709a4b5SWarner Losh 	ucs2_to_utf8(descr, &str);
1605709a4b5SWarner Losh 	printf("%s", str);
1615709a4b5SWarner Losh 	free(str);
1625709a4b5SWarner Losh 	while (dp < edp) {
1635709a4b5SWarner Losh 		efidp_format_device_path(buf, sizeof(buf), dp,
1645709a4b5SWarner Losh 		    (intptr_t)(void *)edp - (intptr_t)(void *)dp);
1655709a4b5SWarner Losh 		dp = (efidp)((char *)dp + efidp_size(dp));
1665709a4b5SWarner Losh 		printf(" %s\n", buf);
1675709a4b5SWarner Losh 	}
1685709a4b5SWarner Losh 	if (optlen == 0)
1695709a4b5SWarner Losh 		return;
1705709a4b5SWarner Losh 	printf("Options: ");
1715709a4b5SWarner Losh 	if (Aflag)
1725709a4b5SWarner Losh 		asciidump(opt, optlen);
1735709a4b5SWarner Losh 	else if (bflag)
1745709a4b5SWarner Losh 		bindump(opt, optlen);
1755709a4b5SWarner Losh 	else if (uflag)
1765709a4b5SWarner Losh 		utf8dump(opt, optlen);
1775709a4b5SWarner Losh 	else
1785709a4b5SWarner Losh 		hexdump(opt, optlen);
1795709a4b5SWarner Losh }
180