bootctl: add sd-boot support

This commit is contained in:
Kay Sievers 2015-02-08 17:18:30 +01:00
parent 0fa2cac4f0
commit 0974a682d1
11 changed files with 1613 additions and 653 deletions

View file

@ -2479,15 +2479,21 @@ systemd_efi_boot_generator_LDADD = \
# ------------------------------------------------------------------------------
bootctl_SOURCES = \
src/boot/boot.h \
src/boot/boot-loader.h \
src/boot/bootctl.c \
src/boot/boot-loader.c \
src/boot/boot-efi.c
src/boot/bootctl.c
bootctl_CPPFLAGS = \
$(AM_CPPFLAGS) \
-DEFI_MACHINE_TYPE_NAME=\"$(EFI_MACHINE_TYPE_NAME)\" \
-DSD_BOOTLIBDIR=\"$(sd_bootlibdir)\"
bootctl_CFLAGS = \
$(AM_CFLAGS) \
$(BLKID_CFLAGS)
bootctl_LDADD = \
libsystemd-shared.la \
libsystemd-internal.la
libsystemd-internal.la \
$(BLKID_LIBS)
bin_PROGRAMS += \
bootctl

View file

@ -21,7 +21,6 @@
<refentry id="bootctl" conditional='ENABLE_EFI'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>bootctl</title>
<productname>systemd</productname>
@ -48,65 +47,82 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>bootctl</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="req">COMMAND</arg>
<command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>status</command>
</cmdsynopsis>
<cmdsynopsis>
<command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>update</command>
</cmdsynopsis>
<cmdsynopsis>
<command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>install</command>
</cmdsynopsis>
<cmdsynopsis>
<command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>remove</command>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>bootctl</command> may be used to query or (in the
future) change the firmware and boot manager settings.</para>
<para><command>bootctl</command> checks, updates,
installs or removes the boot loader from the current
system.</para>
<para>Firmware information is available only on EFI systems.
</para>
<para><command>bootctl status</command> checks and prints the
currently installed versions of the boot loader binaries and the
all current EFI boot variables.</para>
<para>Currently, only the
<citerefentry project='gummiboot'><refentrytitle>gummiboot</refentrytitle><manvolnum>8</manvolnum></citerefentry>
boot manager implements the required boot loader interface to
provide complete boot manager information.</para>
<para><command>bootctl update</command> updates all installed
versions of sd-boot, if the current version is newer than the
version installed in the EFI system partition. This also includes
the EFI default/fallback loader at /EFI/Boot/boot*.efi. An
sd-boot entry in the EFI boot variables is created, if there
is no current entry. A created entry will be added to the end of
the boot order list.</para>
<para><command>bootctl install</command> installs sd-boot into
the EFI system partition. A copy of sd-boot will be stored as
the EFI default/fallback loader at /EFI/Boot/boot*.efi. An sd-boot
entry in the EFI boot variables is created and added to the top
of the boot order list.</para>
<para><command>bootctl remove</command> removes all installed
versions of sd-boot from the EFI system partition, and removes
sd-boot from the EFI boot variables.</para>
<para>If no command is passed <command>status</command> is
implied.</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
<para>The following commands are understood:</para>
<variablelist>
<varlistentry>
<term><command>status</command></term>
<term><option>--path</option></term>
<listitem><para>Path to the EFI system partition. The default is /boot.</para></listitem>
</varlistentry>
<listitem><para>Show firmware and boot manager information
about the system, including secure boot mode status and
selected firmware entry (where available).</para></listitem>
<varlistentry>
<term><option>--no-variables</option></term>
<listitem><para>Do not touch the EFI boot variables.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Exit status</title>
<para>On success, 0 is returned, a non-zero failure code
otherwise.</para>
<para>On success 0 is returned, a non-zero failure
code otherwise.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<ulink url="http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface">Boot loader interface</ulink>,
<ulink url="http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec">Boot loader specification</ulink>,
<ulink url="http://www.freedesktop.org/wiki/Software/gummiboot/">gummiboot</ulink>
<ulink url="http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec">Boot loader specification</ulink>
<ulink url="http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface">Systemd boot loader interface</ulink>
</para>
</refsect1>
</refentry>

