/*
efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
- Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+ Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#define _GNU_SOURCE
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "disk.h"
#include "efibootmgr.h"
+
#ifndef EFIBOOTMGR_VERSION
#define EFIBOOTMGR_VERSION "unknown (fix Makefile!)"
#endif
sscanf(name, pattern, num);
}
-static int
-select_boot_var_names(const struct dirent *d)
+static void
+fill_bootvar_name(char *dest, size_t len, const char *name)
{
- int num, rc;
- rc = sscanf(d->d_name, "Boot0%03x-%*s", &num);
- return rc;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char text_uuid[40];
+ efi_guid_unparse(&guid, text_uuid);
+ snprintf(dest, len, "%s-%s", name, text_uuid);
}
-#if 0
-static int
-select_blk_var_names(const struct dirent *d)
+static void
+fill_var(efi_variable_t *var, const char *name)
{
- int num;
- return sscanf(d->d_name, "blk%x-%*s", &num);
-}
-#endif
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-static int
-read_boot_var_names(struct dirent ***namelist)
-{
- int n;
- n = scandir(PROC_DIR_EFI_VARS, namelist, select_boot_var_names, alphasort);
- if (n < 0) {
- perror("scandir " PROC_DIR_EFI_VARS);
- fprintf(stderr, "You must 'modprobe efivars' before running efibootmgr.\n");
- }
- return n;
+ efichar_from_char(var->VariableName, name, 1024);
+ memcpy(&var->VendorGuid, &guid, sizeof(guid));
+ var->Attributes = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS;
}
-#if 0
-static int
-read_blk_var_names(struct dirent ***namelist)
+static void
+free_vars(list_t *head)
{
- int n;
- n = scandir(PROC_DIR_EFI_VARS, namelist, select_blk_var_names, alphasort);
- if (n < 0)
- perror("scandir");
- return n;
-}
+ list_t *pos, *n;
+ var_entry_t *boot;
-static int
-dirent_list_length(struct dirent **namelist)
-{
- int i;
- if (!namelist) return 0;
- for (i=0; namelist[i]; i++);
- return i;
+ list_for_each_safe(pos, n, head) {
+ boot = list_entry(pos, var_entry_t, list);
+ list_del(&(boot->list));
+ free(boot);
+ }
}
-#endif
static void
read_vars(struct dirent **namelist,
boot->var_data.Data;
if (!efichar_char_strcmp(opts.label,
load_option->description)) {
- fprintf(stderr, "** Warning ** : Boot%04x has same label %s\n",
- boot->num,
+ fprintf(stderr, "** Warning ** : %.8s has same label %s\n",
+ boot->name->d_name,
opts.label);
}
}
{
var_entry_t *boot;
int free_number;
+ list_t *pos;
- if (opts.bootnum == -1) free_number = find_free_boot_var(boot_list);
- else free_number = opts.bootnum;
+ if (opts.bootnum == -1)
+ free_number = find_free_boot_var(boot_list);
+ else {
+ list_for_each(pos, boot_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ if (boot->num == opts.bootnum) {
+ fprintf(stderr, "** Warning ** : bootnum %04X "
+ "already exists\n", opts.bootnum);
+ return NULL;
+ }
+ }
+ free_number = opts.bootnum;
+ }
if (free_number == -1) return NULL;
free(boot);
return NULL;
}
- write_variable(&boot->var_data);
+ create_variable(&boot->var_data);
list_add_tail(&boot->list, boot_list);
return boot;
}
+
+
+static efi_status_t
+read_boot(efi_variable_t *var, const char *name)
+{
+ char name_guid[PATH_MAX];
+
+ memset(var, 0, sizeof(*var));
+ fill_bootvar_name(name_guid, sizeof(name_guid), name);
+ return read_variable(name_guid, var);
+}
+
static efi_status_t
read_boot_order(efi_variable_t *boot_order)
{
efi_status_t status;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
- char boot_order_name[80], text_uuid[40];
- efi_guid_unparse(&guid, text_uuid);
-
- memset(boot_order, 0, sizeof(*boot_order));
- sprintf(boot_order_name, "BootOrder-%s", text_uuid);
- status = read_variable(boot_order_name, boot_order);
+ status = read_boot(boot_order, "BootOrder");
if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
return status;
if (status == EFI_NOT_FOUND) {
- /* Create it */
- efichar_from_char(boot_order->VariableName, "BootOrder",
- 1024);
- memcpy(&boot_order->VendorGuid, &guid, sizeof(guid));
- boot_order->Attributes = EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS;
- return status;
+ fill_var(boot_order, "BootOrder");
}
return EFI_SUCCESS;
}
-
-
static efi_status_t
add_to_boot_order(uint16_t num)
{
/* Now new_data has what we need */
memcpy(&(boot_order.Data), new_data, new_data_size);
boot_order.DataSize = new_data_size;
- return write_variable(&boot_order);
+ return create_or_edit_variable(&boot_order);
}
uint64_t new_data_size;
uint16_t *new_data, *old_data;
int old_i,new_i;
+ char boot_order_name[PATH_MAX];
status = read_boot_order(&boot_order);
if (status != EFI_SUCCESS) return status;
-
/* If it's empty, yea! */
if (!boot_order.DataSize) return EFI_SUCCESS;
+ fill_bootvar_name(boot_order_name, sizeof(boot_order_name),
+ "BootOrder");
+
/* We've now got an array (in boot_order.Data) of the
boot order. Simply copy the array, skipping the
entry we're deleting.
memcpy(&(boot_order.Data), new_data, new_data_size);
boot_order.DataSize = new_data_size;
- return write_variable(&boot_order);
+ return edit_variable(&boot_order);
}
-static int
-read_boot_current()
+static efi_status_t
+delete_var(const char *name)
{
- efi_status_t status;
- efi_variable_t boot_next;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
- char boot_next_name[80], text_uuid[40];
- uint16_t *n = (uint16_t *)(boot_next.Data);
-
- efi_guid_unparse(&guid, text_uuid);
-
- memset(&boot_next, 0, sizeof(boot_next));
- sprintf(boot_next_name, "BootCurrent-%s", text_uuid);
-
- status = read_variable(boot_next_name, &boot_next);
- if (status) return -1;
+ efi_variable_t var;
- return *n;
+ memset(&var, 0, sizeof(var));
+ fill_var(&var, name);
+ return delete_variable(&var);
}
static int
-read_boot_next()
+read_boot_u16(const char *name)
{
efi_status_t status;
- efi_variable_t boot_next;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
- char boot_next_name[80], text_uuid[40];
- uint16_t *n = (uint16_t *)(boot_next.Data);
-
- efi_guid_unparse(&guid, text_uuid);
-
- memset(&boot_next, 0, sizeof(boot_next));
- sprintf(boot_next_name, "BootNext-%s", text_uuid);
+ efi_variable_t var;
+ uint16_t *n = (uint16_t *)(var.Data);
- status = read_variable(boot_next_name, &boot_next);
+ memset(&var, 0, sizeof(var));
+ status = read_boot(&var, name);
if (status) return -1;
-
return *n;
}
-
static efi_status_t
-set_boot_next(uint16_t num)
+set_boot_u16(const char *name, uint16_t num)
{
efi_variable_t var;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
uint16_t *n = (uint16_t *)var.Data;
memset(&var, 0, sizeof(var));
- efichar_from_char(var.VariableName, "BootNext",
- 1024);
- memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ fill_var(&var, name);
*n = num;
var.DataSize = sizeof(uint16_t);
- var.Attributes = EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS;
- return write_variable(&var);
-}
-
-static efi_status_t
-delete_boot_next()
-{
- efi_variable_t var;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-
- memset(&var, 0, sizeof(var));
-
- efichar_from_char(var.VariableName, "BootNext",
- 1024);
- memcpy(&var.VendorGuid, &guid, sizeof(guid));
- return write_variable(&var);
+ return create_or_edit_variable(&var);
}
-
static efi_status_t
delete_boot_var(uint16_t num)
{
efi_status_t status;
efi_variable_t var;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
- char name[80];
+ char name[16];
list_t *pos, *n;
var_entry_t *boot;
- sprintf(name, "Boot%04x", num);
+ snprintf(name, sizeof(name), "Boot%04X", num);
memset(&var, 0, sizeof(var));
-
- efichar_from_char(var.VariableName, name, 1024);
- memcpy(&var.VendorGuid, &guid, sizeof(guid));
- status = write_variable(&var);
+ fill_var(&var, name);
+ status = delete_variable(&var);
+
+ /* For backwards compatibility, try to delete abcdef entries as well */
+ if (status) {
+ snprintf(name, sizeof(name), "Boot%04x", num);
+ memset(&var, 0, sizeof(var));
+ fill_var(&var, name);
+ status = delete_variable(&var);
+ }
if (status) return status;
-
list_for_each_safe(pos, n, &boot_entry_list) {
boot = list_entry(pos, var_entry_t, list);
if (boot->num == num) {
list_t *pos;
var_entry_t *var;
int num=0, rc;
+ char *name;
+ int warn=0;
list_for_each(pos, list) {
var = list_entry(pos, var_entry_t, list);
rc = sscanf(var->name->d_name, pattern, &num);
- if (rc == 1) var->num = num;
+ if (rc == 1) {
+ var->num = num;
+ name = var->name->d_name; /* shorter name */
+ if ((isalpha(name[4]) && islower(name[4])) ||
+ (isalpha(name[5]) && islower(name[5])) ||
+ (isalpha(name[6]) && islower(name[6])) ||
+ (isalpha(name[7]) && islower(name[7]))) {
+ fprintf(stderr, "** Warning ** : %.8s is not "
+ "EFI 1.10 compliant (lowercase hex in name)\n", name);
+ warn++;
+ }
+ }
+ }
+ if (warn) {
+ fprintf(stderr, "** Warning ** : please recreate these using efibootmgr to remove this warning.\n");
}
}
int i;
printf("BootOrder: ");
for (i=0; i<length; i++) {
- printf("%04x", order[i]);
+ printf("%04X", order[i]);
if (i < (length-1))
printf(",");
}
static efi_status_t
set_boot_order()
{
- efi_variable_t var;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
- uint16_t *n = (uint16_t *)var.Data;
+ efi_variable_t boot_order;
+ uint16_t *n = (uint16_t *)boot_order.Data;
if (!opts.bootorder) return EFI_SUCCESS;
- memset(&var, 0, sizeof(var));
-
- efichar_from_char(var.VariableName, "BootOrder",
- 1024);
- memcpy(&var.VendorGuid, &guid, sizeof(guid));
- var.Attributes = EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS;
+ memset(&boot_order, 0, sizeof(boot_order));
+ fill_var(&boot_order, "BootOrder");
- var.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
- return write_variable(&var);
+ boot_order.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
+ return create_or_edit_variable(&boot_order);
}
static void
load_option->description, sizeof(description));
memset(text_path, 0, sizeof(text_path));
path = load_option_path(load_option);
- printf("Boot%04x", boot->num);
+ if (boot->name)
+ printf("%.8s", boot->name->d_name);
+ else
+ printf("Boot%04X", boot->num);
+
if (load_option->attributes & LOAD_OPTION_ACTIVE)
printf("* ");
else printf(" ");
else {
load_option->attributes
|= LOAD_OPTION_ACTIVE;
- return write_variable(&boot->var_data);
+ return edit_variable(&boot->var_data);
}
}
else if (opts.active == 0) {
else {
load_option->attributes
&= ~LOAD_OPTION_ACTIVE;
- return write_variable(&boot->var_data);
+ return edit_variable(&boot->var_data);
}
}
}
-static efi_status_t
-delete_boot_order()
-{
- efi_variable_t var;
- efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-
- memset(&var, 0, sizeof(var));
-
- efichar_from_char(var.VariableName, "BootOrder",
- 1024);
- memcpy(&var.VendorGuid, &guid, sizeof(guid));
- return write_variable(&var);
-}
-
static void
usage()
printf("\t-O | --delete-bootorder delete BootOrder\n");
printf("\t-p | --part part (defaults to 1) containing loader\n");
printf("\t-q | --quiet be quiet\n");
- printf("\t-t | --test filename don't write to NVRAM, write to filename.\n");
+ printf("\t | --test filename don't write to NVRAM, write to filename.\n");
+ printf("\t-t | --timeout seconds set boot manager timeout waiting for user input.\n");
+ printf("\t-T | --delete-timeout delete Timeout.\n");
printf("\t-u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)\n");
printf("\t-U | --acpi_uid XXXX set the ACPI UID (used with -i)\n");
printf("\t-v | --verbose print additional information\n");
printf("\t-V | --version return version and exit\n");
printf("\t-w | --write-signature write unique sig to MBR if needed\n");
+ printf("\t-@ | --append-binary-args file append extra args from file (use \"-\" for stdin)\n");
}
static void
opts.bootnum = -1; /* auto-detect */
opts.bootnext = -1; /* Don't set it */
opts.active = -1; /* Don't set it */
+ opts.timeout = -1; /* Don't set it */
opts.edd10_devicenum = 0x80;
opts.loader = "\\elilo.efi";
opts.label = "Linux";
{"create", no_argument, 0, 'c'},
{"disk", required_argument, 0, 'd'},
{"iface", required_argument, 0, 'i'},
- {"acpi_hid", required_argument, 0, 'H' },
+ {"acpi_hid", required_argument, 0, 'H'},
{"edd-device", required_argument, 0, 'E'},
{"edd30", required_argument, 0, 'e'},
{"gpt", no_argument, 0, 'g'},
{"delete-bootorder", no_argument, 0, 'O'},
{"part", required_argument, 0, 'p'},
{"quiet", no_argument, 0, 'q'},
- {"test", required_argument, 0, 't'},
+ {"test", required_argument, 0, 1},
+ {"timeout", required_argument, 0, 't'},
+ {"delete-timeout", no_argument, 0, 'T'},
{"unicode", no_argument, 0, 'u'},
{"UCS-2", no_argument, 0, 'u'},
- {"acpi_uid", required_argument, 0, 'U' },
+ {"acpi_uid", required_argument, 0, 'U'},
{"verbose", optional_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"write-signature", no_argument, 0, 'w'},
+ {"append-binary-args", required_argument, 0, '@'},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv,
- "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:uU:v::Vw",
+ "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw@:",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
+ case '@':
+ opts.extra_opts_file = optarg;
+ break;
case 'a':
opts.active = 1;
break;
opts.delete_boot = 1;
break;
case 'b':
- rc = sscanf(optarg, "%x", &num);
+ rc = sscanf(optarg, "%X", &num);
if (rc == 1) opts.bootnum = num;
break;
case 'c':
case 'q':
opts.quiet = 1;
break;
- case 't':
+ case 1:
opts.testfile = optarg;
break;
+ case 't':
+ rc = sscanf(optarg, "%u", &num);
+ if (rc == 1) {
+ opts.timeout = num;
+ opts.set_timeout = 1;
+ }
+ break;
+ case 'T':
+ opts.delete_timeout = 1;
+ break;
case 'u':
opts.unicode = 1;
break;
return 1;
}
+ if (!opts.testfile)
+ set_fs_kernel_calls();
+
if (!opts.testfile) {
num_boot_names = read_boot_var_names(&boot_names);
read_vars(boot_names, num_boot_names, &boot_entry_list);
- set_var_nums("Boot%04x-%*s", &boot_entry_list);
+ set_var_nums("Boot%04X-%*s", &boot_entry_list);
if (opts.delete_boot) {
if (opts.bootnum == -1)
if (!opts.testfile) {
if (opts.delete_bootorder) {
- delete_boot_order();
+ delete_var("BootOrder");
}
if (opts.bootorder) {
if (opts.delete_bootnext) {
- delete_boot_next();
+ delete_var("BootNext");
+ }
+
+ if (opts.delete_timeout) {
+ delete_var("Timeout");
}
if (opts.bootnext >= 0) {
- set_boot_next(opts.bootnext & 0xFFFF);
+ set_boot_u16("BootNext", opts.bootnext & 0xFFFF);
+ }
+
+ if (opts.set_timeout) {
+ set_boot_u16("Timeout", opts.timeout);
}
if (!opts.quiet) {
- num = read_boot_next();
+ num = read_boot_u16("BootNext");
if (num != -1 ) {
- printf("BootNext: %04x\n", num);
+ printf("BootNext: %04X\n", num);
+ }
+ num = read_boot_u16("BootCurrent");
+ if (num != -1) {
+ printf("BootCurrent: %04X\n", num);
}
- num = read_boot_current();
+ num = read_boot_u16("Timeout");
if (num != -1) {
- printf("BootCurrent: %04x\n", num);
+ printf("Timeout: %u seconds\n", num);
}
show_boot_order();
show_boot_vars();
}
}
free_dirents(boot_names, num_boot_names);
+ free_vars(&boot_entry_list);
return 0;
}