Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/efivar/efivar.c
/*- | /*- | ||||
* Copyright (c) 2016 Netflix, Inc. | * Copyright (c) 2016-2021 Netflix, Inc. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
Show All 17 Lines | |||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <efivar.h> | #include <efivar.h> | ||||
#include <efivar-dp.h> | #include <efivar-dp.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <getopt.h> | #include <getopt.h> | ||||
#include <stdarg.h> | |||||
#include <stdbool.h> | |||||
#include <stddef.h> | #include <stddef.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "efiutil.h" | #include "efiutil.h" | ||||
#include "efichar.h" | #include "efichar.h" | ||||
Show All 11 Lines | static struct option longopts[] = { | ||||
{ "hex", no_argument, NULL, 'H' }, | { "hex", no_argument, NULL, 'H' }, | ||||
{ "list-guids", no_argument, NULL, 'L' }, | { "list-guids", no_argument, NULL, 'L' }, | ||||
{ "list", no_argument, NULL, 'l' }, | { "list", no_argument, NULL, 'l' }, | ||||
{ "load-option", no_argument, NULL, 'O' }, | { "load-option", no_argument, NULL, 'O' }, | ||||
{ "name", required_argument, NULL, 'n' }, | { "name", required_argument, NULL, 'n' }, | ||||
{ "no-name", no_argument, NULL, 'N' }, | { "no-name", no_argument, NULL, 'N' }, | ||||
{ "print", no_argument, NULL, 'p' }, | { "print", no_argument, NULL, 'p' }, | ||||
// { "print-decimal", no_argument, NULL, 'd' }, /* unimplemnted clash with linux version */ | // { "print-decimal", no_argument, NULL, 'd' }, /* unimplemnted clash with linux version */ | ||||
{ "quiet", no_argument, NULL, 'q' }, | |||||
{ "raw-guid", no_argument, NULL, 'R' }, | { "raw-guid", no_argument, NULL, 'R' }, | ||||
{ "utf8", no_argument, NULL, 'u' }, | { "utf8", no_argument, NULL, 'u' }, | ||||
{ "write", no_argument, NULL, 'w' }, | { "write", no_argument, NULL, 'w' }, | ||||
{ NULL, 0, NULL, 0 } | { NULL, 0, NULL, 0 } | ||||
}; | }; | ||||
static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, | static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, | ||||
lflag, Lflag, Rflag, wflag, pflag, uflag, load_opt_flag; | lflag, Lflag, Rflag, wflag, pflag, uflag, load_opt_flag; | ||||
static bool quiet; | |||||
static char *varname; | static char *varname; | ||||
static char *fromfile; | static char *fromfile; | ||||
static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; | static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
errx(1, "efivar [-abdDHlLNpRtuw] [-n name] [-f file] [--append] [--ascii]\n" | errx(1, "efivar [-abdDHlLNpqRtuw] [-n name] [-f file] [--append] [--ascii]\n" | ||||
markj: Presumably the short options should be updated as well? | |||||
"\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" | "\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" | ||||
"\t[--list-guids] [--list] [--load-option] [--name name] [--no-name]\n" | "\t[--list-guids] [--list] [--load-option] [--name name] [--no-name]\n" | ||||
"\t[--print] [--print-decimal] [--raw-guid] [--utf8] [--write]\n" | "\t[--print] [--print-decimal] [--raw-guid] [--utf8] [--write]\n" | ||||
"\t[--quiet]\n" | |||||
"\tname[=value]"); | "\tname[=value]"); | ||||
} | } | ||||
static void | static void | ||||
rep_err(int eval, const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
if (quiet) | |||||
exit(eval); | |||||
va_start(ap, fmt); | |||||
verr(eval, fmt, ap); | |||||
va_end(ap); | |||||
} | |||||
static void | |||||
rep_errx(int eval, const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
if (quiet) | |||||
exit(eval); | |||||
va_start(ap, fmt); | |||||
verrx(eval, fmt, ap); | |||||
va_end(ap); | |||||
} | |||||
static void | |||||
breakdown_name(char *name, efi_guid_t *guid, char **vname) | breakdown_name(char *name, efi_guid_t *guid, char **vname) | ||||
{ | { | ||||
char *cp; | char *cp; | ||||
cp = strrchr(name, '-'); | cp = strrchr(name, '-'); | ||||
if (cp == NULL) | if (cp == NULL) | ||||
errx(1, "Invalid name: %s", name); | rep_errx(1, "Invalid name: %s", name); | ||||
*vname = cp + 1; | *vname = cp + 1; | ||||
*cp = '\0'; | *cp = '\0'; | ||||
if (efi_name_to_guid(name, guid) < 0) | if (efi_name_to_guid(name, guid) < 0) | ||||
errx(1, "Invalid guid %s", name); | rep_errx(1, "Invalid guid %s", name); | ||||
} | } | ||||
static uint8_t * | static uint8_t * | ||||
get_value(char *val, size_t *datalen) | get_value(char *val, size_t *datalen) | ||||
{ | { | ||||
static char buffer[16*1024]; | static char buffer[16*1024]; | ||||
if (val != NULL) { | if (val != NULL) { | ||||
Show All 12 Lines | append_variable(char *name, char *val) | ||||
char *vname; | char *vname; | ||||
efi_guid_t guid; | efi_guid_t guid; | ||||
size_t datalen; | size_t datalen; | ||||
uint8_t *data; | uint8_t *data; | ||||
breakdown_name(name, &guid, &vname); | breakdown_name(name, &guid, &vname); | ||||
data = get_value(val, &datalen); | data = get_value(val, &datalen); | ||||
if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) | if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) | ||||
err(1, "efi_append_variable"); | rep_err(1, "efi_append_variable"); | ||||
} | } | ||||
static void | static void | ||||
delete_variable(char *name) | delete_variable(char *name) | ||||
{ | { | ||||
char *vname; | char *vname; | ||||
efi_guid_t guid; | efi_guid_t guid; | ||||
breakdown_name(name, &guid, &vname); | breakdown_name(name, &guid, &vname); | ||||
if (efi_del_variable(guid, vname) < 0) | if (efi_del_variable(guid, vname) < 0) | ||||
err(1, "efi_del_variable"); | rep_err(1, "efi_del_variable"); | ||||
} | } | ||||
static void | static void | ||||
write_variable(char *name, char *val) | write_variable(char *name, char *val) | ||||
{ | { | ||||
char *vname; | char *vname; | ||||
efi_guid_t guid; | efi_guid_t guid; | ||||
size_t datalen; | size_t datalen; | ||||
uint8_t *data; | uint8_t *data; | ||||
breakdown_name(name, &guid, &vname); | breakdown_name(name, &guid, &vname); | ||||
data = get_value(val, &datalen); | data = get_value(val, &datalen); | ||||
if (efi_set_variable(guid, vname, data, datalen, attrib) < 0) | if (efi_set_variable(guid, vname, data, datalen, attrib) < 0) | ||||
err(1, "efi_set_variable"); | rep_err(1, "efi_set_variable"); | ||||
} | } | ||||
static void | static void | ||||
devpath_dump(uint8_t *data, size_t datalen) | devpath_dump(uint8_t *data, size_t datalen) | ||||
{ | { | ||||
char buffer[1024]; | char buffer[1024]; | ||||
efidp_format_device_path(buffer, sizeof(buffer), | efidp_format_device_path(buffer, sizeof(buffer), | ||||
Show All 29 Lines | print_var(efi_guid_t *guid, char *name) | ||||
if (guid) | if (guid) | ||||
pretty_guid(guid, &gname); | pretty_guid(guid, &gname); | ||||
if (pflag || fromfile) { | if (pflag || fromfile) { | ||||
if (fromfile) { | if (fromfile) { | ||||
int fd; | int fd; | ||||
fd = open(fromfile, O_RDONLY); | fd = open(fromfile, O_RDONLY); | ||||
if (fd < 0) | if (fd < 0) | ||||
err(1, "open %s", fromfile); | rep_err(1, "open %s", fromfile); | ||||
data = malloc(64 * 1024); | data = malloc(64 * 1024); | ||||
if (data == NULL) | if (data == NULL) | ||||
err(1, "malloc"); | rep_err(1, "malloc"); | ||||
datalen = read(fd, data, 64 * 1024); | datalen = read(fd, data, 64 * 1024); | ||||
if (datalen <= 0) | if (datalen <= 0) | ||||
err(1, "read"); | rep_err(1, "read"); | ||||
close(fd); | close(fd); | ||||
} else { | } else { | ||||
rv = efi_get_variable(*guid, name, &data, &datalen, &att); | rv = efi_get_variable(*guid, name, &data, &datalen, &att); | ||||
if (rv < 0) | if (rv < 0) | ||||
err(1, "fetching %s-%s", gname, name); | rep_err(1, "fetching %s-%s", gname, name); | ||||
} | } | ||||
if (!Nflag) | if (!Nflag) | ||||
printf("%s-%s\n", gname, name); | printf("%s-%s\n", gname, name); | ||||
if (load_opt_flag) | if (load_opt_flag) | ||||
efi_print_load_option(data, datalen, Aflag, bflag, uflag); | efi_print_load_option(data, datalen, Aflag, bflag, uflag); | ||||
else if (Aflag) | else if (Aflag) | ||||
Show All 30 Lines | print_variables(void) | ||||
int rv; | int rv; | ||||
char *name = NULL; | char *name = NULL; | ||||
efi_guid_t *guid = NULL; | efi_guid_t *guid = NULL; | ||||
while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) | while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) | ||||
print_var(guid, name); | print_var(guid, name); | ||||
if (rv < 0) | if (rv < 0) | ||||
err(1, "Error listing names"); | rep_err(1, "Error listing names"); | ||||
} | } | ||||
static void | static void | ||||
print_known_guid(void) | print_known_guid(void) | ||||
{ | { | ||||
struct uuid_table *tbl; | struct uuid_table *tbl; | ||||
int i, n; | int i, n; | ||||
n = efi_known_guid(&tbl); | n = efi_known_guid(&tbl); | ||||
for (i = 0; i < n; i++) | for (i = 0; i < n; i++) | ||||
printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); | printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); | ||||
} | } | ||||
static void | static void | ||||
parse_args(int argc, char **argv) | parse_args(int argc, char **argv) | ||||
{ | { | ||||
int ch, i; | int ch, i; | ||||
while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:OpRt:uw", | while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:OpqRt:uw", | ||||
longopts, NULL)) != -1) { | longopts, NULL)) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
case 'a': | case 'a': | ||||
aflag++; | aflag++; | ||||
break; | break; | ||||
case 'A': | case 'A': | ||||
Aflag++; | Aflag++; | ||||
break; | break; | ||||
Show All 25 Lines | case 'N': | ||||
Nflag++; | Nflag++; | ||||
break; | break; | ||||
case 'O': | case 'O': | ||||
load_opt_flag++; | load_opt_flag++; | ||||
break; | break; | ||||
case 'p': | case 'p': | ||||
pflag++; | pflag++; | ||||
break; | break; | ||||
case 'q': | |||||
quiet = true; | |||||
break; | |||||
case 'R': | case 'R': | ||||
Rflag++; | Rflag++; | ||||
break; | break; | ||||
case 't': | case 't': | ||||
attrib = strtoul(optarg, NULL, 16); | attrib = strtoul(optarg, NULL, 16); | ||||
break; | break; | ||||
case 'u': | case 'u': | ||||
uflag++; | uflag++; | ||||
break; | break; | ||||
case 'w': | case 'w': | ||||
wflag++; | wflag++; | ||||
break; | break; | ||||
case 'f': | case 'f': | ||||
free(fromfile); | free(fromfile); | ||||
fromfile = strdup(optarg); | fromfile = strdup(optarg); | ||||
break; | break; | ||||
case 0: | case 0: | ||||
errx(1, "unknown or unimplemented option\n"); | rep_errx(1, "unknown or unimplemented option\n"); | ||||
break; | break; | ||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |
Presumably the short options should be updated as well?