View file

@ -87,10 +87,6 @@
</a>
</xsl:template>
<xsl:template match="citerefentry[@project='gummiboot']">
<xsl:call-template name="inline.charseq"/>
</xsl:template>
<xsl:template match="refsect1/title|refsect1/info/title">
<!-- the ID is output in the block.object call for refsect1 -->
<h2>

View file

@ -80,7 +80,6 @@
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>gummiboot</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>

View file

@ -1,190 +0,0 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Kay Sievers
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <locale.h>
#include <string.h>
#include <fnmatch.h>
#include <fcntl.h>
#include <sys/timex.h>
#include "boot.h"
#include "boot-loader.h"
#include "build.h"
#include "util.h"
#include "strv.h"
#include "efivars.h"
#include "conf-files.h"
static char *tilt_slashes(char *s) {
char *p;
if (!s)
return NULL;
for (p = s; *p; p++)
if (*p == '\\')
*p = '/';
return s;
}
static int get_boot_entries(struct boot_info *info) {
uint16_t *list = NULL;
int i, n;
int err = 0;
n = efi_get_boot_options(&list);
if (n < 0)
return n;
for (i = 0; i < n; i++) {
struct boot_info_entry *e;
e = realloc(info->fw_entries, (info->fw_entries_count+1) * sizeof(struct boot_info_entry));
if (!e) {
err = -ENOMEM;
break;
}
info->fw_entries = e;
e = &info->fw_entries[info->fw_entries_count];
memzero(e, sizeof(struct boot_info_entry));
e->order = -1;
err = efi_get_boot_option(list[i], &e->title, &e->part_uuid, &e->path);
if (err < 0)
continue;
if (isempty(e->title)) {
free(e->title);
e->title = NULL;
}
tilt_slashes(e->path);
e->id = list[i];
info->fw_entries_count++;
}
free(list);
return err;
}
static int find_active_entry(struct boot_info *info) {
uint16_t boot_cur;
void *buf;
size_t l;
size_t i;
int err;
err = efi_get_variable(EFI_VENDOR_GLOBAL, "BootCurrent", NULL, &buf, &l);
if (err < 0)
return err;
memcpy(&boot_cur, buf, sizeof(uint16_t));
for (i = 0; i < info->fw_entries_count; i++) {
if (info->fw_entries[i].id != boot_cur)
continue;
info->fw_entry_active = i;
err = 0;
break;
}
free(buf);
return err;
}
static int get_boot_order(struct boot_info *info) {
size_t i, k;
int r;
r = efi_get_boot_order(&info->fw_entries_order);
if (r < 0)
return r;
info->fw_entries_order_count = r;
for (i = 0; i < info->fw_entries_order_count; i++) {
for (k = 0; k < info->fw_entries_count; k++) {
if (info->fw_entries[k].id != info->fw_entries_order[i])
continue;
info->fw_entries[k].order = i;
break;
}
}
return 0;
}
static int entry_cmp(const void *a, const void *b) {
const struct boot_info_entry *e1 = a;
const struct boot_info_entry *e2 = b;
/* boot order of active entries */
if (e1->order > 0 && e2->order > 0)
return e1->order - e2->order;
/* sort active entries before inactive ones */
if (e1->order > 0)
return 1;
if (e2->order > 0)
return -1;
/* order of inactive entries */
return e1->id - e2->id;
}
int boot_info_query(struct boot_info *info) {
char str[64];
char buf[64];
char *loader_active = NULL;
info->fw_secure_boot = is_efi_secure_boot();
info->fw_secure_boot_setup_mode = is_efi_secure_boot_setup_mode();
efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info->loader);
get_boot_entries(info);
if (info->fw_entries_count > 0) {
get_boot_order(info);
qsort(info->fw_entries, info->fw_entries_count, sizeof(struct boot_info_entry), entry_cmp);
find_active_entry(info);
}
efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &info->fw_type);
efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &info->fw_info);
efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &info->loader_image_path);
tilt_slashes(info->loader_image_path);
efi_loader_get_device_part_uuid(&info->loader_part_uuid);
boot_loader_read_entries(info);
efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntrySelected", &loader_active);
if (loader_active) {
boot_loader_find_active_entry(info, loader_active);
free(loader_active);
}
snprintf(str, sizeof(str), "LoaderEntryOptions-%s", sd_id128_to_string(info->machine_id, buf));
efi_get_variable_string(EFI_VENDOR_LOADER, str, &info->loader_options_added);
return 0;
}

