File efibootmgr-delete-multiple.diff of Package efibootmgr

From: Raymund Will <rw@suse.com>
Subject: Delete boot entries based on partition UUID.
References: bsc#870211, bsc#945705


Signed-off-by: Raymund Will <rw@suse.com>
---
 src/efibootmgr/efibootmgr.c |  149 +++++++++++++++++++++++++++++++++++++++++++-
 src/include/efibootmgr.h    |    2 
 2 files changed, 149 insertions(+), 2 deletions(-)

--- a/src/efibootmgr/efibootmgr.c
+++ b/src/efibootmgr/efibootmgr.c
@@ -467,6 +467,109 @@ delete_boot_var(uint16_t num)
 	return EFI_SUCCESS;
 }
 
+static int
+delete_boot_uuid(char *uuid_str)
+{
+	int count = 0;
+	list_t *pos, *tmp;
+	var_entry_t *boot;
+	char description[80];
+	EFI_LOAD_OPTION *load_option;
+	EFI_DEVICE_PATH *path;
+	char text_path[1024];
+
+	list_for_each_safe(pos, tmp, &boot_entry_list) {
+		boot = list_entry(pos, var_entry_t, list);
+		load_option = (EFI_LOAD_OPTION *)boot->var_data.Data;
+		path = load_option_path(load_option);
+		memset(text_path, 0, sizeof(text_path));
+		unparse_path(text_path, path,
+				load_option->file_path_list_length);
+		if (strlen(text_path) == 0)
+			continue;
+		if (strcasestr(text_path, uuid_str) == NULL)
+			continue;
+		/* found! */
+		if (opts.verbose) {
+			efichar_to_char(description, load_option->description,
+				sizeof(description));
+			printf("Delete Boot%04X %s\t%s\n",
+				boot->num, description, text_path);
+		}
+		if (delete_boot_var(boot->num) != EFI_SUCCESS)
+			return -1;
+		count++;
+	}
+	if (count==0) {
+		/* Nothing changed => exit early */
+		exit(0);
+	}
+	return 0;
+}
+
+static int
+delete_boot_diskpart(char *disk, uint32_t part)
+{
+	int fd, rc;
+	uint64_t start, size;
+#define MLEN 80
+	char signature[16], sigstr[40], msg[MLEN+1];
+	uint8_t mbr_type, signature_type;
+
+	memset(signature, 0, sizeof(signature));
+
+	fd = open(disk, O_RDONLY|O_DIRECT);
+	if (fd == -1) {
+		snprintf(msg, MLEN, "Could not open disk %s", disk);
+		msg[MLEN] = 0;
+		perror(msg);
+		return -1;
+	}
+	rc = disk_get_partition_info(fd, part, &start, &size, signature,
+			 &mbr_type, &signature_type);
+	close(fd);
+	if (rc)
+		return -1;
+	if (mbr_type != 0x02) {
+		snprintf(msg, MLEN, "Cowardly refusing non-GPT disk %s", disk);
+		msg[MLEN] = 0;
+		perror(msg);
+		return -1;
+	}
+	efi_guid_unparse((efi_guid_t *)signature, sigstr);
+
+	if (opts.verbose) {
+		printf("About to delete all entries referring to UUID %s\n",
+			sigstr);
+	}
+	return delete_boot_uuid(sigstr);
+}
+
+static int
+check_uuid(const char *s)
+{
+	/* algorithm derived from efivar-0.15/src/guid.h */
+	int len = 36;
+	unsigned int i;
+	if (strlen(s) != len)
+		return -1;
+	for (i = 0; i < len; i++) {
+		if (i == 8 || i == 13 || i == 18 || i == 23) {
+			if (s[i] != '-')
+				return -1;
+			continue;
+		}
+                if (s[i] >= '0' && s[i] <= '9')
+                        continue;
+		/* "| 0x20" is tolower() without having to worry about
+		 * locale concerns, since we know everything here must
+		 * be within traditional ascii space. */
+		if ((s[i] | 0x20) >= 'a' && (s[i] | 0x20) <= 'f')
+			continue;
+		return -1;
+	}
+	return 0;
+}
 
 static void
 set_var_nums(const char *pattern, list_t *list)
@@ -786,8 +889,10 @@ usage()
 	printf("\t-a | --active         sets bootnum active\n");
 	printf("\t-A | --inactive       sets bootnum inactive\n");
 	printf("\t-b | --bootnum XXXX   modify BootXXXX (hex)\n");
-	printf("\t-B | --delete-bootnum delete bootnum (hex)\n");
+	printf("\t-B | --delete-bootnum delete bootnum (specified with -b)\n");
 	printf("\t-c | --create         create new variable bootnum and add to bootorder\n");
