Blob Blame History Raw
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