View file

@ -1,132 +0,0 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Kay Sievers
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <locale.h>
#include <string.h>
#include <ctype.h>
#include <sys/timex.h>
#include "boot.h"
#include "boot-loader.h"
#include "build.h"
#include "util.h"
#include "strv.h"
#include "conf-files.h"
static char *loader_fragment_read_title(const char *fragment) {
FILE *f;
char line[LINE_MAX];
char *title = NULL;
f = fopen(fragment, "re");
if (!f)
return NULL;
while (fgets(line, sizeof(line), f) != NULL) {
char *s;
size_t l;
l = strlen(line);
if (l < 1)
continue;
if (line[l-1] == '\n')
line[l-1] = '\0';
s = line;
while (isspace(s[0]))
s++;
if (s[0] == '#')
continue;
if (!startswith(s, "title"))
continue;
s += strlen("title");
if (!isspace(s[0]))
continue;
while (isspace(s[0]))
s++;
title = strdup(s);
break;
}
fclose(f);
return title;
}
int boot_loader_read_entries(struct boot_info *info) {
_cleanup_strv_free_ char **files = NULL;
static const char *loader_dir[] = { "/boot/loader/entries", NULL};
unsigned int count;
unsigned int i;
int err;
err = conf_files_list_strv(&files, ".conf", NULL, loader_dir);
if (err < 0)
return err;
count = strv_length(files);
info->loader_entries = new0(struct boot_info_entry, count);
if (!info->loader_entries)
return -ENOMEM;
for (i = 0; i < count; i++) {
info->loader_entries[i].title = loader_fragment_read_title(files[i]);
info->loader_entries[i].path = strdup(files[i]);
if (!info->loader_entries[i].title || !info->loader_entries[i].path) {
free(info->loader_entries[i].title);
free(info->loader_entries[i].path);
return -ENOMEM;
}
info->loader_entries_count++;
}
return 0;
}
int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active) {
char *fn;
unsigned int i;
if (!loader_active)
return -ENOENT;
if (info->loader_entries_count == 0)
return -ENOENT;
if (asprintf(&fn, "/boot/loader/entries/%s.conf", loader_active) < 0)
return -ENOMEM;
for (i = 0; i < info->loader_entries_count; i++) {
if (streq(fn, info->loader_entries[i].path)) {
info->loader_entry_active = i;
break;
}
}
free(fn);
return 0;
}

View file

@ -1,27 +0,0 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Kay Sievers
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "boot.h"
int boot_loader_read_entries(struct boot_info *info);
int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active);

View file