+	printf("\t-C | --delete         delete entry by bootnum (-b), by UUID (-P)\n");
+	printf("\t                      or by disk+partition (-d -p)\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");
@@ -801,6 +906,7 @@ usage()
 	printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,...     explicitly set BootOrder (hex)\n");
 	printf("\t-O | --delete-bootorder delete BootOrder\n");
 	printf("\t-p | --part part        (defaults to 1) containing loader\n");
+	printf("\t-P | --part-uuid UUID   select all variables for given partition UUID\n");
 	printf("\t-q | --quiet            be quiet\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");
@@ -829,6 +935,7 @@ set_default_opts()
 	opts.part            = 1;
 	opts.acpi_hid        = -1;
 	opts.acpi_uid        = -1;
+	opts.part_uuid       = NULL;
 }
 
 static void
@@ -847,6 +954,7 @@ parse_opts(int argc, char **argv)
 			{"bootnum",          required_argument, 0, 'b'},
 			{"delete-bootnum",         no_argument, 0, 'B'},
 			{"create",                 no_argument, 0, 'c'},
+			{"delete",                 no_argument, 0, 'C'},
 			{"disk",             required_argument, 0, 'd'},
 			{"iface",            required_argument, 0, 'i'},
 			{"acpi_hid",         required_argument, 0, 'H'},
@@ -860,6 +968,7 @@ parse_opts(int argc, char **argv)
 			{"bootorder",        required_argument, 0, 'o'},
 			{"delete-bootorder",       no_argument, 0, 'O'},
 			{"part",             required_argument, 0, 'p'},
+			{"part-uuid",        required_argument, 0, 'P'},
 			{"quiet",                  no_argument, 0, 'q'},
 			{"test",             required_argument, 0,   1},
 			{"timeout",          required_argument, 0, 't'},
@@ -875,7 +984,8 @@ 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:cCd:e:E:gH:i:l:L:n:N"
+				 "o:Op:P:qt:TuU:v::Vw@:",
 				 long_options, &option_index);
 		if (c == -1)
 			break;
@@ -905,8 +1015,12 @@ parse_opts(int argc, char **argv)
 		case 'c':
 			opts.create = 1;
 			break;
+		case 'C':
+			opts.delete |= 1;
+			break;
 		case 'd':
 			opts.disk = optarg;
+			opts.delete |= 2;
 			break;
 		case 'e':
 			rc = sscanf(optarg, "%d", &num);
@@ -968,7 +1082,18 @@ parse_opts(int argc, char **argv)
 				fprintf (stderr,"invalid numeric value %s\n",optarg);
 				exit(1);
 			}
+			opts.delete |= 4;
 			break;
+		case 'P':
+			if ((rc=check_uuid(optarg)) < 0) {
+				fprintf(stderr,
+					"malformed partition UUID: %s (%d)\n",
+					optarg, rc);
+				exit(1);
+			}
+			opts.part_uuid = optarg;
+			break;
+
 		case 'q':
 			opts.quiet = 1;
 			break;
@@ -1073,6 +1198,26 @@ main(int argc, char **argv)
 				ret = delete_boot_var(opts.bootnum);
 		}
 
+		if (opts.delete & 1) {
+			if (opts.part_uuid) {
+				ret = delete_boot_uuid(opts.part_uuid);
+				if (ret < 0) {
+					fprintf(stderr, "\nCould not delete boot variables.\n\n");
+					return 1;
+				}
+			} else if (opts.delete & 6) {
+				ret = delete_boot_diskpart(opts.disk, opts.part);
+				if (ret < 0) {
+					fprintf(stderr, "\nCould not delete boot variables.\n\n");
+					return 1;
+				}
+			} else if (opts.bootnum != -1) {
+				ret = delete_boot_var(opts.bootnum);
+			} else {
+				fprintf(stderr, "\nYou must specify a boot entry to delete.\n\n");
+				return 1;
+			}
+		}
 		if (opts.active >= 0) {
 			if (opts.bootnum == -1) {
 				fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n");
--- a/src/include/efibootmgr.h
+++ b/src/include/efibootmgr.h
@@ -32,6 +32,7 @@ typedef struct {
 	char *bootorder;
 	char *testfile;
 	char *extra_opts_file;
+	char *part_uuid;
 	uint32_t part;
 	int edd_version;
 	int edd10_devicenum;
@@ -39,6 +40,7 @@ typedef struct {
 	int bootnext;
 	int verbose;
 	int active;
+	int delete;
 	uint32_t acpi_hid;
 	uint32_t acpi_uid;
 	unsigned int delete_boot:1;
openSUSE Build Service is sponsored by