@@ -16,20 +16,34 @@
#include <efibootguard/ebgenv.h>
#include <generated/autoconf.h>
#include <state.h>
+#include "dlfcn.h"
#include "bootloader.h"
+static struct {
+ void (*beverbose)(ebgenv_t *e, bool v);
+ int (*env_create_new)(ebgenv_t *e);
+ int (*env_open_current)(ebgenv_t *e);
+ int (*env_get)(ebgenv_t *e, char *key, char* buffer);
+ int (*env_set)(ebgenv_t *e, char *key, char *value);
+ int (*env_set_ex)(ebgenv_t *e, char *key, uint64_t datatype, uint8_t *value, uint32_t datalen);
+ uint16_t (*env_getglobalstate)(ebgenv_t *e);
+ int (*env_setglobalstate)(ebgenv_t *e, uint16_t ustate);
+ int (*env_close)(ebgenv_t *e);
+ int (*env_finalize_update)(ebgenv_t *e);
+} libebg;
+
static ebgenv_t ebgenv = {0};
-int bootloader_env_set(const char *name, const char *value)
+static int do_env_set(const char *name, const char *value)
{
int ret;
errno = 0;
- ebg_beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
+ libebg.beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
DEBUG("Setting %s=%s in bootloader environment", name, value);
- if ((ret = ebg_env_open_current(&ebgenv)) != 0) {
+ if ((ret = libebg.env_open_current(&ebgenv)) != 0) {
ERROR("Cannot open current bootloader environment: %s.", strerror(ret));
return ret;
}
@@ -40,73 +54,73 @@ int bootloader_env_set(const char *name, const char *value)
/* Open or create a new environment to reflect
* EFI Boot Guard's representation of SWUpdate's
* recovery_status=in_progress. */
- if ((ret = ebg_env_create_new(&ebgenv)) != 0) {
+ if ((ret = libebg.env_create_new(&ebgenv)) != 0) {
ERROR("Cannot open/create new bootloader environment: %s.",
strerror(ret));
}
} else if (strncmp(name, (char *)STATE_KEY, strlen((char *)STATE_KEY) + 1) == 0) {
/* Map suricatta's update_state_t to EFI Boot Guard's API. */
- if ((ret = ebg_env_setglobalstate(&ebgenv, *value - '0')) != 0) {
+ if ((ret = libebg.env_setglobalstate(&ebgenv, *value - '0')) != 0) {
ERROR("Cannot set %s=%s in bootloader environment.", STATE_KEY, value);
}
} else {
/* A new environment is created if EFI Boot Guard's
* representation of SWUpdate's recovery_status is
* not in_progress. */
- if ((ret = ebg_env_create_new(&ebgenv)) != 0) {
+ if ((ret = libebg.env_create_new(&ebgenv)) != 0) {
ERROR("Cannot open/create new bootloader environment: %s.",
strerror(ret));
return ret;
}
- if ((ret = ebg_env_set(&ebgenv, (char *)name, (char *)value)) != 0) {
+ if ((ret = libebg.env_set(&ebgenv, (char *)name, (char *)value)) != 0) {
ERROR("Cannot set %s=%s in bootloader environment: %s.",
name, value, strerror(ret));
}
}
- (void)ebg_env_close(&ebgenv);
+ (void)libebg.env_close(&ebgenv);
return ret;
}
-int bootloader_env_unset(const char *name)
+static int do_env_unset(const char *name)
{
int ret;
- ebg_beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
+ libebg.beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
- if ((ret = ebg_env_open_current(&ebgenv)) != 0) {
+ if ((ret = libebg.env_open_current(&ebgenv)) != 0) {
ERROR("Cannot open current bootloader environment: %s.", strerror(ret));
return ret;
}
if (strncmp(name, BOOTVAR_TRANSACTION, strlen(name) + 1) == 0) {
- ret = ebg_env_finalize_update(&ebgenv);
+ ret = libebg.env_finalize_update(&ebgenv);
if (ret) {
ERROR("Cannot unset %s in bootloader environment: %s.", BOOTVAR_TRANSACTION, strerror(ret));
}
} else if (strncmp(name, (char *)STATE_KEY, strlen((char *)STATE_KEY) + 1) == 0) {
/* Unsetting STATE_KEY is semantically equivalent to setting it to STATE_OK. */
- if ((ret = ebg_env_setglobalstate(&ebgenv, STATE_OK - '0')) != 0) {
+ if ((ret = libebg.env_setglobalstate(&ebgenv, STATE_OK - '0')) != 0) {
ERROR("Cannot unset %s in bootloader environment.", STATE_KEY);
}
} else {
- ret = ebg_env_set_ex(&ebgenv, (char *)name, USERVAR_TYPE_DELETED, (uint8_t *)"", 1);
+ ret = libebg.env_set_ex(&ebgenv, (char *)name, USERVAR_TYPE_DELETED, (uint8_t *)"", 1);
}
- (void)ebg_env_close(&ebgenv);
+ (void)libebg.env_close(&ebgenv);
return ret;
}
-char *bootloader_env_get(const char *name)
+static char *do_env_get(const char *name)
{
char *value = NULL;
size_t size;
errno = 0;
- ebg_beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
+ libebg.beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
int ret;
- if ((ret = ebg_env_open_current(&ebgenv)) != 0) {
+ if ((ret = libebg.env_open_current(&ebgenv)) != 0) {
ERROR("Cannot open current bootloader environment: %s.",
strerror(ret));
return NULL;
@@ -114,19 +128,19 @@ char *bootloader_env_get(const char *name)
if (strncmp(name, (char *)STATE_KEY, strlen((char *)STATE_KEY) + 1) == 0) {
value = (char *)malloc(sizeof(char));
- *value = ebg_env_getglobalstate(&ebgenv);
+ *value = libebg.env_getglobalstate(&ebgenv);
} else {
- if ((size = ebg_env_get(&ebgenv, (char *)name, NULL)) != 0) {
+ if ((size = libebg.env_get(&ebgenv, (char *)name, NULL)) != 0) {
value = malloc(size);
if (value) {
- if (ebg_env_get(&ebgenv, (char *)name, value) != 0) {
+ if (libebg.env_get(&ebgenv, (char *)name, value) != 0) {
value = NULL;
}
}
}
}
- (void)ebg_env_close(&ebgenv);
+ (void)libebg.env_close(&ebgenv);
if (value == NULL) {
ERROR("Cannot get %s from bootloader environment: %s",
@@ -138,7 +152,7 @@ char *bootloader_env_get(const char *name)
return value;
}
-int bootloader_apply_list(const char *filename)
+static int do_apply_list(const char *filename)
{
FILE *fp = NULL;
char *line = NULL;
@@ -148,7 +162,7 @@ int bootloader_apply_list(const char *filename)
int ret = 0;
errno = 0;
- ebg_beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
+ libebg.beverbose(&ebgenv, loglevel > INFOLEVEL ? true : false);
if (!(fp = fopen(filename, "rb"))) {
ERROR("Failed to open bootloader environment file %s: %s",
@@ -174,3 +188,37 @@ int bootloader_apply_list(const char *filename)
}
return ret;
}
+
+static bootloader ebg = {
+ .env_get = &do_env_get,
+ .env_set = &do_env_set,
+ .env_unset = &do_env_unset,
+ .apply_list = &do_apply_list
+};
+
+static bootloader* probe(void)
+{
+ void* handle = dlopen("libebgenv.so", RTLD_NOW | RTLD_GLOBAL);
+ if (!handle) {
+ return NULL;
+ }
+
+ (void)dlerror();
+ load_symbol(handle, &libebg.beverbose, "ebg_beverbose");
+ load_symbol(handle, &libebg.env_create_new, "ebg_env_create_new");
+ load_symbol(handle, &libebg.env_open_current, "ebg_env_open_current");
+ load_symbol(handle, &libebg.env_get, "ebg_env_get");
+ load_symbol(handle, &libebg.env_set, "ebg_env_set");
+ load_symbol(handle, &libebg.env_set_ex, "ebg_env_set_ex");
+ load_symbol(handle, &libebg.env_getglobalstate, "ebg_env_getglobalstate");
+ load_symbol(handle, &libebg.env_setglobalstate, "ebg_env_setglobalstate");
+ load_symbol(handle, &libebg.env_close, "ebg_env_close");
+ load_symbol(handle, &libebg.env_finalize_update, "ebg_env_finalize_update");
+ return &ebg;
+}
+
+__attribute__((constructor))
+static void ebg_probe(void)
+{
+ (void)register_bootloader("ebg", probe());
+}
@@ -258,7 +258,7 @@ static inline void grubenv_close(struct grubenv_t *grubenv)
/* I feel that '#' and '=' characters should be forbidden. Although it's not
* explicitly mentioned in original grub env code, they may cause unexpected
* behavior */
-int bootloader_env_set(const char *name, const char *value)
+static int do_env_set(const char *name, const char *value)
{
static struct grubenv_t grubenv;
int ret;
@@ -280,7 +280,7 @@ cleanup:
return ret;
}
-int bootloader_env_unset(const char *name)
+static int do_env_unset(const char *name)
{
static struct grubenv_t grubenv;
int ret = 0;
@@ -301,7 +301,7 @@ cleanup:
return ret;
}
-char *bootloader_env_get(const char *name)
+static char *do_env_get(const char *name)
{
static struct grubenv_t grubenv;
char *value = NULL, *var;
@@ -322,7 +322,7 @@ cleanup:
}
-int bootloader_apply_list(const char *script)
+static int do_apply_list(const char *script)
{
static struct grubenv_t grubenv;
int ret = 0;
@@ -343,3 +343,16 @@ cleanup:
grubenv_close(&grubenv);
return ret;
}
+
+static bootloader grub = {
+ .env_get = &do_env_get,
+ .env_set = &do_env_set,
+ .env_unset = &do_env_unset,
+ .apply_list = &do_apply_list
+};
+
+__attribute__((constructor))
+static void grub_probe(void)
+{
+ (void)register_bootloader("grub", &grub);
+}
@@ -12,7 +12,7 @@
static struct dict environment;
-int bootloader_env_set(const char *name,
+static int do_env_set(const char *name,
const char *value)
{
dict_set_value(&environment, name, value);
@@ -20,14 +20,14 @@ int bootloader_env_set(const char *name,
return 0;
}
-int bootloader_env_unset(const char *name)
+static int do_env_unset(const char *name)
{
dict_remove(&environment, name);
return 0;
}
-char *bootloader_env_get(const char *name)
+static char *do_env_get(const char *name)
{
char *value = NULL, *var;
@@ -39,7 +39,20 @@ char *bootloader_env_get(const char *name)
return value;
}
-int bootloader_apply_list(const char *filename)
+static int do_apply_list(const char *filename)
{
return dict_parse_script(&environment, filename);
}
+
+static bootloader none = {
+ .env_get = &do_env_get,
+ .env_set = &do_env_set,
+ .env_unset = &do_env_unset,
+ .apply_list = &do_apply_list
+};
+
+__attribute__((constructor))
+static void none_probe(void)
+{
+ (void)register_bootloader("none", &none);
+}
@@ -17,6 +17,7 @@
#include <dirent.h>
#include "generated/autoconf.h"
#include "util.h"
+#include "dlfcn.h"
#include "bootloader.h"
#include <libuboot.h>
@@ -24,19 +25,31 @@
#define CONFIG_UBOOT_DEFAULTENV "/etc/u-boot-initial-env"
#endif
+static struct {
+ int (*open)(struct uboot_ctx*);
+ void (*close)(struct uboot_ctx *ctx);
+ void (*exit)(struct uboot_ctx *ctx);
+ int (*initialize)(struct uboot_ctx **out, struct uboot_env_device *envdevs);
+ char* (*get_env)(struct uboot_ctx *ctx, const char *varname);
+ int (*read_config)(struct uboot_ctx *ctx, const char *config);
+ int (*load_file)(struct uboot_ctx *ctx, const char *filename);
+ int (*set_env)(struct uboot_ctx *ctx, const char *varname, const char *value);
+ int (*env_store)(struct uboot_ctx *ctx);
+} libuboot;
+
static int bootloader_initialize(struct uboot_ctx **ctx)
{
- if (libuboot_initialize(ctx, NULL) < 0) {
+ if (libuboot.initialize(ctx, NULL) < 0) {
ERROR("Error: environment not initialized");
return -ENODEV;
}
- if (libuboot_read_config(*ctx, CONFIG_UBOOT_FWENV) < 0) {
+ if (libuboot.read_config(*ctx, CONFIG_UBOOT_FWENV) < 0) {
ERROR("Configuration file %s wrong or corrupted", CONFIG_UBOOT_FWENV);
return -EINVAL;
}
- if (libuboot_open(*ctx) < 0) {
+ if (libuboot.open(*ctx) < 0) {
WARN("Cannot read environment, using default");
- if (libuboot_load_file(*ctx, CONFIG_UBOOT_DEFAULTENV) < 0) {
+ if (libuboot.load_file(*ctx, CONFIG_UBOOT_DEFAULTENV) < 0) {
ERROR("Error: Cannot read default environment from file");
return -ENODATA;
}
@@ -45,47 +58,47 @@ static int bootloader_initialize(struct uboot_ctx **ctx)
return 0;
}
-int bootloader_env_set(const char *name, const char *value)
+static int do_env_set(const char *name, const char *value)
{
int ret;
struct uboot_ctx *ctx = NULL;
ret = bootloader_initialize(&ctx);
if (!ret) {
- libuboot_set_env(ctx, name, value);
- ret = libuboot_env_store(ctx);
+ libuboot.set_env(ctx, name, value);
+ ret = libuboot.env_store(ctx);
}
- libuboot_close(ctx);
- libuboot_exit(ctx);
+ libuboot.close(ctx);
+ libuboot.exit(ctx);
return ret;
}
-int bootloader_env_unset(const char *name)
+static int do_env_unset(const char *name)
{
- return bootloader_env_set(name, NULL);
+ return do_env_set(name, NULL);
}
-int bootloader_apply_list(const char *filename)
+static int do_apply_list(const char *filename)
{
int ret;
struct uboot_ctx *ctx = NULL;
ret = bootloader_initialize(&ctx);
if (!ret) {
- libuboot_load_file(ctx, filename);
- ret = libuboot_env_store(ctx);
+ libuboot.load_file(ctx, filename);
+ ret = libuboot.env_store(ctx);
}
- libuboot_close(ctx);
- libuboot_exit(ctx);
+ libuboot.close(ctx);
+ libuboot.exit(ctx);
return ret;
}
-char *bootloader_env_get(const char *name)
+static char *do_env_get(const char *name)
{
int ret;
struct uboot_ctx *ctx = NULL;
@@ -93,10 +106,43 @@ char *bootloader_env_get(const char *name)
ret = bootloader_initialize(&ctx);
if (!ret) {
- value = libuboot_get_env(ctx, name);
+ value = libuboot.get_env(ctx, name);
}
- libuboot_close(ctx);
- libuboot_exit(ctx);
+ libuboot.close(ctx);
+ libuboot.exit(ctx);
return value;
}
+
+static bootloader uboot = {
+ .env_get = &do_env_get,
+ .env_set = &do_env_set,
+ .env_unset = &do_env_unset,
+ .apply_list = &do_apply_list
+};
+
+static bootloader* probe(void)
+{
+ void* handle = dlopen("libubootenv.so", RTLD_NOW | RTLD_GLOBAL);
+ if (!handle) {
+ return NULL;
+ }
+
+ (void)dlerror();
+ load_symbol(handle, &libuboot.open, "libuboot_open");
+ load_symbol(handle, &libuboot.close, "libuboot_close");
+ load_symbol(handle, &libuboot.exit, "libuboot_exit");
+ load_symbol(handle, &libuboot.initialize, "libuboot_initialize");
+ load_symbol(handle, &libuboot.get_env, "libuboot_get_env");
+ load_symbol(handle, &libuboot.read_config, "libuboot_read_config");
+ load_symbol(handle, &libuboot.load_file, "libuboot_load_file");
+ load_symbol(handle, &libuboot.set_env, "libuboot_set_env");
+ load_symbol(handle, &libuboot.env_store, "libuboot_env_store");
+ return &uboot;
+}
+
+__attribute__((constructor))
+static void uboot_probe(void)
+{
+ (void)register_bootloader("uboot", probe());
+}
Adopt the bootloader interface implementations to the runtime-dynamic bootloader selection mechanism. Signed-off-by: Christian Storm <christian.storm@siemens.com> --- bootloader/ebg.c | 96 ++++++++++++++++++++++++++++++++++------------ bootloader/grub.c | 21 ++++++++-- bootloader/none.c | 21 ++++++++-- bootloader/uboot.c | 86 +++++++++++++++++++++++++++++++---------- 4 files changed, 172 insertions(+), 52 deletions(-)