From 683831290c50f64d8964bef2a5d8d0092b32ca15 Mon Sep 17 00:00:00 2001 From: Peter Jones 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 --- 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