efibootmgr/efibootmgr-delete-multiple.diff

304 lines
9.2 KiB
Diff

From 21741160071c83e4ae6b9fa268947abfd0d3405f Mon Sep 17 00:00:00 2001
From: Raymund Will <rw@suse.com>
Date: Fri, 3 Mar 2017 18:47:44 +0100
Subject: [PATCH] Extended Delete
References: bsc#870211, bsc#945705
Delete boot entries not only by number. but alse based on
- partition UUID, optionally restricted by loader
or
- disk and partition, again optionally restricted by loader.
This does unfortunately require an API-change of efivar!
Signed-off-by: Raymund Will <rw@suse.com>
---
Index: efibootmgr-18/src/efibootmgr.c
===================================================================
--- efibootmgr-18.orig/src/efibootmgr.c
+++ efibootmgr-18/src/efibootmgr.c
@@ -664,6 +664,146 @@ delete_label(const char *prefix, const u
return 0;
}
+static int
+delete_by_uuid(const char *prefix, char *uuid_str, char *loader)
+{
+ int count = 0;
+ list_t *pos, *tmp;
+ var_entry_t *entry;
+ const unsigned char *description;
+ efi_load_option *load_option;
+ efidp path = NULL;
+ char text_path[1024];
+
+ list_for_each_safe(pos, tmp, &entry_list) {
+ uint16_t pathlen;
+ ssize_t rc;
+
+ entry = list_entry(pos, var_entry_t, list);
+ load_option = (efi_load_option *)entry->data;
+ pathlen = efi_loadopt_pathlen(load_option,
+ entry->data_size);
+ path = efi_loadopt_path(load_option, entry->data_size);
+ rc = efidp_format_device_path((unsigned char *)text_path, 1024,
+ path, pathlen);
+
+ if (rc < 0 || rc > 1024)
+ error(20, "Could not parse device path");
+
+ if (strlen(text_path) == 0)
+ continue;
+ if (strcasestr(text_path, uuid_str) == NULL)
+ continue;
+ if (loader && strcasestr(text_path, loader) == NULL)
+ continue;
+ /* found! */
+ if (opts.verbose) {
+ description = efi_loadopt_desc(load_option,
+ entry->data_size);
+ printf("Delete %s%04X %s\t%s\n",
+ prefix, entry->num, description, text_path);
+ }
+ if (delete_var(prefix, entry->num) != 0)
+ return -1;
+ count++;
+ }
+ if (count==0) {
+ /* Nothing changed => exit early */
+ exit(0);
+ }
+ return 0;
+}
+
+static int
+delete_by_dpl(const char *prefix, char *disk, uint32_t part, char *loader)
+{
+ int fd, rc;
+ uint64_t start, size;
+ efi_guid_t signature;
+ char sigstr[40];
+ char *sigstrp = sigstr;
+ uint8_t mbr_type, signature_type;
+
+ if (disk == NULL && part == 0 && loader == NULL)
+ errx(42, "Cowardly refusing to delete ALL %s entries.",
+ prefix);
+ if (disk == NULL) {
+ /* foreach d in gpt_disks
+ * delete_by_dpl(prefix, d, part, loader)
+ */
+ errx(42, "Future extension.");
+ }
+ if (part == 0) {
+ /* foreach p in partions_on_gpt_disk
+ * delete_by_dpl(prefix, disk, p, loader)
+ */
+ errx(42, "Future extension.");
+ }
+ memset((char *)&signature, 0, sizeof(signature));
+
+ fd = open(disk, O_RDONLY|O_DIRECT);
+ if (fd == -1)
+ error(42, "Could not open disk %s", disk);
+ rc = efi_disk_get_partition_info(fd, part, &start, &size,
+ (uint8_t*)&signature, &mbr_type, &signature_type);
+ close(fd);
+
+ if (rc)
+ return -1;
+ if (mbr_type != 0x02) {
+ errx(42, "Cowardly refusing non-GPT disk %s", disk);
+ }
+
+ efi_guid_to_str(&signature, &sigstrp);
+
+ if (opts.verbose && !loader) {
+ printf("About to delete all entries referring to UUID %s\n",
+ sigstr);
+ } else if ( opts.delete != 15) {
+ printf("About to delete all entries referring to loader %s\n"
+ " on UUID %s\n",
+ loader, sigstr);
+ }
+ return delete_by_uuid(prefix,sigstr,loader);
+}
+
+/* verbatim copy of same function in efivar/src/creator.c */
+static char *
+tilt_slashes(char *s)
+{
+ char *p;
+ for (p = s; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+ return s;
+}
+
+static int
+check_uuid(const char *s)
+{
+ /* algorithm derived from efivar/src/guid.h */
+ size_t 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 *prefix, list_t *list)
{
@@ -1397,7 +1537,9 @@ usage()
printf("\t-a | --active Set bootnum active.\n");
printf("\t-A | --inactive Set bootnum inactive.\n");
printf("\t-b | --bootnum XXXX Modify BootXXXX (hex).\n");
- printf("\t-B | --delete-bootnum Delete bootnum.\n");
+ printf("\t-B | --delete-bootnum delete bootnum (specified with -b)\n");
+ printf("\t --delete delete entry by bootnum (-b), by UUID (-P)\n");
+ printf("\t or by disk+partition[+file] (-d -p -l)\n");
printf("\t-c | --create Create new variable bootnum and add to bootorder at index (-I).\n");
printf("\t-C | --create-only Create new variable bootnum and do not add to bootorder.\n");
printf("\t-d | --disk disk Disk containing boot loader (defaults to /dev/sda).\n");
@@ -1420,6 +1562,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 Partition containing loader (defaults to 1 on partitioned devices).\n");
+ printf("\t-P | --part-uuid UUID select all variables for given partition UUID\n");
printf("\t-q | --quiet Be quiet.\n");
printf("\t-r | --driver Operate on Driver variables, not Boot Variables.\n");
printf("\t-t | --timeout seconds Set boot manager timeout waiting for user input.\n");
@@ -1447,6 +1590,7 @@ set_default_opts()
opts.label = (unsigned char *)"Linux";
opts.disk = "/dev/sda";
opts.part = -1;
+ opts.part_uuid = NULL;
}
static void
@@ -1470,6 +1614,7 @@ parse_opts(int argc, char **argv)
{"delete-bootnum", no_argument, 0, 'B'},
{"create", no_argument, 0, 'c'},
{"create-only", no_argument, 0, 'C'},
+ {"delete", no_argument, 0, 2},
{"disk", required_argument, 0, 'd'},
{"remove-dups", no_argument, 0, 'D'},
{"edd", required_argument, 0, 'e'},
@@ -1508,7 +1653,7 @@ parse_opts(int argc, char **argv)
};
c = getopt_long(argc, argv,
- "aAb:BcCd:De:E:fFgi:kl:L:m:M:n:No:Op:qrt:Tuv::Vwy@:h",
+ "aAb:BcCd:De:E:fFgi:kl:L:m:M:n:No:Op:P:qrt:Tuv::Vwy@:h",
long_options, &option_index);
if (c == -1)
break;
@@ -1561,11 +1706,16 @@ parse_opts(int argc, char **argv)
opts.create = 1;
opts.no_order = 1;
break;
+ case 2:
+ opts.delete |= 1;
+ break;
case 'D':
opts.deduplicate = 1;
break;
case 'd':
opts.disk = optarg;
+ if (opts.delete)
+ opts.delete |= 2;
break;
case 'e':
rc = sscanf(optarg, "%d", &snum);
@@ -1627,6 +1777,9 @@ parse_opts(int argc, char **argv)
break;
case 'l':
opts.loader = optarg;
+ tilt_slashes(opts.loader);
+ if (opts.delete)
+ opts.delete |= 8;
break;
case 'L':
opts.label = (unsigned char *)optarg;
@@ -1707,6 +1860,17 @@ parse_opts(int argc, char **argv)
else
errorx(37, "invalid numeric value %s\n",
optarg);
+ if (opts.delete)
+ 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;
@@ -1843,9 +2007,24 @@ main(int argc, char **argv)
set_var_nums(prefices[mode], &entry_list);
if (opts.delete) {
- if (opts.num == -1 && opts.explicit_label == 0) {
+ if (opts.part_uuid) {
+ ret = delete_by_uuid(prefices[mode], opts.part_uuid,
+ (opts.delete & 8) ? opts.loader : NULL);
+ if (ret < 0)
+ error(42, "Could not delete variable(s)");
+ } else if (opts.delete & 2) {
+ ret = delete_by_dpl(prefices[mode],
+ (opts.delete & 2) ? opts.disk : NULL,
+ (opts.delete & 4) ? opts.part : 0,
+ (opts.delete & 8) ? opts.loader : NULL);
+ if (ret < 0)
+ error(42, "Could not delete variable(s)");
+ } else if (opts.delete > 1)
+ errorx(3, "Disk and partition must be specified "
+ "(see the --delete option).");
+ else if (opts.num == -1 && opts.explicit_label == 0) {
errorx(3,
- "You must specify an entry to delete (see the -b option or -L option).");
+ "You must specify an entry to delete (e.g. with the -b option or -L option).");
} else {
if (opts.num != -1) {
ret = delete_var(prefices[mode], opts.num);
Index: efibootmgr-18/src/include/efibootmgr.h
===================================================================
--- efibootmgr-18.orig/src/include/efibootmgr.h
+++ efibootmgr-18/src/include/efibootmgr.h
@@ -66,6 +66,7 @@ typedef struct {
int keep_old_entries;
char *testfile;
char *extra_opts_file;
+ char *part_uuid;
uint32_t part;
int abbreviate_path;
uint32_t edd10_devicenum;
@@ -77,7 +78,7 @@ typedef struct {
int below4g;
int above4g;
int deduplicate;
- unsigned int delete:1;
+ unsigned int delete:4;
unsigned int delete_order:1;
unsigned int delete_bootnext:1;
unsigned int quiet:1;