summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2013-02-16 17:25:19 +0100
committerKay Sievers <kay@vrfy.org>2013-02-16 17:25:19 +0100
commitf599ff3dac02411a046544c495beffb68f908d2f (patch)
tree8722e1d037c8daeff52b5f800fc760daae3b56cd
parentbf2afc024e2e7fc5a18a52af2cb5c03f8d880245 (diff)
setup: efivars - remove boot option variable at remove
-rw-r--r--src/setup/efivars.c16
-rw-r--r--src/setup/efivars.h3
-rw-r--r--src/setup/setup.c69
3 files changed, 73 insertions, 15 deletions
diff --git a/src/setup/efivars.c b/src/setup/efivars.c
index d6d0e88..808c52f 100644
--- a/src/setup/efivars.c
+++ b/src/setup/efivars.c
@@ -142,8 +142,6 @@ int efi_set_variable(
assert(vendor);
assert(name);
- assert(value);
- assert(size);
if (asprintf(&p,
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
@@ -152,6 +150,11 @@ int efi_set_variable(
vendor[8], vendor[9], vendor[10], vendor[11], vendor[12], vendor[13], vendor[14], vendor[15]) < 0)
return -ENOMEM;
+ if (size == 0) {
+ r = unlink(p);
+ goto finish;
+ }
+
fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
if (fd < 0) {
r = -errno;
@@ -403,7 +406,7 @@ static void to_utf16(uint16_t *dest, const char *src) {
dest[i] = '\0';
}
-int efi_set_boot_option(uint16_t id, const char *title,
+int efi_add_boot_option(uint16_t id, const char *title,
uint32_t part, uint64_t pstart, uint64_t psize,
const uint8_t part_uuid[16],
const char *path) {
@@ -473,6 +476,13 @@ finish:
return err;
}
+int efi_remove_boot_option(uint16_t id) {
+ char boot_id[9];
+
+ snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
+ return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
+}
+
int efi_get_boot_order(uint16_t **order) {
void *buf;
size_t l;
diff --git a/src/setup/efivars.h b/src/setup/efivars.h
index b555fe0..d54be9f 100644
--- a/src/setup/efivars.h
+++ b/src/setup/efivars.h
@@ -36,10 +36,11 @@ int efi_get_variable_string(const uint8_t vendor[16], const char *name, char **p
int efi_get_boot_option(uint16_t id, char **title, uint8_t part_uuid[16], char **path);
int efi_get_boot_options(uint16_t **options);
-int efi_set_boot_option(uint16_t id, const char *title,
+int efi_add_boot_option(uint16_t id, const char *title,
uint32_t part, uint64_t pstart, uint64_t psize,
const uint8_t part_uuid[16],
const char *path);
+int efi_remove_boot_option(uint16_t id);
int efi_get_boot_order(uint16_t **order);
int efi_set_boot_order(uint16_t *order, size_t n);
diff --git a/src/setup/setup.c b/src/setup/setup.c
index 2fb2951..badc3a0 100644
--- a/src/setup/setup.c
+++ b/src/setup/setup.c
@@ -43,8 +43,6 @@
/* TODO:
*
- * - Maybe write EFI variables as right-away?
- * - Make backups of foreign files we overwrite
* - Generate loader.conf from /etc/os-release?
* - fix seek nonsense when looking for file version
*/
@@ -884,20 +882,22 @@ finish:
return same;
}
-static uint16_t find_slot(const uint8_t uuid[16], const char *path) {
+static int find_slot(const uint8_t uuid[16], const char *path, uint16_t *id) {
uint16_t *options = NULL;
int n_options;
int i;
uint16_t new_id = 0;
+ bool existing = false;
n_options = efi_get_boot_options(&options);
if (n_options < 0)
- return new_id;
+ return n_options;
/* find already existing gummiboot entry */
for (i = 0; i < n_options; i++)
if (same_entry(options[i], uuid, path)) {
new_id = i;
+ existing = true;
goto finish;
}
@@ -909,11 +909,12 @@ static uint16_t find_slot(const uint8_t uuid[16], const char *path) {
}
finish:
+ *id = new_id;
free(options);
- return new_id;
+ return existing ? 1 : 0;
}
-static int insert_order(uint16_t slot) {
+static int insert_into_order(uint16_t slot) {
uint16_t *order = NULL;
uint16_t *new_order;
int n_order;
@@ -947,6 +948,32 @@ finish:
return err;
}
+static int remove_from_order(uint16_t slot) {
+ uint16_t *order = NULL;
+ int n_order;
+ int i;
+ int err = 0;
+
+ n_order = efi_get_boot_order(&order);
+ if (n_order < 0)
+ return n_order;
+ if (n_order == 0)
+ return 0;
+
+ for (i = 0; i < n_order; i++) {
+ if (order[i] != slot)
+ continue;
+
+ if (i+1 < n_order)
+ memmove(&order[i], &order[i+1], (n_order - i) * sizeof(uint16_t));
+ efi_set_boot_order(order, n_order-1);
+ break;
+ }
+
+ free(order);
+ return err;
+}
+
static int install_variables(uint32_t part, uint64_t pstart, uint64_t psize,
const uint8_t uuid[16], const char *path,
bool in_order) {
@@ -962,8 +989,13 @@ static int install_variables(uint32_t part, uint64_t pstart, uint64_t psize,
return 0;
}
- slot = find_slot(uuid, path);
- err = efi_set_boot_option(slot,
+ err = find_slot(uuid, path, &slot);
+ if (err < 0) {
+ fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(err));
+ goto finish;
+ }
+
+ err = efi_add_boot_option(slot,
"Linux Boot Manager",
part, pstart, psize,
uuid, path);
@@ -972,9 +1004,10 @@ static int install_variables(uint32_t part, uint64_t pstart, uint64_t psize,
else {
fprintf(stderr, "Created EFI Boot entry \"Linux Boot Manager\".\n");
if (in_order)
- insert_order(slot);
+ insert_into_order(slot);
}
+finish:
free(options);
return 0;
}
@@ -1147,13 +1180,27 @@ static int remove_binaries(void) {
return r;
}
-static int remove_variables(void) {
+static int remove_variables(const uint8_t uuid[16], const char *path, bool in_order) {
+ uint16_t slot;
+ int err;
+
if (!arg_touch_variables)
return 0;
if (!is_efi_boot())
return 0;
+ err = find_slot(uuid, path, &slot);
+ if (err != 1)
+ return 0;
+
+ err = efi_remove_boot_option(slot);
+ if (err < 0)
+ return err;
+
+ if (in_order)
+ remove_from_order(slot);
+
return 0;
}
@@ -1274,7 +1321,7 @@ int main(int argc, char*argv[]) {
case ACTION_REMOVE:
r = remove_binaries();
- q = remove_variables();
+ q = remove_variables(uuid, "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi", true);
if (q < 0 && r == 0)
r = q;
break;