From 683831290c50f64d8964bef2a5d8d0092b32ca15 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 1 Aug 2014 08:23:34 -0400
Subject: [PATCH 19/22] Add the ability to clean up duplicates in BootOrder
This adds -D (--remove-dups), which iterates BootOrder and keeps only
the first of any number it finds. Duplicate entries can happen as a
result of an interaction between fallback.efi and some system firmware,
and this option provides an easy workaround to fix it.
Resolves: rhbz#1097396
Signed-off-by: Peter Jones <pjones@redhat.com>
---
src/efibootmgr/efibootmgr.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-
src/include/efibootmgr.h | 1 +
src/man/man8/efibootmgr.8 | 5 +++-
3 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c
index c8cb6fd..40be505 100644
--- a/src/efibootmgr/efibootmgr.c
+++ b/src/efibootmgr/efibootmgr.c
@@ -347,6 +347,57 @@ add_to_boot_order(uint16_t num)
}
static int
+remove_dupes_from_boot_order(void)
+{
+ efi_variable_t *boot_order = NULL;
+ uint64_t new_data_size;
+ uint16_t *new_data, *old_data;
+ unsigned int old_i,new_i;
+ int rc;
+
+ rc = read_boot_order(&boot_order);
+ if (rc < 0)
+ return rc;
+
+ old_data = (uint16_t *)(boot_order->data);
+ /* Start with the same size */
+ new_data_size = boot_order->data_size;
+ new_data = malloc(new_data_size);
+ if (!new_data)
+ return -1;
+
+ unsigned int old_max = boot_order->data_size / sizeof(*new_data);
+ for (old_i = 0, new_i = 0; old_i < old_max; old_i++) {
+ int copies = 0;
+ unsigned int j;
+ for (j = 0; j < new_i; j++) {
+ if (new_data[j] == old_data[old_i]) {
+ copies++;
+ break;
+ }
+ }
+ if (copies == 0) {
+ /* Copy this value */
+ new_data[new_i] = old_data[old_i];
+ new_i++;
+ }
+ }
+ /* Adjust the size if we didn't copy everything. */
+ new_data_size = sizeof(new_data[0]) * new_i;
+
+ /* Now new_data has what we need */
+ free(boot_order->data);
+ boot_order->data = (uint8_t *)new_data;
+ boot_order->data_size = new_data_size;
+ efi_del_variable(EFI_GLOBAL_GUID, "BootOrder");
+ rc = efi_set_variable(EFI_GLOBAL_GUID, "BootOrder", boot_order->data,
+ boot_order->data_size, boot_order->attributes);
+ free(boot_order->data);
+ free(boot_order);
+ return rc;
+}
+
+static int
remove_from_boot_order(uint16_t num)
{
efi_variable_t *boot_order = NULL;
@@ -835,6 +886,7 @@ usage()
printf("\t-b | --bootnum XXXX modify BootXXXX (hex)\n");
printf("\t-B | --delete-bootnum delete bootnum (hex)\n");
printf("\t-c | --create create new variable bootnum and add to bootorder\n");
+ printf("\t-D | --remove-dups remove duplicate values from BootOrder\n");
printf("\t-d | --disk disk (defaults to /dev/sda) containing loader\n");
printf("\t-e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess\n");
printf("\t-E | --device num EDD 1.0 device number (defaults to 0x80)\n");
@@ -894,6 +946,7 @@ parse_opts(int argc, char **argv)
{"bootnum", required_argument, 0, 'b'},
{"delete-bootnum", no_argument, 0, 'B'},
{"create", no_argument, 0, 'c'},
+ {"remove-dups", no_argument, 0, 'D'},
{"disk", required_argument, 0, 'd'},
{"iface", required_argument, 0, 'i'},
{"acpi_hid", required_argument, 0, 'H'},
@@ -923,7 +976,7 @@ parse_opts(int argc, char **argv)
};
c = getopt_long (argc, argv,
- "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw"
+ "AaBb:cDd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw"
"@:h",
long_options, &option_index);
if (c == -1)
@@ -955,6 +1008,9 @@ parse_opts(int argc, char **argv)
case 'c':
opts.create = 1;
break;
+ case 'D':
+ opts.deduplicate = 1;
+ break;
case 'd':
opts.disk = optarg;
break;
@@ -1163,6 +1219,9 @@ main(int argc, char **argv)
ret = set_boot_order(opts.keep_old_entries);
}
+ if (opts.deduplicate) {
+ ret = remove_dupes_from_boot_order();
+ }
if (opts.delete_bootnext) {
ret = efi_del_variable(EFI_GLOBAL_GUID, "BootNext");
diff --git a/src/include/efibootmgr.h b/src/include/efibootmgr.h
index 87c83bb..b978caf 100644
--- a/src/include/efibootmgr.h
+++ b/src/include/efibootmgr.h
@@ -40,6 +40,7 @@ typedef struct {
int bootnext;
int verbose;
int active;
+ int deduplicate;
int64_t acpi_hid;
int64_t acpi_uid;
unsigned int delete_boot:1;
diff --git a/src/man/man8/efibootmgr.8 b/src/man/man8/efibootmgr.8
index 61631df..5c0ea70 100644
--- a/src/man/man8/efibootmgr.8
+++ b/src/man/man8/efibootmgr.8
@@ -9,7 +9,7 @@
efibootmgr \- manipulate the EFI Boot Manager
.SH SYNOPSIS
-\fBefibootmgr\fR [ \fB-a\fR ] [ \fB-A\fR ] [ \fB-b \fIXXXX\fB\fR ] [ \fB-B \fIXXXX\fB\fR ] [ \fB-c\fR ] [ \fB-d \fIDISK\fB\fR ] [ \fB-e \fI1|3|-1\fB\fR ] [ \fB-E \fINUM\fB\fR ] [ \fB-g\fR ] [ \fB-H \fIXXXX\fB\fR ] [ \fB-i \fINAME\fB\fR ] [ \fB-l \fINAME\fB\fR ] [ \fB-L \fILABEL\fB\fR ] [ \fB-n \fIXXXX\fB\fR ] [ \fB-N\fR ] [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR ] [ \fB-O\fR ] [ \fB-p \fIPART\fB\fR ] [ \fB-q\fR ] [ \fB-t \fIseconds\fB\fR ] [ \fB-T\fR ] [ \fB-u\fR ] [ \fB-U \fIXXXX\fB\fR ] [ \fB-v\fR ] [ \fB-V\fR ] [ \fB-w\fR ] [ \fB-@ \fIfile\fB\fR ]
+\fBefibootmgr\fR [ \fB-a\fR ] [ \fB-A\fR ] [ \fB-b \fIXXXX\fB\fR ] [ \fB-B \fIXXXX\fB\fR ] [ \fB-c\fR ] [ \fB-d \fIDISK\fB\fR ] [ \fB-D\fR ] [ \fB-e \fI1|3|-1\fB\fR ] [ \fB-E \fINUM\fB\fR ] [ \fB-g\fR ] [ \fB-H \fIXXXX\fB\fR ] [ \fB-i \fINAME\fB\fR ] [ \fB-l \fINAME\fB\fR ] [ \fB-L \fILABEL\fB\fR ] [ \fB-n \fIXXXX\fB\fR ] [ \fB-N\fR ] [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR ] [ \fB-O\fR ] [ \fB-p \fIPART\fB\fR ] [ \fB-q\fR ] [ \fB-t \fIseconds\fB\fR ] [ \fB-T\fR ] [ \fB-u\fR ] [ \fB-U \fIXXXX\fB\fR ] [ \fB-v\fR ] [ \fB-V\fR ] [ \fB-w\fR ] [ \fB-@ \fIfile\fB\fR ]
.SH "DESCRIPTION"
.PP
@@ -51,6 +51,9 @@ Create new variable bootnum and add to bootorder
The disk containing the loader (defaults to
\fI/dev/sda\fR)
.TP
+\fB-D | --remove-dups\fR
+Remove duplicated entries from BootOrder
+.TP
\fB-e | --edd \fI1|3|-1\fB\fR
Force EDD 1.0 or 3.0 creation variables, or guess.
.TP
--
1.9.3