@ -1,64 +0,0 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Kay Sievers
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-id128.h"
/*
* Firmware and boot manager information to be filled in
* by the platform.
*
* This is partly EFI specific, if you add things, keep this
* as generic as possible to be able to re-use it on other
* platforms.
*/
struct boot_info_entry {
uint16_t id;
uint16_t order;
char *title;
sd_id128_t part_uuid;
char *path;
};
struct boot_info {
sd_id128_t machine_id;
sd_id128_t boot_id;
char *fw_type;
char *fw_info;
int fw_secure_boot;
int fw_secure_boot_setup_mode;
struct boot_info_entry *fw_entries;
size_t fw_entries_count;
uint16_t *fw_entries_order;
size_t fw_entries_order_count;
ssize_t fw_entry_active;
char *loader;
char *loader_image_path;
sd_id128_t loader_part_uuid;
struct boot_info_entry *loader_entries;
size_t loader_entries_count;
ssize_t loader_entry_active;
char *loader_options_added;
};
int boot_info_query(struct boot_info *info);

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,40 @@
#ifdef ENABLE_EFI
#define LOAD_OPTION_ACTIVE 0x00000001
#define MEDIA_DEVICE_PATH 0x04
#define MEDIA_HARDDRIVE_DP 0x01
#define MEDIA_FILEPATH_DP 0x04
#define SIGNATURE_TYPE_GUID 0x02
#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
#define END_DEVICE_PATH_TYPE 0x7f
#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
struct boot_option {
uint32_t attr;
uint16_t path_len;
uint16_t title[];
} __attribute__((packed));
struct drive_path {
uint32_t part_nr;
uint64_t part_start;
uint64_t part_size;
char signature[16];
uint8_t mbr_type;
uint8_t signature_type;
} __attribute__((packed));
struct device_path {
uint8_t type;
uint8_t sub_type;
uint16_t length;
union {
uint16_t path[0];
struct drive_path drive;
};
} __attribute__((packed));
bool is_efi_boot(void) {
return access("/sys/firmware/efi", F_OK) >= 0;
}
@ -128,6 +162,66 @@ int efi_get_variable(
return 0;
}
int efi_set_variable(
sd_id128_t vendor,
const char *name,
const void *value,
size_t size) {
struct var {
uint32_t attr;
char buf[];
} __attribute__((packed)) *buf = NULL;
char *p = NULL;
int fd = -1;
int r;
assert(name);
if (asprintf(&p,
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
name, SD_ID128_FORMAT_VAL(vendor)) < 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;
goto finish;
}
buf = malloc(sizeof(uint32_t) + size);
if (!buf) {
r = -errno;
goto finish;
}
buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
memcpy(buf->buf, value, size);
r = write(fd, buf, sizeof(uint32_t) + size);
if (r < 0) {
r = -errno;
goto finish;
}
if ((size_t)r != sizeof(uint32_t) + size) {
r = -EIO;
goto finish;
}
finish:
if (fd >= 0)
close(fd);
free(buf);
free(p);
return r;
}
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
_cleanup_free_ void *s = NULL;
size_t ss = 0;
@ -179,8 +273,8 @@ int efi_get_boot_option(
uint16_t id,
char **title,
sd_id128_t *part_uuid,
char **path) {
char **path,
bool *active) {
struct boot_option {
uint32_t attr;
uint16_t path_len;
@ -250,23 +344,23 @@ int efi_get_boot_option(
break;
/* Type 0x7F End of Hardware Device Path, Sub-Type 0xFF End Entire Device Path */
if (dpath->type == 0x7f && dpath->sub_type == 0xff)
if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
break;
dnext += dpath->length;
/* Type 0x04 Media Device Path */
if (dpath->type != 0x04)
if (dpath->type != MEDIA_DEVICE_PATH)
continue;
/* Sub-Type 1 Hard Drive */
if (dpath->sub_type == 0x01) {
if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
/* 0x02 GUID Partition Table */
if (dpath->drive.mbr_type != 0x02)
if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
continue;
/* 0x02 GUID signature */
if (dpath->drive.signature_type != 0x02)
if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
continue;
if (part_uuid)
@ -275,8 +369,9 @@ int efi_get_boot_option(
}
/* Sub-Type 4 File Path */
if (dpath->sub_type == 0x04 && !p && path) {
if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
p = utf16_to_utf8(dpath->path, dpath->length-4);
efi_tilt_backslashes(p);
continue;
}
}
@ -288,6 +383,8 @@ int efi_get_boot_option(
*part_uuid = p_uuid;
if (path)
*path = p;
if (active)
*active = !!header->attr & LOAD_OPTION_ACTIVE;
return 0;
err:
@ -296,6 +393,126 @@ err:
return err;
}
static void to_utf16(uint16_t *dest, const char *src) {
int i;
for (i = 0; src[i] != '\0'; i++)
dest[i] = src[i];
dest[i] = '\0';
}
struct guid {
uint32_t u1;
uint16_t u2;
uint16_t u3;
uint8_t u4[8];
} __attribute__((packed));
static void id128_to_efi_guid(sd_id128_t id, void *guid) {
struct guid *uuid = guid;
uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
}
static uint16_t *tilt_slashes(uint16_t *s) {
uint16_t *p;
for (p = s; *p; p++)
if (*p == '/')
*p = '\\';
return s;
}
char *efi_tilt_backslashes(char *s) {
char *p;
for (p = s; *p; p++)
if (*p == '\\')
*p = '/';
return s;
}
int efi_add_boot_option(uint16_t id, const char *title,
uint32_t part, uint64_t pstart, uint64_t psize,
sd_id128_t part_uuid, const char *path) {
char boot_id[9];
char *buf;
size_t size;
size_t title_len;
size_t path_len;
struct boot_option *option;
struct device_path *devicep;
int err;
title_len = (strlen(title)+1) * 2;
path_len = (strlen(path)+1) * 2;
buf = calloc(sizeof(struct boot_option) + title_len +
sizeof(struct drive_path) +
sizeof(struct device_path) + path_len, 1);
if (!buf) {
err = -ENOMEM;
goto finish;
}
/* header */
option = (struct boot_option *)buf;
option->attr = LOAD_OPTION_ACTIVE;
option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
offsetof(struct device_path, path) + path_len +
offsetof(struct device_path, path);
to_utf16(option->title, title);
size = offsetof(struct boot_option, title) + title_len;
/* partition info */
devicep = (struct device_path *)(buf + size);
devicep->type = MEDIA_DEVICE_PATH;
devicep->sub_type = MEDIA_HARDDRIVE_DP;
devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
devicep->drive.part_nr = part;
devicep->drive.part_start = pstart;
devicep->drive.part_size = psize;
devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
id128_to_efi_guid(part_uuid, devicep->drive.signature);
size += devicep->length;
/* path to loader */
devicep = (struct device_path *)(buf + size);
devicep->type = MEDIA_DEVICE_PATH;
devicep->sub_type = MEDIA_FILEPATH_DP;
devicep->length = offsetof(struct device_path, path) + path_len;
to_utf16(devicep->path, path);
tilt_slashes(devicep->path);
size += devicep->length;
/* end of path */
devicep = (struct device_path *)(buf + size);
devicep->type = END_DEVICE_PATH_TYPE;
devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
devicep->length = offsetof(struct device_path, path);
size += devicep->length;
snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
err = efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
finish:
free(buf);
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;
@ -320,6 +537,10 @@ int efi_get_boot_order(uint16_t **order) {
return (int) (l / sizeof(uint16_t));
}
int efi_set_boot_order(uint16_t *order, size_t n) {
return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
}
static int boot_id_hex(const char s[4]) {
int i;
int id = 0;

View file

@ -30,17 +30,26 @@
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
bool is_efi_boot(void);
int is_efi_secure_boot(void);
int is_efi_secure_boot_setup_mode(void);
int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *partuuid, char **path);
int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active);
int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, 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);
int efi_get_boot_options(uint16_t **options);
int efi_loader_get_device_part_uuid(sd_id128_t *u);
int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader);
char *efi_tilt_backslashes(char *s);