From: Reichel Andreas <
andreas.r...@siemens.com>
* Refactor API
Provide one function to set and one to get the global update state
instead of six different.
Improve code quality and use a context for API functions instead of
hidden static global variables.
* env: Remove BGENVTYPE from code
Since different storage backends come with different .c files, there
is no need for switch cases.
* move some functions to simplify API dependencies
* remove ebgdefs.h, since it only included one define, which better
fits into the envdata.h
* Add a ebgenv_t structure as a context for all ebg_ API functions.
This provides better maintainability and future extensibility.
It helps avoiding ugly global variables.
One might argue that a context implicitly suggests multi-threading
capability and needs an implementation for access scheduling for
multiple environment accesses at the same time, however, the
introduction of a better coding style per se is independent of this
idea and all functions remain unsafe regarding threads.
* Update tests
docs/API.md | 20 ++-
env/env_api_fat.c | 294 +++++++++++++++++++++++++---------
env/fatvars.c | 1 -
include/ebgdefs.h | 20 ---
include/env_api.h | 30 ++--
include/envdata.h | 2 +
swupdate-adapter/ebgenv.c | 398 ++++++++--------------------------------------
swupdate-adapter/ebgenv.h | 78 +++++----
tools/bg_setenv.c | 14 +-
tools/tests/Makefile | 2 +-
tools/tests/test_api.c | 128 ++++++++-------
11 files changed, 431 insertions(+), 556 deletions(-)
delete mode 100644 include/ebgdefs.h
diff --git a/docs/API.md b/docs/API.md
index 8778b70..3da00b3 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -42,11 +42,13 @@ and sets it to the testing state:
int main(void)
{
- ebg_env_create_new();
- ebg_env_set("kernelfile", "vmlinux-new");
- ebg_env_set("kernelparams", "root=/dev/bootdevice");
- ebg_env_set("watchdog_timeout_sec", "30");
- ebg_env_close();
+ ebgenv_t e;
+
+ ebg_env_create_new(&e);
+ ebg_env_set(&e, "kernelfile", "vmlinux-new");
+ ebg_env_set(&e, "kernelparams", "root=/dev/bootdevice");
+ ebg_env_set(&e, "watchdog_timeout_sec", "30");
+ ebg_env_close(&e);
return 0;
}
```
@@ -66,9 +68,11 @@ modifies the kernel file name:
int main(void)
{
- ebg_env_open_current();
- ebg_env_set("kernelfile", "vmlinux-new");
- ebg_env_close();
+ ebgenv_t e;
+
+ ebg_env_open_current(&e);
+ ebg_env_set(&e, "kernelfile", "vmlinux-new");
+ ebg_env_close(&e);
return 0;
}
```
diff --git a/env/env_api_fat.c b/env/env_api_fat.c
index bed74d9..24235c0 100644
--- a/env/env_api_fat.c
+++ b/env/env_api_fat.c
@@ -18,6 +18,27 @@ const char *tmp_mnt_dir = "/tmp/mnt-XXXXXX";
static bool verbosity = false;
+static EBGENVKEY bgenv_str2enum(char *key)
+{
+ if (strncmp(key, "kernelfile", strlen("kernelfile") + 1) == 0) {
+ return EBGENV_KERNELFILE;
+ }
+ if (strncmp(key, "kernelparams", strlen("kernelparams") + 1) == 0) {
+ return EBGENV_KERNELPARAMS;
+ }
+ if (strncmp(key, "watchdog_timeout_sec",
+ strlen("watchdog_timeout_sec") + 1) == 0) {
+ return EBGENV_WATCHDOG_TIMEOUT_SEC;
+ }
+ if (strncmp(key, "revision", strlen("revision") + 1) == 0) {
+ return EBGENV_REVISION;
+ }
+ if (strncmp(key, "ustate", strlen("ustate") + 1) == 0) {
+ return EBGENV_USTATE;
+ }
+ return EBGENV_UNKNOWN;
+}
+
void be_verbose(bool v)
{
verbosity = v;
@@ -348,89 +369,72 @@ bool write_env(CONFIG_PART *part, BG_ENVDATA *env)
return result;
}
-CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
-BG_ENVDATA oldenvs[ENV_NUM_CONFIG_PARTS];
+static CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
+static BG_ENVDATA oldenvs[ENV_NUM_CONFIG_PARTS];
-bool bgenv_init(BGENVTYPE type)
+bool bgenv_init()
{
- switch (type) {
- case BGENVTYPE_FAT:
- memset((void *)&config_parts, 0,
- sizeof(CONFIG_PART) * ENV_NUM_CONFIG_PARTS);
- /* enumerate all config partitions */
- if (!probe_config_partitions(config_parts)) {
- VERBOSE(stderr, "Error finding config partitions.\n");
- return false;
- }
- for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
- read_env(&config_parts[i], &oldenvs[i]);
- uint32_t sum = crc32(0, (Bytef *)&oldenvs[i],
- sizeof(BG_ENVDATA) - sizeof(oldenvs[i].crc32));
- if (oldenvs[i].crc32 != sum) {
- VERBOSE(stderr, "Invalid CRC32!\n");
- continue;
- }
+ memset((void *)&config_parts, 0,
+ sizeof(CONFIG_PART) * ENV_NUM_CONFIG_PARTS);
+ /* enumerate all config partitions */
+ if (!probe_config_partitions(config_parts)) {
+ VERBOSE(stderr, "Error finding config partitions.\n");
+ return false;
+ }
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ read_env(&config_parts[i], &oldenvs[i]);
+ uint32_t sum = crc32(0, (Bytef *)&oldenvs[i],
+ sizeof(BG_ENVDATA) - sizeof(oldenvs[i].crc32));
+ if (oldenvs[i].crc32 != sum) {
+ VERBOSE(stderr, "Invalid CRC32!\n");
+ continue;
}
- return true;
}
- return false;
+ return true;
}
-BGENV *bgenv_get_by_index(BGENVTYPE type, uint32_t index)
+BGENV *bgenv_open_by_index(uint32_t index)
{
BGENV *handle;
- switch (type) {
- case BGENVTYPE_FAT:
- /* get config partition by index and allocate handle */
- if (index >= ENV_NUM_CONFIG_PARTS) {
- return NULL;
- }
- if (!(handle = calloc(1, sizeof(BGENV)))) {
- return NULL;
- }
- handle->desc = (void *)&config_parts[index];
- handle->data = &oldenvs[index];
- handle->type = type;
- return handle;
+ /* get config partition by index and allocate handle */
+ if (index >= ENV_NUM_CONFIG_PARTS) {
+ return NULL;
}
- return NULL;
+ if (!(handle = calloc(1, sizeof(BGENV)))) {
+ return NULL;
+ }
+ handle->desc = (void *)&config_parts[index];
+ handle->data = &oldenvs[index];
+ return handle;
}
-BGENV *bgenv_get_oldest(BGENVTYPE type)
+BGENV *bgenv_open_oldest()
{
uint32_t minrev = 0xFFFFFFFF;
uint32_t min_idx = 0;
- switch (type) {
- case BGENVTYPE_FAT:
- for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
- if (oldenvs[i].revision < minrev) {
- minrev = oldenvs[i].revision;
- min_idx = i;
- }
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ if (oldenvs[i].revision < minrev) {
+ minrev = oldenvs[i].revision;
+ min_idx = i;
}
- return bgenv_get_by_index(type, min_idx);
}
- return NULL;
+ return bgenv_open_by_index(min_idx);
}
-BGENV *bgenv_get_latest(BGENVTYPE type)
+BGENV *bgenv_open_latest()
{
uint32_t maxrev = 0;
uint32_t max_idx = 0;
- switch (type) {
- case BGENVTYPE_FAT:
- for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
- if (oldenvs[i].revision > maxrev) {
- maxrev = oldenvs[i].revision;
- max_idx = i;
- }
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ if (oldenvs[i].revision > maxrev) {
+ maxrev = oldenvs[i].revision;
+ max_idx = i;
}
- return bgenv_get_by_index(type, max_idx);
}
- return NULL;
+ return bgenv_open_by_index(max_idx);
}
bool bgenv_write(BGENV *env)
@@ -440,23 +444,19 @@ bool bgenv_write(BGENV *env)
if (!env) {
return false;
}
- switch (env->type) {
- case BGENVTYPE_FAT:
- part = (CONFIG_PART *)env->desc;
- if (!part) {
- VERBOSE(
- stderr,
- "Invalid config partition to store environment.\n");
- return false;
- }
- if (!write_env(part, env->data)) {
- VERBOSE(stderr, "Could not write to %s\n",
- part->devpath);
- return false;
- }
- return true;
+ part = (CONFIG_PART *)env->desc;
+ if (!part) {
+ VERBOSE(
+ stderr,
+ "Invalid config partition to store environment.\n");
+ return false;
}
- return false;
+ if (!write_env(part, env->data)) {
+ VERBOSE(stderr, "Could not write to %s\n",
+ part->devpath);
+ return false;
+ }
+ return true;
}
BG_ENVDATA *bgenv_read(BGENV *env)
@@ -475,3 +475,151 @@ bool bgenv_close(BGENV *env)
}
return false;
}
+
+int bgenv_get(BGENV *env, char *key, char **type, void *data, size_t maxlen)
+{
+ EBGENVKEY e;
+
+ if (!key || !data || maxlen == 0) {
+ return EINVAL;
+ }
+ e = bgenv_str2enum(key);
+ if (e == EBGENV_UNKNOWN) {
+ return EINVAL;
+ }
+ if (!env) {
+ return EPERM;
+ }
+ switch (e) {
+ case EBGENV_KERNELFILE:
+ str16to8(data, env->data->kernelfile);
+ if (type) {
+ sprintf(*type, "char*");
+ }
+ break;
+ case EBGENV_KERNELPARAMS:
+ str16to8(data, env->data->kernelparams);
+ if (type) {
+ sprintf(*type, "char*");
+ }
+ break;
+ case EBGENV_WATCHDOG_TIMEOUT_SEC:
+ sprintf(data, "%lu", env->data->watchdog_timeout_sec);
+ if (type) {
+ sprintf(*type, "uint16_t");
+ }
+ break;
+ case EBGENV_REVISION:
+ sprintf(data, "%lu", env->data->revision);
+ if (type) {
+ sprintf(*type, "uint32_t");
+ }
+ break;
+ case EBGENV_USTATE:
+ sprintf(data, "%u", env->data->ustate);
+ if (type) {
+ sprintf(*type, "uint16_t");
+ }
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+int bgenv_set(BGENV *env, char *key, char *type, void *data, size_t datalen)
+{
+ EBGENVKEY e;
+ int val;
+ char *p;
+ char *value = (char *)data;
+
+ if (!key || !data || datalen == 0) {
+ return EINVAL;
+ }
+
+ e = bgenv_str2enum(key);
+ if (e == EBGENV_UNKNOWN) {
+ return EINVAL;
+ }
+ if (!env) {
+ return EPERM;
+ }
+ switch (e) {
+ case EBGENV_REVISION:
+ val = strtol(value, &p, 10);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0)) {
+ return errno;
+ }
+ if (p == value) {
+ return EINVAL;
+ }
+ env->data->revision = val;
+ break;
+ case EBGENV_KERNELFILE:
+ str8to16(env->data->kernelfile, value);
+ break;
+ case EBGENV_KERNELPARAMS:
+ str8to16(env->data->kernelparams, value);
+ break;
+ case EBGENV_WATCHDOG_TIMEOUT_SEC:
+ val = strtol(value, &p, 10);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0)) {
+ return errno;
+ }
+ if (p == value) {
+ return EINVAL;
+ }
+ env->data->watchdog_timeout_sec = val;
+ break;
+ case EBGENV_USTATE:
+ val = strtol(value, &p, 10);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0)) {
+ return errno;
+ }
+ if (p == value) {
+ return EINVAL;
+ }
+ env->data->ustate = val;
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+BGENV *bgenv_create_new()
+{
+ BGENV *env_latest;
+ BGENV *env_new;
+
+ env_latest = bgenv_open_latest();
+ if (!env_latest)
+ goto create_new_io_error;
+
+ int new_rev = env_latest->data->revision + 1;
+
+ if (!bgenv_close(env_latest))
+ goto create_new_io_error;
+
+ env_new = bgenv_open_oldest();
+ if (!env_new)
+ goto create_new_io_error;
+
+ /* zero fields */
+ memset(env_new->data, 0, sizeof(BG_ENVDATA));
+ /* update revision field and testing mode */
+ env_new->data->revision = new_rev;
+ env_new->data->ustate = 1;
+ /* set default watchdog timeout */
+ env_new->data->watchdog_timeout_sec = 30;
+
+ return env_new;
+
+create_new_io_error:
+ errno = EIO;
+ return NULL;
+}
diff --git a/env/fatvars.c b/env/fatvars.c
index 8f871b9..5d391c7 100644
--- a/env/fatvars.c
+++ b/env/fatvars.c
@@ -11,7 +11,6 @@
*/
#include <bootguard.h>
-#include <ebgdefs.h>
#include <syspart.h>
#include <envdata.h>
diff --git a/include/ebgdefs.h b/include/ebgdefs.h
deleted file mode 100644
index 4327d45..0000000
--- a/include/ebgdefs.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/** @file
- *
- * EFI Boot Guard
- *
- * Copyright (c) Siemens AG, 2017
- *
- * Authors:
- * Andreas Reichel <
andreas.r...@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef __EFI_BOOT_GUARD_DEFS_H__
-#define __EFI_BOOT_GUARD_DEFS_H__
-
-#define REVISION_FAILED 0
-
-#endif
diff --git a/include/env_api.h b/include/env_api.h
index 83c7123..dc53ae4 100644
--- a/include/env_api.h
+++ b/include/env_api.h
@@ -10,8 +10,8 @@
* the COPYING file in the top-level directory.
*/
-#ifndef __BG_UTILS_H__
-#define __BG_UTILS_H__
+#ifndef __ENV_API_H__
+#define __ENV_API_H__
#include <stddef.h>
#include <stdint.h>
@@ -42,7 +42,14 @@
if (verbosity) \
fprintf(o, __VA_ARGS__)
-typedef enum { BGENVTYPE_FAT } BGENVTYPE;
+typedef enum {
+ EBGENV_KERNELFILE,
+ EBGENV_KERNELPARAMS,
+ EBGENV_WATCHDOG_TIMEOUT_SEC,
+ EBGENV_REVISION,
+ EBGENV_USTATE,
+ EBGENV_UNKNOWN
+} EBGENVKEY;
typedef struct {
char *devpath;
@@ -51,7 +58,6 @@ typedef struct {
} CONFIG_PART;
typedef struct {
- BGENVTYPE type;
void *desc;
BG_ENVDATA *data;
} BGENV;
@@ -61,12 +67,18 @@ extern void be_verbose(bool v);
extern char *str16to8(char *buffer, wchar_t *src);
extern wchar_t *str8to16(wchar_t *buffer, char *src);
-extern bool bgenv_init(BGENVTYPE type);
-extern BGENV *bgenv_get_by_index(BGENVTYPE type, uint32_t index);
-extern BGENV *bgenv_get_oldest(BGENVTYPE type);
-extern BGENV *bgenv_get_latest(BGENVTYPE type);
+extern bool bgenv_init(void);
+extern BGENV *bgenv_open_by_index(uint32_t index);
+extern BGENV *bgenv_open_oldest(void);
+extern BGENV *bgenv_open_latest(void);
extern bool bgenv_write(BGENV *env);
extern BG_ENVDATA *bgenv_read(BGENV *env);
extern bool bgenv_close(BGENV *env);
-#endif // __BG_UTILS_H__
+extern BGENV *bgenv_create_new(void);
+extern int bgenv_get(BGENV *env, char *key, char **type, void *data,
+ size_t maxlen);
+extern int bgenv_set(BGENV *env, char *key, char *type, void *data,
+ size_t datalen);
+
+#endif // __ENV_API_H__
diff --git a/include/envdata.h b/include/envdata.h
index 78dda9b..3f1fb38 100644
--- a/include/envdata.h
+++ b/include/envdata.h
@@ -27,6 +27,8 @@
#define USTATE_MIN 0
#define USTATE_MAX 4
+#define REVISION_FAILED 0
+
#pragma pack(push)
#pragma pack(1)
struct _BG_ENVDATA {
diff --git a/swupdate-adapter/ebgenv.c b/swupdate-adapter/ebgenv.c
index 115e0a9..9b4e0c4 100644
--- a/swupdate-adapter/ebgenv.c
+++ b/swupdate-adapter/ebgenv.c
@@ -11,403 +11,133 @@
*/
#include "env_api.h"
-#include "ebgdefs.h"
#include "ebgenv.h"
-typedef enum {
- EBGENV_KERNELFILE,
- EBGENV_KERNELPARAMS,
- EBGENV_WATCHDOG_TIMEOUT_SEC,
- EBGENV_REVISION,
- EBGENV_USTATE,
- EBGENV_UNKNOWN
-} EBGENVKEY;
-
-static BGENV *env_current = NULL;
-
-typedef struct _PCOLLECTOR {
- void *p;
- struct _PCOLLECTOR *next;
-} PCOLLECTOR;
-
-static PCOLLECTOR ebg_gc;
-
-static bool ebg_new_env_created = false;
-
-static bool ebg_gc_addpointer(void *pnew)
-{
- PCOLLECTOR *pc = &ebg_gc;
-
- while (pc->next) {
- pc = pc->next;
- }
- pc->next = calloc(sizeof(PCOLLECTOR), 1);
- if (!pc->next) {
- return false;
- }
- pc = pc->next;
- pc->p = pnew;
- return true;
-}
-
-static void ebg_gc_cleanup()
-{
- PCOLLECTOR *pc = &ebg_gc;
-
- while (pc) {
- if (pc->p) {
- free(pc->p);
- }
- PCOLLECTOR *tmp = pc;
- pc = pc->next;
- if (tmp != &ebg_gc) {
- free(tmp);
- }
- }
- ebg_gc.p = NULL;
- ebg_gc.next = NULL;
-}
-
-static EBGENVKEY ebg_env_str2enum(char *key)
-{
- if (strncmp(key, "kernelfile", strlen("kernelfile") + 1) == 0) {
- return EBGENV_KERNELFILE;
- }
- if (strncmp(key, "kernelparams", strlen("kernelparams") + 1) == 0) {
- return EBGENV_KERNELPARAMS;
- }
- if (strncmp(key, "watchdog_timeout_sec",
- strlen("watchdog_timeout_sec") + 1) == 0) {
- return EBGENV_WATCHDOG_TIMEOUT_SEC;
- }
- if (strncmp(key, "revision", strlen("revision") + 1) == 0) {
- return EBGENV_REVISION;
- }
- if (strncmp(key, "ustate", strlen("ustate") + 1) == 0) {
- return EBGENV_USTATE;
- }
- return EBGENV_UNKNOWN;
-}
-
-void ebg_beverbose(bool v)
+void ebg_beverbose(ebgenv_t *e, bool v)
{
be_verbose(v);
}
-int ebg_env_create_new(void)
+int ebg_env_create_new(ebgenv_t *e)
{
- /* initialize garbage collector */
- ebg_gc.p = NULL;
- ebg_gc.next = NULL;
-
- if (!bgenv_init(BGENVTYPE_FAT)) {
+ if (!bgenv_init()) {
return EIO;
}
- env_current = bgenv_get_latest(BGENVTYPE_FAT);
-
- if (ebg_new_env_created)
- return env_current == NULL ? EIO : 0;
-
- if (!env_current) {
- return EIO;
+ if (!e->ebg_new_env_created) {
+ e->bgenv = (void *)bgenv_create_new();
}
- /* first time env is opened, a new one is created for update
- * purpose */
- int new_rev = env_current->data->revision + 1;
- if (!bgenv_close(env_current)) {
- return EIO;
- }
- env_current = bgenv_get_oldest(BGENVTYPE_FAT);
- if (!env_current) {
- return EIO;
- }
- /* zero fields */
- memset(env_current->data, 0, sizeof(BG_ENVDATA));
- /* update revision field and testing mode */
- env_current->data->revision = new_rev;
- env_current->data->ustate = USTATE_INSTALLED;
- /* set default watchdog timeout */
- env_current->data->watchdog_timeout_sec = 30;
- ebg_new_env_created = true;
+ e->ebg_new_env_created = e->bgenv != NULL;
- return env_current == NULL ? EIO : 0;
+ return e->bgenv == NULL ? errno : 0;
}
-int ebg_env_open_current(void)
+int ebg_env_open_current(ebgenv_t *e)
{
- /* initialize garbage collector */
- ebg_gc.p = NULL;
- ebg_gc.next = NULL;
-
- if (!bgenv_init(BGENVTYPE_FAT)) {
+ if (!bgenv_init()) {
return EIO;
}
- env_current = bgenv_get_latest(BGENVTYPE_FAT);
+ e->bgenv = (void *)bgenv_open_latest();
- return env_current == NULL ? EIO : 0;
+ return e->bgenv == NULL ? EIO : 0;
}
-char *ebg_env_get(char *key)
+int ebg_env_get(ebgenv_t *e, char *key, char *buffer)
{
- EBGENVKEY e;
- char *buffer;
-
- if (!key) {
- errno = EINVAL;
- return NULL;
- }
- e = ebg_env_str2enum(key);
- if (e == EBGENV_UNKNOWN) {
- errno = EINVAL;
- return NULL;
- }
- if (!env_current) {
- errno = EPERM;
- return NULL;
- }
- switch (e) {
- case EBGENV_KERNELFILE:
- buffer = (char *)malloc(ENV_STRING_LENGTH);
- if (!buffer) {
- errno = ENOMEM;
- return NULL;
- }
- if (!ebg_gc_addpointer(buffer)) {
- errno = ENOMEM;
- return NULL;
- };
- str16to8(buffer, env_current->data->kernelfile);
- return buffer;
- case EBGENV_KERNELPARAMS:
- buffer = (char *)malloc(ENV_STRING_LENGTH);
- if (!buffer) {
- errno = ENOMEM;
- return NULL;
- }
- if (!ebg_gc_addpointer(buffer)) {
- errno = ENOMEM;
- return NULL;
- }
- str16to8(buffer, env_current->data->kernelparams);
- return buffer;
- case EBGENV_WATCHDOG_TIMEOUT_SEC:
- if (asprintf(&buffer, "%lu",
- env_current->data->watchdog_timeout_sec) < 0) {
- errno = ENOMEM;
- return NULL;
- }
- if (!ebg_gc_addpointer(buffer)) {
- errno = ENOMEM;
- return NULL;
- }
- return buffer;
- case EBGENV_REVISION:
- if (asprintf(&buffer, "%lu", env_current->data->revision) < 0) {
- errno = ENOMEM;
- return NULL;
- }
- if (!ebg_gc_addpointer(buffer)) {
- errno = ENOMEM;
- return NULL;
- }
- return buffer;
- case EBGENV_USTATE:
- if (asprintf(&buffer, "%u", env_current->data->ustate) < 0) {
- errno = ENOMEM;
- return NULL;
- }
- if (!ebg_gc_addpointer(buffer)) {
- errno = ENOMEM;
- return NULL;
- }
- return buffer;
- default:
- errno = EINVAL;
- return NULL;
- }
- errno = EINVAL;
- return NULL;
+ return bgenv_get((BGENV *)e->bgenv, key, NULL, buffer,
+ ENV_STRING_LENGTH);
}
-int ebg_env_set(char *key, char *value)
+int ebg_env_set(ebgenv_t *e, char *key, char *value)
{
- EBGENVKEY e;
- int val;
- char *p;
-
- if (!key || !value) {
- return EINVAL;
- }
- e = ebg_env_str2enum(key);
- if (e == EBGENV_UNKNOWN) {
- return EINVAL;
- }
- if (!env_current) {
- return EPERM;
- }
- switch (e) {
- case EBGENV_REVISION:
- errno = 0;
- val = strtol(value, &p, 10);
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
- (errno != 0 && val == 0)) {
- return errno;
- }
- if (p == value) {
- return EINVAL;
- }
- env_current->data->revision = val;
- break;
- case EBGENV_KERNELFILE:
- str8to16(env_current->data->kernelfile, value);
- break;
- case EBGENV_KERNELPARAMS:
- str8to16(env_current->data->kernelparams, value);
- break;
- case EBGENV_WATCHDOG_TIMEOUT_SEC:
- errno = 0;
- val = strtol(value, &p, 10);
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
- (errno != 0 && val == 0)) {
- return errno;
- }
- if (p == value) {
- return EINVAL;
- }
- env_current->data->watchdog_timeout_sec = val;
- break;
- case EBGENV_USTATE:
- errno = 0;
- val = strtol(value, &p, 10);
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
- (errno != 0 && val == 0)) {
- return errno;
- }
- if (p == value) {
- return EINVAL;
- }
- env_current->data->ustate = val;
- break;
- default:
- return EINVAL;
- }
- return 0;
-}
+ return bgenv_set((BGENV *)e->bgenv, key, "String", value,
+ strlen(value)); }
-bool ebg_env_isupdatesuccessful(void)
+uint16_t ebg_env_getglobalstate(ebgenv_t *e)
{
+ BGENV *env;
+ int res = 4;
+
/* find all environments with revision 0 */
for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
- BGENV *env = bgenv_get_by_index(BGENVTYPE_FAT, i);
+ BGENV *env = bgenv_open_by_index(i);
if (!env) {
continue;
}
- /* update was unsuccessful if there is a revision 0 config,
- * with
- * testing and boot_once set */
+ /* update was unsuccessful if there is a config,
+ * with revision == REVISION_FAILED and
+ * with ustate == USTATE_FAILED */
if (env->data->revision == REVISION_FAILED &&
env->data->ustate == USTATE_FAILED) {
(void)bgenv_close(env);
- return false;
+ res = 3;
}
(void)bgenv_close(env);
- }
- return true;
-}
-
-int ebg_env_clearerrorstate(void)
-{
- for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
- BGENV *env = bgenv_get_by_index(BGENVTYPE_FAT, i);
-
- if (!env) {
- continue;
- }
- if (env->data->revision == REVISION_FAILED &&
- env->data->ustate == USTATE_FAILED) {
- env->data->ustate = USTATE_OK;
- if (!bgenv_write(env)) {
- (void)bgenv_close(env);
- return EIO;
- }
- }
- if (!bgenv_close(env)) {
- return EIO;
+ if (res == 3) {
+ return res;
}
}
- return 0;
-}
-int ebg_env_confirmupdate(void)
-{
- return ebg_env_set("ustate", "0");
-}
-
-bool ebg_env_isokay(void)
-{
- BGENV *env;
- bool res = false;
-
- env = bgenv_get_latest(BGENVTYPE_FAT);
+ env = bgenv_open_latest();
if (!env) {
errno = EIO;
return res;
}
- if (env->data->ustate == USTATE_OK) {
- res = true;
- }
+
+ res = env->data->ustate;
bgenv_close(env);
+
return res;
}
-bool ebg_env_isinstalled(void)
+int ebg_env_setglobalstate(ebgenv_t *e, uint16_t ustate)
{
- BGENV *env;
- bool res = false;
+ char buffer[2];
+ int res;
- env = bgenv_get_latest(BGENVTYPE_FAT);
- if (!env) {
- errno = EIO;
- return res;
- }
- if (env->data->ustate == USTATE_INSTALLED) {
- res = true;
+ if (ustate > USTATE_FAILED) {
+ return EINVAL;
}
- bgenv_close(env);
- return res;
-}
-
-bool ebg_env_istesting(void)
-{
- BGENV *env;
- bool res = false;
+ snprintf(buffer, sizeof(buffer), "%d", ustate);
+ res =
+ bgenv_set((BGENV *)e->bgenv, "ustate", "String", buffer,
+ strlen(buffer));
- env = bgenv_get_latest(BGENVTYPE_FAT);
- if (!env) {
- errno = EIO;
+ if (ustate != USTATE_OK) {
return res;
}
- if (env->data->ustate == USTATE_TESTING) {
- res = true;
+
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ BGENV *env = bgenv_open_by_index(i);
+
+ if (!env) {
+ continue;
+ }
+ env->data->ustate = ustate;
+ if (!bgenv_write(env)) {
+ (void)bgenv_close(env);
+ return EIO;
+ }
+ if (!bgenv_close(env)) {
+ return EIO;
+ }
}
- bgenv_close(env);
- return res;
+ return 0;
}
-int ebg_env_close(void)
+int ebg_env_close(ebgenv_t *e)
{
- /* free all allocated memory */
- ebg_gc_cleanup();
-
/* if no environment is open, just return EIO */
- if (!env_current) {
+ if (!e->bgenv) {
return EIO;
}
+ BGENV *env_current;
+ env_current = (BGENV *)e->bgenv;
+
/* recalculate checksum */
env_current->data->crc32 =
crc32(0, (Bytef *)env_current->data,
@@ -420,6 +150,6 @@ int ebg_env_close(void)
if (!bgenv_close(env_current)) {
return EIO;
}
- env_current = NULL;
+ e->bgenv = NULL;
return 0;
}
diff --git a/swupdate-adapter/ebgenv.h b/swupdate-adapter/ebgenv.h
index 97c23db..fb3e809 100644
--- a/swupdate-adapter/ebgenv.h
+++ b/swupdate-adapter/ebgenv.h
@@ -17,74 +17,68 @@
#include <errno.h>
+typedef struct {
+ void *bgenv;
+ bool ebg_new_env_created;
+} ebgenv_t;
+
/** @brief Tell the library to output information for the user.
+ * @param e A pointer to an ebgenv_t context.
+ * @param v A boolean to set verbosity.
*/
-void ebg_beverbose(bool v);
+void ebg_beverbose(ebgenv_t *e, bool v);
/** @brief Initialize environment library and open environment. The first
- * time this function is called, it will create a new environment with the
- * highest revision number for update purposes. Every next time it will
- * just open the environment with the highest revision number.
+ * time this function is called, it will create a new environment with
+ * the highest revision number for update purposes. Every next time it
+ * will just open the environment with the highest revision number.
+ * @param e A pointer to an ebgenv_t context.
* @return 0 on success, errno on failure
*/
-int ebg_env_create_new(void);
+int ebg_env_create_new(ebgenv_t *e);
/** @brief Initialize environment library and open current environment.
+ * @param e A pointer to an ebgenv_t context.
* @return 0 on success, errno on failure
*/
-int ebg_env_open_current(void);
+int ebg_env_open_current(ebgenv_t *e);
/** @brief Retrieve variable content
+ * @param e A pointer to an ebgenv_t context.
* @param key an enum constant to specify the variable
- * @return a pointer to the buffer with the variable content on success,
- * NULL on failure. The returned pointer must not be freed and is freed
- * automatically on closing the environment. If NULL is returned, errno is
- * set.
+ * @param buffer pointer to buffer containing requested value
+ * @return 0 on success, errno on failure
*/
-char *ebg_env_get(char *key);
+int ebg_env_get(ebgenv_t *e, char *key, char* buffer);
/** @brief Store new content into variable
+ * @param e A pointer to an ebgenv_t context.
* @param key name of the environment variable to set
* @param value a string to be stored into the variable
* @return 0 on success, errno on failure
*/
-int ebg_env_set(char *key, char *value);
-
-/** @brief Check if last update was successful
- * @return true if successful, false if not
- */
-bool ebg_env_isupdatesuccessful(void);
-
-/** @brief Reset all stored failure states
- * @return 0 if successful, errno on failure
- */
-int ebg_env_clearerrorstate(void);
-
-/** @brief Check if active env is clean
- * @return true if yes, errno set on failure
- */
-bool ebg_env_isokay(void);
-
-/** @brief Check if active env has state 'installed'
- * @return true if yes, errno set on failure
- */
-bool ebg_env_isinstalled(void);
+int ebg_env_set(ebgenv_t *e, char *key, char *value);
-/** @brief Check if active env is in testing state
- * @return true if yes, errno set on failure
+/** @brief Get global ustate value, accounting for all environments
+ * @param e A pointer to an ebgenv_t context.
+ * @return ustate value
*/
-bool ebg_env_istesting(void);
+uint16_t ebg_env_getglobalstate(ebgenv_t *e);
-/** @brief Confirm environment after update - sets testing and boot_once
- * both to 0
- * @return 0 if successful, errno on failure
+/** @brief Set global ustate value, accounting for all environments
+ * if state is set to zero and updating only current environment if
+ * state is set to a non-zero value.
+ * @param e A pointer to an ebgenv_t context.
+ * @param ustate The global ustate value to set.
+ * @return errno on error, 0 if okay.
*/
-int ebg_env_confirmupdate(void);
+int ebg_env_setglobalstate(ebgenv_t *e, uint16_t ustate);
-/** @brief Closes environment and finalize library. Changes are written
- * before closing.
+/** @brief Closes environment and finalize library. Changes are written before
+ * closing.
+ * @param e A pointer to an ebgenv_t context.
* @return 0 on success, errno on failure
*/
-int ebg_env_close(void);
+int ebg_env_close(ebgenv_t *e);
#endif //__EBGENV_H__
diff --git a/tools/bg_setenv.c b/tools/bg_setenv.c
index e678188..fc3628f 100644
--- a/tools/bg_setenv.c
+++ b/tools/bg_setenv.c
@@ -281,7 +281,7 @@ int main(int argc, char **argv)
}
int result = 0;
if (!arguments.output_to_file) {
- if (!bgenv_init(BGENVTYPE_FAT)) {
+ if (!bgenv_init()) {
fprintf(stderr,
"Error initializing FAT environment.\n");
return 1;
@@ -291,7 +291,7 @@ int main(int argc, char **argv)
printf("\n----------------------------\n");
printf(" Config Partition #%d ", i);
}
- BGENV *env = bgenv_get_by_index(BGENVTYPE_FAT, i);
+ BGENV *env = bgenv_open_by_index(i);
if (env) {
if (verbosity) {
dump_env(env->data);
@@ -309,7 +309,7 @@ int main(int argc, char **argv)
BGENV *env_current;
if (auto_update) {
/* search latest and oldest revision */
- env_current = bgenv_get_latest(BGENVTYPE_FAT);
+ env_current = bgenv_open_latest();
if (!env_current) {
fprintf(stderr, "Failed to retrieve "
"latest "
@@ -319,7 +319,7 @@ int main(int argc, char **argv)
arguments.tmpdata.revision =
env_current->data->revision + 1;
- env_new = bgenv_get_oldest(BGENVTYPE_FAT);
+ env_new = bgenv_open_oldest();
if (!env_new) {
fprintf(stderr, "Failed to retrieve "
"oldest "
@@ -353,12 +353,10 @@ int main(int argc, char **argv)
}
} else {
if (part_specified) {
- env_new = bgenv_get_by_index(
- BGENVTYPE_FAT,
+ env_new = bgenv_open_by_index(
arguments.which_part);
} else {
- env_new =
- bgenv_get_latest(BGENVTYPE_FAT);
+ env_new = bgenv_open_latest();
}
if (!env_new) {
fprintf(stderr, "Failed to retrieve "
diff --git a/tools/tests/Makefile b/tools/tests/Makefile
index 994dd59..417e449 100644
--- a/tools/tests/Makefile
+++ b/tools/tests/Makefile
@@ -67,7 +67,7 @@ MOCKOBJS_test_api = $(ENV_API)
MOCKOBJS_SYMBOLS_$(ENV_API)-test_partitions = probe_config_file
MOCKOBJS_SYMBOLS_$(ENV_API)-test_environment = oldenvs configparts fopen fclose fread fwrite feof mount_partition
-MOCKOBJS_SYMBOLS_$(ENV_API)-test_api = bgenv_init bgenv_write bgenv_close bgenv_get_latest bgenv_get_by_index bgenv_get_oldest
+MOCKOBJS_SYMBOLS_$(ENV_API)-test_api = bgenv_init bgenv_write bgenv_close bgenv_open_latest bgenv_open_by_index bgenv_open_oldest
MOCKOBJS_SYMBOLS_ebgpart-test_partitions = ped_device_probe_all ped_device_get_next ped_disk_next_partition
TEST_TARGETS = test_partitions.target test_environment.target test_api.target
diff --git a/tools/tests/test_api.c b/tools/tests/test_api.c
index 53e573d..605a23b 100644
--- a/tools/tests/test_api.c
+++ b/tools/tests/test_api.c
@@ -29,12 +29,10 @@ static BG_ENVDATA dataupdate = {0};
#define DEFAULT_WATCHDOG_TIMEOUT_SEC 30
static int test_env_revision = 42;
static char *test_env_revision_str = "42";
+static ebgenv_t e;
-bool bgenv_init(BGENVTYPE type)
+bool bgenv_init()
{
- if (type != BGENVTYPE_FAT) {
- return false;
- }
return true;
}
@@ -48,17 +46,20 @@ bool bgenv_close(BGENV *env_current)
return true;
}
-BGENV *bgenv_get_by_index(BGENVTYPE type, uint32_t index)
+BGENV *bgenv_open_by_index(uint32_t index)
{
- return &envupdate;
+ if (index == 1) {
+ return &envupdate;
+ }
+ return &env;
}
-BGENV *bgenv_get_latest(BGENVTYPE type)
+BGENV *bgenv_open_latest()
{
return mock_ptr_type(BGENV *);
}
-BGENV *bgenv_get_oldest(BGENVTYPE type)
+BGENV *bgenv_open_oldest()
{
return mock_ptr_type(BGENV *);
}
@@ -67,24 +68,24 @@ static void test_api_openclose(void **state)
{
int ret;
- will_return(bgenv_get_latest, &env);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, &env);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, 0);
will_return(bgenv_write, true);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, 0);
- will_return(bgenv_get_latest, &env);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, &env);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, 0);
will_return(bgenv_write, false);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, EIO);
- will_return(bgenv_get_latest, NULL);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, NULL);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, EIO);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, EIO);
(void)state;
@@ -93,51 +94,55 @@ static void test_api_openclose(void **state)
static void test_api_accesscurrent(void **state)
{
int ret;
+ char buffer[4096];
- will_return(bgenv_get_latest, &env);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, &env);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, 0);
will_return(bgenv_write, true);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, 0);
- ret = ebg_env_set("NonsenseKey", "AnyValue");
+ ret = ebg_env_set(&e, "NonsenseKey", "AnyValue");
assert_int_equal(ret, EINVAL);
- ret = ebg_env_set("kernelfile", "vmlinuz");
+ ret = ebg_env_set(&e, "kernelfile", "vmlinuz");
assert_int_equal(ret, EPERM);
- will_return(bgenv_get_latest, &env);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, &env);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, 0);
- assert_int_equal(ebg_env_set("kernelfile", "vmlinuz"), 0);
- assert_int_equal(ebg_env_set("kernelparams", "root=/dev/sda"), 0);
- assert_int_equal(ebg_env_set("watchdog_timeout_sec", "abc"), EINVAL);
- assert_int_equal(ebg_env_set("watchdog_timeout_sec", "0013"), 0);
- assert_int_equal(ebg_env_set("ustate", "1"), 0);
+ assert_int_equal(ebg_env_set(&e, "kernelfile", "vmlinuz"), 0);
+ assert_int_equal(ebg_env_set(&e, "kernelparams", "root=/dev/sda"), 0);
+ assert_int_equal(ebg_env_set(&e, "watchdog_timeout_sec", "abc"), EINVAL);
+ assert_int_equal(ebg_env_set(&e, "watchdog_timeout_sec", "0013"), 0);
+ assert_int_equal(ebg_env_set(&e, "ustate", "1"), 0);
will_return(bgenv_write, true);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, 0);
- char *value;
- value = ebg_env_get("kernelfile");
- assert_null(value);
- assert_int_equal(errno, EPERM);
+ ret = ebg_env_get(&e, "kernelfile", buffer);
+ assert_int_equal(ret, EPERM);
- will_return(bgenv_get_latest, &env);
- ret = ebg_env_open_current();
+ will_return(bgenv_open_latest, &env);
+ ret = ebg_env_open_current(&e);
assert_int_equal(ret, 0);
- assert_string_equal(ebg_env_get("kernelfile"), "vmlinuz");
- assert_string_equal(ebg_env_get("kernelparams"), "root=/dev/sda");
- assert_string_equal(ebg_env_get("watchdog_timeout_sec"), "13");
- assert_string_equal(ebg_env_get("ustate"), "1");
- assert_string_equal(ebg_env_get("revision"), test_env_revision_str);
+ assert_int_equal(ebg_env_get(&e, "kernelfile", buffer), 0);
+ assert_string_equal(buffer, "vmlinuz");
+ assert_int_equal(ebg_env_get(&e, "kernelparams", buffer), 0);
+ assert_string_equal(buffer, "root=/dev/sda");
+ assert_int_equal(ebg_env_get(&e, "watchdog_timeout_sec", buffer), 0);
+ assert_string_equal(buffer, "13");
+ assert_int_equal(ebg_env_get(&e, "ustate", buffer), 0);
+ assert_string_equal(buffer, "1");
+ assert_int_equal(ebg_env_get(&e, "revision", buffer), 0);
+ assert_string_equal(buffer, test_env_revision_str);
will_return(bgenv_write, true);
- ret = ebg_env_close();
+ ret = ebg_env_close(&e);
assert_int_equal(ret, 0);
(void)state;
@@ -145,34 +150,37 @@ static void test_api_accesscurrent(void **state)
static void test_api_update(void **state)
{
- will_return(bgenv_get_latest, &env);
- will_return(bgenv_get_oldest, &envupdate);
- assert_int_equal(ebg_env_create_new(), 0);
+ will_return(bgenv_open_latest, &env);
+ will_return(bgenv_open_oldest, &envupdate);
+ assert_int_equal(ebg_env_create_new(&e), 0);
assert_int_equal(envupdate.data->revision, test_env_revision + 1);
assert_int_equal(envupdate.data->watchdog_timeout_sec,
DEFAULT_WATCHDOG_TIMEOUT_SEC);
assert_int_equal(envupdate.data->ustate, 1);
- assert_int_equal(ebg_env_set("ustate", "2"), 0);
- assert_int_equal(ebg_env_confirmupdate(), 0);
-
- assert_int_equal(ebg_env_set("revision", "0"), 0);
- assert_int_equal(ebg_env_set("ustate", "3"), 0);
- assert_false(ebg_env_isupdatesuccessful());
+ assert_int_equal(ebg_env_set(&e, "ustate", "2"), 0);
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ will_return(bgenv_write, true);
+ }
+ assert_int_equal(ebg_env_setglobalstate(&e, 0), 0);
- assert_int_equal(ebg_env_set("revision", "0"), 0);
- assert_int_equal(ebg_env_set("ustate", "0"), 0);
- assert_true(ebg_env_isupdatesuccessful());
+ if (ENV_NUM_CONFIG_PARTS == 1) {
+ will_return(bgenv_open_latest, &envupdate);
+ }
+ assert_int_equal(ebg_env_set(&e, "revision", "0"), 0);
+ assert_int_equal(ebg_env_set(&e, "ustate", "3"), 0);
+ assert_int_equal(ebg_env_getglobalstate(&e), 3);
- assert_int_equal(ebg_env_set("revision", "0"), 0);
- assert_int_equal(ebg_env_set("ustate", "3"), 0);
- will_return(bgenv_write, true);
- assert_int_equal(ebg_env_clearerrorstate(), 0);
- assert_true(ebg_env_isupdatesuccessful());
+ will_return(bgenv_open_latest, &env);
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ will_return(bgenv_write, true);
+ }
+ assert_int_equal(ebg_env_setglobalstate(&e, 0), 0);
+ assert_int_equal(ebg_env_getglobalstate(&e), 0);
will_return(bgenv_write, true);
- assert_int_equal(ebg_env_close(), 0);
+ assert_int_equal(ebg_env_close(&e), 0);
(void)state;
}
--
2.14.1