mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
From: Michael Olbrich <m.olbrich@pengutronix.de>
To: ptxdist@pengutronix.de
Cc: Alexander Dahl <ada@thorsis.com>
Subject: Re: [ptxdist] [APPLIED] libubootenv: version bump 0.3.6 -> 0.3.7
Date: Mon,  2 Mar 2026 10:25:17 +0100	[thread overview]
Message-ID: <20260302092517.3502252-1-m.olbrich@pengutronix.de> (raw)
In-Reply-To: <20260212100924.1556815-1-ada@thorsis.com>

Thanks, applied as 63876ac3c6c9d9cb660da274b42a25407d5209dd.

Michael

[sent from post-receive hook]

On Mon, 02 Mar 2026 10:25:17 +0100, Alexander Dahl <ada@thorsis.com> wrote:
> All patches gone upstream.  Changes from 0.3.6 to 0.3.7 are basically
> all those patches plus some build warnings removed and typos fixed.
> 
> Signed-off-by: Alexander Dahl <ada@thorsis.com>
> Message-Id: <20260212100924.1556815-1-ada@thorsis.com>
> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
> 
> diff --git a/patches/libubootenv-0.3.6/0001-Make-libyaml-optional.patch b/patches/libubootenv-0.3.6/0001-Make-libyaml-optional.patch
> deleted file mode 100644
> index 631d0f1ef7fb..000000000000
> --- a/patches/libubootenv-0.3.6/0001-Make-libyaml-optional.patch
> +++ /dev/null
> @@ -1,1507 +0,0 @@
> -From: Stefano Babic <stefano.babic@swupdate.org>
> -Date: Tue, 29 Oct 2024 09:23:20 +0100
> -Subject: [PATCH] Make libyaml optional
> -
> -NewYAML format is required for extended features because the format
> -foreseen by U-Boot is very limited. However, some systems due to
> -low resources don't want to link to libyaml. Add the option
> -NO_YML_SUPPORT to disable YAML configuration file and just use
> -fw_env.config in the U-Boot format.
> -
> -There are no functional changes in this patch - function depending on
> -YML are moved in a separate file, and some functions are factorized.
> -
> -Signed-off-by: Stefano Babic <stefano.babic@swupdate.org>
> ----
> - CMakeLists.txt        |   6 +
> - src/CMakeLists.txt    |   9 +-
> - src/common.c          | 248 +++++++++++++++++++
> - src/common.h          |  15 ++
> - src/extended_config.c | 452 ++++++++++++++++++++++++++++++++++
> - src/uboot_env.c       | 655 +-------------------------------------------------
> - 6 files changed, 735 insertions(+), 650 deletions(-)
> - create mode 100644 src/common.c
> - create mode 100644 src/common.h
> - create mode 100644 src/extended_config.c
> -
> -diff --git a/CMakeLists.txt b/CMakeLists.txt
> -index 3bb93e16b42b..796d7bcffb29 100644
> ---- a/CMakeLists.txt
> -+++ b/CMakeLists.txt
> -@@ -12,6 +12,8 @@ set(VERSION	"0.3.6")
> - SET(SOVERSION "0")
> - add_definitions(-DVERSION="${VERSION}")
> - 
> -+option(NO_YML_SUPPORT "YML Support")
> -+
> - if(DEFAULT_CFG_FILE)
> -     add_definitions(-DDEFAULT_CFG_FILE="${DEFAULT_CFG_FILE}")
> - endif(DEFAULT_CFG_FILE)
> -@@ -20,6 +22,10 @@ if(DEFAULT_ENV_FILE)
> -     add_definitions(-DDEFAULT_ENV_FILE="${DEFAULT_ENV_FILE}")
> - endif(DEFAULT_ENV_FILE)
> - 
> -+if(NO_YML_SUPPORT)
> -+  add_definitions(-DNO_YAML_SUPPORT)
> -+endif(NO_YML_SUPPORT)
> -+
> - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
> - 
> - #set(CMAKE_C_FLAGS_DEBUG "-g")
> -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
> -index 63d48225f83b..c56d0c756528 100644
> ---- a/src/CMakeLists.txt
> -+++ b/src/CMakeLists.txt
> -@@ -6,6 +6,9 @@ cmake_minimum_required (VERSION 2.6)
> - SET(libubootenv_SOURCES
> -   uboot_env.c
> -   uboot_mtd.c
> -+  extended_config.c
> -+  common.c
> -+  common.h
> -   uboot_private.h
> - )
> - 
> -@@ -22,7 +25,11 @@ SET_TARGET_PROPERTIES(ubootenv PROPERTIES VERSION ${VERSION} SOVERSION ${SOVERSI
> - ADD_LIBRARY(ubootenv_static STATIC ${libubootenv_SOURCES} ${include_HEADERS})
> - SET_TARGET_PROPERTIES(ubootenv_static PROPERTIES OUTPUT_NAME ubootenv)
> - add_executable(fw_printenv fw_printenv.c)
> --target_link_libraries(ubootenv z yaml)
> -+target_link_libraries(ubootenv z)
> -+if (NOT NO_YML_SUPPORT)
> -+target_link_libraries(ubootenv yaml)
> -+endif(NOT NO_YML_SUPPORT)
> -+
> - target_link_libraries(fw_printenv ubootenv)
> - add_custom_target(fw_setenv ALL ${CMAKE_COMMAND} -E create_symlink fw_printenv fw_setenv)
> - 
> -diff --git a/src/common.c b/src/common.c
> -new file mode 100644
> -index 000000000000..2cbde93a7140
> ---- /dev/null
> -+++ b/src/common.c
> -@@ -0,0 +1,248 @@
> -+/*
> -+ * (C) Copyright 2024
> -+ * Stefano Babic, <stefano.babic@swupdate.org>
> -+ *
> -+ * SPDX-License-Identifier:     LGPL-2.1-or-later
> -+ */
> -+
> -+#define _GNU_SOURCE
> -+
> -+#include <stdio.h>
> -+#include <stdlib.h>
> -+#include <stdint.h>
> -+#include <stddef.h>
> -+#include <dirent.h>
> -+#include <unistd.h>
> -+#include <limits.h>
> -+#include <string.h>
> -+#include <errno.h>
> -+#include <fcntl.h>
> -+#include <sys/stat.h>
> -+#include <sys/ioctl.h>
> -+#ifdef __FreeBSD__
> -+#include <sys/disk.h>
> -+#define BLKGETSIZE64 DIOCGMEDIASIZE
> -+#else
> -+#include <linux/fs.h>
> -+#endif
> -+
> -+#include "uboot_private.h"
> -+#include "common.h"
> -+
> -+static enum device_type get_device_type(char *device)
> -+{
> -+	enum device_type type = DEVICE_NONE;
> -+
> -+	if (!strncmp(device, DEVICE_MTD_NAME, strlen(DEVICE_MTD_NAME)))
> -+		if (strchr(device, DEVNAME_SEPARATOR)) {
> -+			type = DEVICE_UBI;
> -+		} else {
> -+			type = DEVICE_MTD;
> -+		}
> -+	else if (!strncmp(device, DEVICE_UBI_NAME, strlen(DEVICE_UBI_NAME)))
> -+		type = DEVICE_UBI;
> -+	else if (strlen(device) > 0)
> -+		type = DEVICE_FILE;
> -+
> -+	return type;
> -+}
> -+
> -+int normalize_device_path(char *path, struct uboot_flash_env *dev)
> -+{
> -+	char *sep = NULL, *normalized = NULL;
> -+	size_t normalized_len = 0, volume_len = 0, output_len = 0;
> -+
> -+	/*
> -+	 * if volume name is present, split into device path and volume
> -+	 * since only the device path needs normalized
> -+	 */
> -+	sep = strchr(path, DEVNAME_SEPARATOR);
> -+	if (sep)
> -+	{
> -+		volume_len = strlen(sep);
> -+		*sep = '\0';
> -+	}
> -+
> -+	if ((normalized = realpath(path, NULL)) == NULL)
> -+	{
> -+		/* device file didn't exist */
> -+		return -EINVAL;
> -+	}
> -+
> -+	normalized_len = strlen(normalized);
> -+	output_len = sizeof(dev->devname) - 1; /* leave room for null */
> -+	if ((normalized_len + volume_len) > output_len)
> -+	{
> -+		/* full name is too long to fit */
> -+		free(normalized);
> -+		return -EINVAL;
> -+	}
> -+
> -+	/*
> -+	 * save normalized path to device file,
> -+	 * and possibly append separator char & volume name
> -+	 */
> -+	memset(dev->devname, 0, sizeof(dev->devname));
> -+	strncpy(dev->devname, normalized, output_len);
> -+	free(normalized);
> -+
> -+	if (sep)
> -+	{
> -+		*sep = DEVNAME_SEPARATOR;
> -+		strncpy(dev->devname + normalized_len, sep, output_len - normalized_len);
> -+	}
> -+
> -+	return 0;
> -+}
> -+
> -+void set_var_access_type(struct var_entry *entry, const char *pvarflags)
> -+{
> -+	if (entry) {
> -+		for (int i = 0; i < strlen(pvarflags); i++) {
> -+			switch (pvarflags[i]) {
> -+			case 's':
> -+				entry->type = TYPE_ATTR_STRING;
> -+				break;
> -+			case 'd':
> -+				entry->type = TYPE_ATTR_DECIMAL;
> -+				break;
> -+			case 'x':
> -+				entry->type = TYPE_ATTR_HEX;
> -+				break;
> -+			case 'b':
> -+				entry->type = TYPE_ATTR_BOOL;
> -+				break;
> -+			case 'i':
> -+				entry->type = TYPE_ATTR_IP;
> -+				break;
> -+			case 'm':
> -+				entry->type = TYPE_ATTR_MAC;
> -+				break;
> -+			case 'a':
> -+				entry->access = ACCESS_ATTR_ANY;
> -+				break;
> -+			case 'r':
> -+				entry->access = ACCESS_ATTR_READ_ONLY;
> -+				break;
> -+			case 'o':
> -+				entry->access = ACCESS_ATTR_WRITE_ONCE;
> -+				break;
> -+			case 'c':
> -+				entry->access = ACCESS_ATTR_CHANGE_DEFAULT;
> -+				break;
> -+			default: /* ignore it */
> -+				break;
> -+			}
> -+		}
> -+	}
> -+}
> -+
> -+struct var_entry *create_var_entry(const char *name)
> -+{
> -+	struct var_entry *entry;
> -+
> -+	entry = (struct var_entry *)calloc(1, sizeof(*entry));
> -+	if (!entry)
> -+		return NULL;
> -+	entry->name = strdup(name);
> -+	if (!entry->name) {
> -+		free(entry);
> -+		return NULL;
> -+	}
> -+
> -+	return entry;
> -+}
> -+
> -+bool check_compatible_devices(struct uboot_ctx *ctx)
> -+{
> -+	if (!ctx->redundant)
> -+		return true;
> -+
> -+	if (ctx->envdevs[0].mtdinfo.type != ctx->envdevs[1].mtdinfo.type)
> -+		return false;
> -+	if (ctx->envdevs[0].flagstype != ctx->envdevs[1].flagstype)
> -+		return false;
> -+	if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize)
> -+		return false;
> -+
> -+	return true;
> -+}
> -+
> -+int check_env_device(struct uboot_flash_env *dev)
> -+{
> -+	int fd, ret;
> -+	struct stat st;
> -+
> -+	dev->device_type = get_device_type(dev->devname);
> -+	if (dev->device_type == DEVICE_NONE)
> -+		return -EBADF;
> -+
> -+	if (dev->device_type == DEVICE_UBI) {
> -+		ret = libubootenv_ubi_update_name(dev);
> -+		if (ret)
> -+			return ret;
> -+	}
> -+
> -+	ret = stat(dev->devname, &st);
> -+	if (ret < 0)
> -+		return -EBADF;
> -+	fd = open(dev->devname, O_RDONLY);
> -+	if (fd < 0)
> -+		return -EBADF;
> -+
> -+	if (S_ISCHR(st.st_mode)) {
> -+		if (dev->device_type == DEVICE_MTD) {
> -+			ret = libubootenv_mtdgetinfo(fd, dev);
> -+			if (ret < 0 || (dev->mtdinfo.type != MTD_NORFLASH &&
> -+					dev->mtdinfo.type != MTD_NANDFLASH)) {
> -+				close(fd);
> -+				return -EBADF;
> -+			}
> -+			if (dev->sectorsize == 0) {
> -+				dev->sectorsize = dev->mtdinfo.erasesize;
> -+			}
> -+		}
> -+	}
> -+
> -+	switch (dev->device_type) {
> -+	case DEVICE_FILE:
> -+		dev->flagstype = FLAGS_INCREMENTAL;
> -+		break;
> -+	case DEVICE_MTD:
> -+		switch (dev->mtdinfo.type) {
> -+		case MTD_NORFLASH:
> -+			dev->flagstype = FLAGS_BOOLEAN;
> -+			break;
> -+		case MTD_NANDFLASH:
> -+			dev->flagstype = FLAGS_INCREMENTAL;
> -+		};
> -+		break;
> -+	case DEVICE_UBI:
> -+		dev->flagstype = FLAGS_INCREMENTAL;
> -+		break;
> -+	default:
> -+		close(fd);
> -+		return -EBADF;
> -+	};
> -+
> -+	/*
> -+	 * Check for negative offsets, treat it as backwards offset
> -+	 * from the end of the block device
> -+	 */
> -+	if (dev->offset < 0) {
> -+		uint64_t blkdevsize;
> -+		int rc;
> -+
> -+		rc = ioctl(fd, BLKGETSIZE64, &blkdevsize);
> -+		if (rc < 0) {
> -+			close(fd);
> -+			return -EINVAL;
> -+		}
> -+
> -+		dev->offset += blkdevsize;
> -+	}
> -+
> -+	close(fd);
> -+
> -+	return 0;
> -+}
> -diff --git a/src/common.h b/src/common.h
> -new file mode 100644
> -index 000000000000..adacd4896741
> ---- /dev/null
> -+++ b/src/common.h
> -@@ -0,0 +1,15 @@
> -+/*
> -+ * (C) Copyright 2024
> -+ * Stefano Babic, <stefano.babic@swupdate.org>
> -+ *
> -+ * SPDX-License-Identifier:     LGPL-2.1-or-later
> -+ */
> -+
> -+
> -+#include "uboot_private.h"
> -+
> -+struct var_entry *create_var_entry(const char *name);
> -+void set_var_access_type(struct var_entry *entry, const char *pvarflags);
> -+int normalize_device_path(char *path, struct uboot_flash_env *dev);
> -+int check_env_device(struct uboot_flash_env *dev);
> -+bool check_compatible_devices(struct uboot_ctx *ctx);
> -diff --git a/src/extended_config.c b/src/extended_config.c
> -new file mode 100644
> -index 000000000000..ec814f484efd
> ---- /dev/null
> -+++ b/src/extended_config.c
> -@@ -0,0 +1,452 @@
> -+/*
> -+ * (C) Copyright 2024
> -+ * Stefano Babic, <stefano.babic@swupdate.org>
> -+ *
> -+ * SPDX-License-Identifier:     LGPL-2.1-or-later
> -+ */
> -+
> -+/**
> -+ * @file extended_config.c
> -+ *
> -+ * @brief Implement the extended config file YAML
> -+	*
> -+ */
> -+#define _GNU_SOURCE
> -+
> -+#if !defined(NO_YAML_SUPPORT)
> -+#include <stdio.h>
> -+#include <stdlib.h>
> -+#include <stdint.h>
> -+#include <stddef.h>
> -+#include <unistd.h>
> -+#include <errno.h>
> -+#include <yaml.h>
> -+
> -+#include "uboot_private.h"
> -+#include "common.h"
> -+
> -+/* yaml_* functions return 1 on success and 0 on failure. */
> -+enum yaml_status {
> -+    SUCCESS = 0,
> -+    FAILURE = 1
> -+};
> -+
> -+enum yaml_state {
> -+	STATE_START,    /* start state */
> -+	STATE_STREAM,   /* start/end stream */
> -+	STATE_DOCUMENT, /* start/end document */
> -+	STATE_SECTION,  /* top level */
> -+
> -+	STATE_NAMESPACE,	/* Init Configuration Namespace */
> -+	STATE_NAMESPACE_FIELDS,	/* namespace key list */
> -+	STATE_NKEY,		/* Check key names */
> -+	STATE_NSIZE,		/* Size key-value pair */
> -+	STATE_NLOCKFILE,	/* Lockfile key-value pair */
> -+	STATE_DEVVALUES,	/* Devices key names */
> -+	STATE_WRITELIST,	/* List with vars that are accepted by write
> -+				 * if list is missing, all vars are accepted
> -+				 * var is in the format name:flags, see U-Boot
> -+				 * documentation
> -+				 */
> -+
> -+	STATE_NPATH,
> -+	STATE_NOFFSET,
> -+	STATE_NSECTORSIZE,
> -+	STATE_NUNLOCK,
> -+	STATE_STOP      /* end state */
> -+};
> -+
> -+typedef enum yaml_parse_error_e {
> -+	YAML_UNEXPECTED_STATE,
> -+	YAML_UNEXPECTED_KEY,
> -+	YAML_BAD_DEVICE,
> -+	YAML_BAD_DEVNAME,
> -+	YAML_BAD_VARLIST,
> -+	YAML_DUPLICATE_VARLIST,
> -+	YAML_OOM,
> -+} yaml_parse_error_type_t;
> -+
> -+struct parser_state {
> -+	enum yaml_state state;		/* The current parse state */
> -+	struct uboot_ctx *ctxsets;	/* Array of vars set ctx */
> -+	struct uboot_ctx *ctx;		/* Current ctx in parsing */
> -+	unsigned int nelem;		/* Number of elemets in ctxsets */
> -+	unsigned int cdev;		/* current device in parsing */
> -+	yaml_parse_error_type_t error;	/* error causing parser to stop */
> -+	yaml_event_type_t event_type;	/* event type causing error */
> -+};
> -+
> -+static int consume_event(struct parser_state *s, yaml_event_t *event)
> -+{
> -+	char *value;
> -+	struct uboot_flash_env *dev;
> -+	struct uboot_ctx *newctx;
> -+	int cdev;
> -+
> -+	switch (s->state) {
> -+	case STATE_START:
> -+		switch (event->type) {
> -+		case YAML_STREAM_START_EVENT:
> -+			s->state = STATE_STREAM;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_STREAM:
> -+		switch (event->type) {
> -+		case YAML_DOCUMENT_START_EVENT:
> -+			s->state = STATE_DOCUMENT;
> -+			break;
> -+		case YAML_STREAM_END_EVENT:
> -+			s->state = STATE_STOP;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_DOCUMENT:
> -+		switch (event->type) {
> -+		case YAML_MAPPING_START_EVENT:
> -+			s->state = STATE_SECTION;
> -+			break;
> -+		case YAML_DOCUMENT_END_EVENT:
> -+			s->state = STATE_STREAM;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_SECTION:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+			newctx = calloc (s->nelem + 1, sizeof(*newctx));
> -+			for (int i = 0; i < s->nelem; i++) {
> -+				newctx[i] = s->ctxsets[i];
> -+			}
> -+			if (s->ctxsets) free(s->ctxsets);
> -+			s->ctxsets = newctx;
> -+			s->ctx = &newctx[s->nelem];
> -+			s->ctx->name = strdup(value);
> -+			s->nelem++;
> -+			s->state = STATE_NAMESPACE;
> -+			break;
> -+		case YAML_MAPPING_END_EVENT:
> -+			s->state = STATE_DOCUMENT;
> -+			break;
> -+		case YAML_DOCUMENT_END_EVENT:
> -+			s->state = STATE_STREAM;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NAMESPACE:
> -+		switch (event->type) {
> -+		case YAML_MAPPING_START_EVENT:
> -+			s->state = STATE_NAMESPACE_FIELDS;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NAMESPACE_FIELDS:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+			if (!strcmp(value, "size")) {
> -+				s->state = STATE_NSIZE;
> -+			} else if (!strcmp(value, "lockfile")) {
> -+				s->state = STATE_NLOCKFILE;
> -+			} else if (!strcmp(value, "devices")) {
> -+				s->state = STATE_DEVVALUES;
> -+				s->cdev = 0;
> -+			} else if (!strcmp(value, "writelist")) {
> -+				s->state = STATE_WRITELIST;
> -+			} else {
> -+				s->error = YAML_UNEXPECTED_KEY;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			break;
> -+		case YAML_MAPPING_END_EVENT:
> -+			s->state = STATE_SECTION;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NSIZE:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+			errno = 0;
> -+			s->ctx->size = strtoull(value, NULL, 0);
> -+			s->state = STATE_NAMESPACE_FIELDS;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NLOCKFILE:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+			s->ctx->lockfile = strdup(value);
> -+			s->state = STATE_NAMESPACE_FIELDS;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_DEVVALUES:
> -+		switch (event->type) {
> -+		case YAML_MAPPING_START_EVENT:
> -+		case YAML_SEQUENCE_START_EVENT:
> -+			break;
> -+		case YAML_MAPPING_END_EVENT:
> -+			dev = &s->ctx->envdevs[s->cdev];
> -+			if (check_env_device(dev) < 0) {
> -+				s->error = YAML_BAD_DEVICE;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			s->cdev++;
> -+			break;
> -+		case YAML_SEQUENCE_END_EVENT:
> -+			s->state = STATE_NAMESPACE_FIELDS;
> -+			break;
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+			if (s->cdev)
> -+				s->ctx->redundant = true;
> -+			if (!strcmp(value, "path")) {
> -+				s->state = STATE_NPATH;
> -+			} else if (!strcmp(value, "offset")) {
> -+				s->state = STATE_NOFFSET;
> -+			} else if (!strcmp(value, "sectorsize")) {
> -+				s->state = STATE_NSECTORSIZE;
> -+				} else if (!strcmp(value, "disablelock")) {
> -+				s->state = STATE_NUNLOCK;
> -+			} else {
> -+				s->error = YAML_UNEXPECTED_KEY;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_WRITELIST:
> -+		switch (event->type) {
> -+
> -+		char *varflag, *name;
> -+		struct var_entry *entry;
> -+
> -+		case YAML_MAPPING_START_EVENT:
> -+		case YAML_SEQUENCE_START_EVENT:
> -+			break;
> -+		case YAML_MAPPING_END_EVENT:
> -+			break;
> -+		case YAML_SEQUENCE_END_EVENT:
> -+			s->state = STATE_NAMESPACE_FIELDS;
> -+			break;
> -+		case YAML_SCALAR_EVENT:
> -+			value = (char *)event->data.scalar.value;
> -+
> -+			/*
> -+			 * Format is name:flags, split it into two values
> -+			 */
> -+			varflag = strchr(value, ':');
> -+			if (!varflag || varflag > value + (strlen(value) - 1)) {
> -+				s->error = YAML_BAD_VARLIST;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			*varflag++ = '\0';
> -+
> -+			/*
> -+			 * Check there is not yet an entry for this variable
> -+			 */
> -+			LIST_FOREACH(entry, &s->ctx->writevarlist, next) {
> -+				if (strcmp(entry->name, value) == 0) {
> -+					s->error = YAML_DUPLICATE_VARLIST;
> -+					s->event_type = event->type;
> -+					return FAILURE;
> -+				}
> -+			}
> -+
> -+			/*
> -+			 * Insert variable with its configuration into the list
> -+			 * of modifiable vars
> -+			 */
> -+			entry = create_var_entry(value);
> -+			if (!entry) {
> -+				s->error = YAML_OOM;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			set_var_access_type(entry, varflag);
> -+			LIST_INSERT_HEAD(&s->ctx->writevarlist, entry, next);
> -+
> -+#if !defined(NDEBUG)
> -+			fprintf(stdout, "Writelist: %s flags %s\n", value, varflag);
> -+#endif
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NPATH:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			dev = &s->ctx->envdevs[s->cdev];
> -+			value = (char *)event->data.scalar.value;
> -+			if (normalize_device_path(value, dev) < 0) {
> -+				s->error = YAML_BAD_DEVNAME;
> -+				s->event_type = event->type;
> -+				return FAILURE;
> -+			}
> -+			dev->envsize = s->ctx->size;
> -+			s->state = STATE_DEVVALUES;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NOFFSET:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			dev = &s->ctx->envdevs[s->cdev];
> -+			value = (char *)event->data.scalar.value;
> -+			dev->offset = strtoull(value, NULL, 0);
> -+			s->state = STATE_DEVVALUES;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NSECTORSIZE:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			dev = &s->ctx->envdevs[s->cdev];
> -+			value = (char *)event->data.scalar.value;
> -+			dev->sectorsize = strtoull(value, NULL, 0);
> -+			s->state = STATE_DEVVALUES;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+	case STATE_NUNLOCK:
> -+		switch (event->type) {
> -+		case YAML_SCALAR_EVENT:
> -+			dev = &s->ctx->envdevs[s->cdev];
> -+			value = (char *)event->data.scalar.value;
> -+			if (!strcmp(value, "yes"))
> -+				dev->disable_mtd_lock = 1;
> -+			s->state = STATE_DEVVALUES;
> -+			break;
> -+		default:
> -+			s->error = YAML_UNEXPECTED_STATE;
> -+			s->event_type = event->type;
> -+			return FAILURE;
> -+		}
> -+		break;
> -+
> -+    case STATE_STOP:
> -+        break;
> -+    }
> -+    return SUCCESS;
> -+}
> -+
> -+int parse_yaml_config(struct uboot_ctx **ctxlist, FILE *fp)
> -+{
> -+	yaml_parser_t parser;
> -+	yaml_event_t  event;
> -+	enum yaml_status status;
> -+	struct parser_state state;
> -+	struct uboot_ctx *ctx;
> -+
> -+	if (!yaml_parser_initialize(&parser))
> -+		return -ENOMEM;
> -+
> -+	 /* Set input file */
> -+	yaml_parser_set_input_file(&parser, fp);
> -+	memset(&state, 0, sizeof(state));
> -+	state.state = STATE_START;
> -+	do {
> -+		if (!yaml_parser_parse(&parser, &event)) {
> -+			status = FAILURE;
> -+			goto cleanup;
> -+		}
> -+		status = consume_event(&state, &event);
> -+		yaml_event_delete(&event);
> -+		if (status == FAILURE) {
> -+			goto cleanup;
> -+		}
> -+	} while (state.state != STATE_STOP);
> -+
> -+	state.ctxsets[0].nelem = state.nelem;
> -+
> -+	for (int i = 0; i < state.nelem; i++) {
> -+		ctx = &state.ctxsets[i];
> -+		ctx->ctxlist = &state.ctxsets[0];
> -+		if (ctx->redundant && !check_compatible_devices(ctx)) {
> -+			status = FAILURE;
> -+			break;
> -+		}
> -+	}
> -+
> -+
> -+cleanup:
> -+	yaml_parser_delete(&parser);
> -+	if (status == FAILURE) {
> -+		if (state.ctxsets) free (state.ctxsets);
> -+		state.ctxsets = NULL;
> -+	}
> -+	*ctxlist = state.ctxsets;
> -+	return status;
> -+}
> -+#endif
> -diff --git a/src/uboot_env.c b/src/uboot_env.c
> -index 0b4f9f4d0458..d8b93dac7479 100644
> ---- a/src/uboot_env.c
> -+++ b/src/uboot_env.c
> -@@ -21,12 +21,6 @@
> - #include <dirent.h>
> - #include <unistd.h>
> - #include <limits.h>
> --#ifdef __FreeBSD__
> --#include <sys/disk.h>
> --#define BLKGETSIZE64 DIOCGMEDIASIZE
> --#else
> --#include <linux/fs.h>
> --#endif
> - #include <string.h>
> - #include <fcntl.h>
> - #include <errno.h>
> -@@ -38,60 +32,15 @@
> - #include <sys/wait.h>
> - #include <sys/ioctl.h>
> - #include <zlib.h>
> --#include <yaml.h>
> - 
> - #include "uboot_private.h"
> -+#include "common.h"
> - 
> --/* yaml_* functions return 1 on success and 0 on failure. */
> --enum yaml_status {
> --    SUCCESS = 0,
> --    FAILURE = 1
> --};
> --
> --enum yaml_state {
> --	STATE_START,    /* start state */
> --	STATE_STREAM,   /* start/end stream */
> --	STATE_DOCUMENT, /* start/end document */
> --	STATE_SECTION,  /* top level */
> --
> --	STATE_NAMESPACE,	/* Init Configuration Namespace */
> --	STATE_NAMESPACE_FIELDS,	/* namespace key list */
> --	STATE_NKEY,		/* Check key names */
> --	STATE_NSIZE,		/* Size key-value pair */
> --	STATE_NLOCKFILE,	/* Lockfile key-value pair */
> --	STATE_DEVVALUES,	/* Devices key names */
> --	STATE_WRITELIST,	/* List with vars that are accepted by write
> --				 * if list is missing, all vars are accepted
> --				 * var is in the format name:flags, see U-Boot
> --				 * documentation
> --				 */
> --
> --	STATE_NPATH,
> --	STATE_NOFFSET,
> --	STATE_NSECTORSIZE,
> --	STATE_NUNLOCK,
> --	STATE_STOP      /* end state */
> --};
> --
> --typedef enum yaml_parse_error_e {
> --	YAML_UNEXPECTED_STATE,
> --	YAML_UNEXPECTED_KEY,
> --	YAML_BAD_DEVICE,
> --	YAML_BAD_DEVNAME,
> --	YAML_BAD_VARLIST,
> --	YAML_DUPLICATE_VARLIST,
> --	YAML_OOM,
> --} yaml_parse_error_type_t;
> --
> --struct parser_state {
> --	enum yaml_state state;		/* The current parse state */
> --	struct uboot_ctx *ctxsets;	/* Array of vars set ctx */
> --	struct uboot_ctx *ctx;		/* Current ctx in parsing */
> --	unsigned int nelem;		/* Number of elemets in ctxsets */
> --	unsigned int cdev;		/* current device in parsing */
> --	yaml_parse_error_type_t error;	/* error causing parser to stop */
> --	yaml_event_type_t event_type;	/* event type causing error */
> --};
> -+#if defined(NO_YAML_SUPPORT)
> -+#define parse_yaml_config(ctx,fp) -1
> -+#else
> -+extern int parse_yaml_config(struct uboot_ctx **ctxlist, FILE *fp);
> -+#endif
> - 
> - #define FREE_ENTRY do { \
> - 	free(entry->name); \
> -@@ -152,64 +101,6 @@ static char attr_tostring(type_attribute a)
> - 	return 's';
> - }
> - 
> --static void set_var_access_type(struct var_entry *entry, const char *pvarflags)
> --{
> --	if (entry) {
> --		for (int i = 0; i < strlen(pvarflags); i++) {
> --			switch (pvarflags[i]) {
> --			case 's':
> --				entry->type = TYPE_ATTR_STRING;
> --				break;
> --			case 'd':
> --				entry->type = TYPE_ATTR_DECIMAL;
> --				break;
> --			case 'x':
> --				entry->type = TYPE_ATTR_HEX;
> --				break;
> --			case 'b':
> --				entry->type = TYPE_ATTR_BOOL;
> --				break;
> --			case 'i':
> --				entry->type = TYPE_ATTR_IP;
> --				break;
> --			case 'm':
> --				entry->type = TYPE_ATTR_MAC;
> --				break;
> --			case 'a':
> --				entry->access = ACCESS_ATTR_ANY;
> --				break;
> --			case 'r':
> --				entry->access = ACCESS_ATTR_READ_ONLY;
> --				break;
> --			case 'o':
> --				entry->access = ACCESS_ATTR_WRITE_ONCE;
> --				break;
> --			case 'c':
> --				entry->access = ACCESS_ATTR_CHANGE_DEFAULT;
> --				break;
> --			default: /* ignore it */
> --				break;
> --			}
> --		}
> --	}
> --}
> --
> --static struct var_entry *create_var_entry(const char *name)
> --{
> --	struct var_entry *entry;
> --
> --	entry = (struct var_entry *)calloc(1, sizeof(*entry));
> --	if (!entry)
> --		return NULL;
> --	entry->name = strdup(name);
> --	if (!entry->name) {
> --		free(entry);
> --		return NULL;
> --	}
> --
> --	return entry;
> --}
> --
> - static char access_tostring(access_attribute a)
> - {
> - 	switch(a) {
> -@@ -389,166 +280,6 @@ static int __libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const
> - 	return 0;
> - }
> - 
> --static enum device_type get_device_type(char *device)
> --{
> --	enum device_type type = DEVICE_NONE;
> --
> --	if (!strncmp(device, DEVICE_MTD_NAME, strlen(DEVICE_MTD_NAME)))
> --		if (strchr(device, DEVNAME_SEPARATOR)) {
> --			type = DEVICE_UBI;
> --		} else {
> --			type = DEVICE_MTD;
> --		}
> --	else if (!strncmp(device, DEVICE_UBI_NAME, strlen(DEVICE_UBI_NAME)))
> --		type = DEVICE_UBI;
> --	else if (strlen(device) > 0)
> --		type = DEVICE_FILE;
> --
> --	return type;
> --}
> --
> --static int normalize_device_path(char *path, struct uboot_flash_env *dev)
> --{
> --	char *sep = NULL, *normalized = NULL;
> --	size_t normalized_len = 0, volume_len = 0, output_len = 0;
> --
> --	/*
> --	 * if volume name is present, split into device path and volume
> --	 * since only the device path needs normalized
> --	 */
> --	sep = strchr(path, DEVNAME_SEPARATOR);
> --	if (sep)
> --	{
> --		volume_len = strlen(sep);
> --		*sep = '\0';
> --	}
> --
> --	if ((normalized = realpath(path, NULL)) == NULL)
> --	{
> --		/* device file didn't exist */
> --		return -EINVAL;
> --	}
> --
> --	normalized_len = strlen(normalized);
> --	output_len = sizeof(dev->devname) - 1; /* leave room for null */
> --	if ((normalized_len + volume_len) > output_len)
> --	{
> --		/* full name is too long to fit */
> --		free(normalized);
> --		return -EINVAL;
> --	}
> --
> --	/*
> --	 * save normalized path to device file,
> --	 * and possibly append separator char & volume name
> --	 */
> --	memset(dev->devname, 0, sizeof(dev->devname));
> --	strncpy(dev->devname, normalized, output_len);
> --	free(normalized);
> --
> --	if (sep)
> --	{
> --		*sep = DEVNAME_SEPARATOR;
> --		strncpy(dev->devname + normalized_len, sep, output_len - normalized_len);
> --	}
> --
> --	return 0;
> --}
> --
> --static int check_env_device(struct uboot_flash_env *dev)
> --{
> --	int fd, ret;
> --	struct stat st;
> --
> --	dev->device_type = get_device_type(dev->devname);
> --	if (dev->device_type == DEVICE_NONE)
> --		return -EBADF;
> --
> --	if (dev->device_type == DEVICE_UBI) {
> --		ret = libubootenv_ubi_update_name(dev);
> --		if (ret)
> --			return ret;
> --	}
> --
> --	ret = stat(dev->devname, &st);
> --	if (ret < 0)
> --		return -EBADF;
> --	fd = open(dev->devname, O_RDONLY);
> --	if (fd < 0)
> --		return -EBADF;
> --
> --	if (S_ISCHR(st.st_mode)) {
> --		if (dev->device_type == DEVICE_MTD) {
> --			ret = libubootenv_mtdgetinfo(fd, dev);
> --			if (ret < 0 || (dev->mtdinfo.type != MTD_NORFLASH &&
> --					dev->mtdinfo.type != MTD_NANDFLASH)) {
> --				close(fd);
> --				return -EBADF;
> --			}
> --			if (dev->sectorsize == 0) {
> --				dev->sectorsize = dev->mtdinfo.erasesize;
> --			}
> --		}
> --	}
> --
> --	switch (dev->device_type) {
> --	case DEVICE_FILE:
> --		dev->flagstype = FLAGS_INCREMENTAL;
> --		break;
> --	case DEVICE_MTD:
> --		switch (dev->mtdinfo.type) {
> --		case MTD_NORFLASH:
> --			dev->flagstype = FLAGS_BOOLEAN;
> --			break;
> --		case MTD_NANDFLASH:
> --			dev->flagstype = FLAGS_INCREMENTAL;
> --		};
> --		break;
> --	case DEVICE_UBI:
> --		dev->flagstype = FLAGS_INCREMENTAL;
> --		break;
> --	default:
> --		close(fd);
> --		return -EBADF;
> --	};
> --
> --	/*
> --	 * Check for negative offsets, treat it as backwards offset
> --	 * from the end of the block device
> --	 */
> --	if (dev->offset < 0) {
> --		uint64_t blkdevsize;
> --		int rc;
> --
> --		rc = ioctl(fd, BLKGETSIZE64, &blkdevsize);
> --		if (rc < 0) {
> --			close(fd);
> --			return -EINVAL;
> --		}
> --
> --		dev->offset += blkdevsize;
> --	}
> --
> --	close(fd);
> --
> --	return 0;
> --}
> --
> --static bool check_compatible_devices(struct uboot_ctx *ctx)
> --{
> --	if (!ctx->redundant)
> --		return true;
> --
> --	if (ctx->envdevs[0].mtdinfo.type != ctx->envdevs[1].mtdinfo.type)
> --		return false;
> --	if (ctx->envdevs[0].flagstype != ctx->envdevs[1].flagstype)
> --		return false;
> --	if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize)
> --		return false;
> --
> --	return true;
> --}
> --
> - static int fileread(struct uboot_flash_env *dev, void *data)
> - {
> - 	int ret = 0;
> -@@ -1035,380 +766,6 @@ static int libuboot_load(struct uboot_ctx *ctx)
> - 	return ctx->valid ? 0 : -ENODATA;
> - }
> - 
> --static int consume_event(struct parser_state *s, yaml_event_t *event)
> --{
> --	char *value;
> --	struct uboot_flash_env *dev;
> --	struct uboot_ctx *newctx;
> --	int cdev;
> --
> --	switch (s->state) {
> --	case STATE_START:
> --		switch (event->type) {
> --		case YAML_STREAM_START_EVENT:
> --			s->state = STATE_STREAM;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_STREAM:
> --		switch (event->type) {
> --		case YAML_DOCUMENT_START_EVENT:
> --			s->state = STATE_DOCUMENT;
> --			break;
> --		case YAML_STREAM_END_EVENT:
> --			s->state = STATE_STOP;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_DOCUMENT:
> --		switch (event->type) {
> --		case YAML_MAPPING_START_EVENT:
> --			s->state = STATE_SECTION;
> --			break;
> --		case YAML_DOCUMENT_END_EVENT:
> --			s->state = STATE_STREAM;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_SECTION:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --			newctx = calloc (s->nelem + 1, sizeof(*newctx));
> --			for (int i = 0; i < s->nelem; i++) {
> --				newctx[i] = s->ctxsets[i];
> --			}
> --			if (s->ctxsets) free(s->ctxsets);
> --			s->ctxsets = newctx;
> --			s->ctx = &newctx[s->nelem];
> --			s->ctx->name = strdup(value);
> --			s->nelem++;
> --			s->state = STATE_NAMESPACE;
> --			break;
> --		case YAML_MAPPING_END_EVENT:
> --			s->state = STATE_DOCUMENT;
> --			break;
> --		case YAML_DOCUMENT_END_EVENT:
> --			s->state = STATE_STREAM;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NAMESPACE:
> --		switch (event->type) {
> --		case YAML_MAPPING_START_EVENT:
> --			s->state = STATE_NAMESPACE_FIELDS;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NAMESPACE_FIELDS:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --			if (!strcmp(value, "size")) {
> --				s->state = STATE_NSIZE;
> --			} else if (!strcmp(value, "lockfile")) {
> --				s->state = STATE_NLOCKFILE;
> --			} else if (!strcmp(value, "devices")) {
> --				s->state = STATE_DEVVALUES;
> --				s->cdev = 0;
> --			} else if (!strcmp(value, "writelist")) {
> --				s->state = STATE_WRITELIST;
> --			} else {
> --				s->error = YAML_UNEXPECTED_KEY;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			break;
> --		case YAML_MAPPING_END_EVENT:
> --			s->state = STATE_SECTION;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NSIZE:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --			errno = 0;
> --			s->ctx->size = strtoull(value, NULL, 0);
> --			s->state = STATE_NAMESPACE_FIELDS;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NLOCKFILE:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --			s->ctx->lockfile = strdup(value);
> --			s->state = STATE_NAMESPACE_FIELDS;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_DEVVALUES:
> --		switch (event->type) {
> --		case YAML_MAPPING_START_EVENT:
> --		case YAML_SEQUENCE_START_EVENT:
> --			break;
> --		case YAML_MAPPING_END_EVENT:
> --			dev = &s->ctx->envdevs[s->cdev];
> --			if (check_env_device(dev) < 0) {
> --				s->error = YAML_BAD_DEVICE;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			s->cdev++;
> --			break;
> --		case YAML_SEQUENCE_END_EVENT:
> --			s->state = STATE_NAMESPACE_FIELDS;
> --			break;
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --			if (s->cdev)
> --				s->ctx->redundant = true;
> --			if (!strcmp(value, "path")) {
> --				s->state = STATE_NPATH;
> --			} else if (!strcmp(value, "offset")) {
> --				s->state = STATE_NOFFSET;
> --			} else if (!strcmp(value, "sectorsize")) {
> --				s->state = STATE_NSECTORSIZE;
> --				} else if (!strcmp(value, "disablelock")) {
> --				s->state = STATE_NUNLOCK;
> --			} else {
> --				s->error = YAML_UNEXPECTED_KEY;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_WRITELIST:
> --		switch (event->type) {
> --
> --		char *varflag, *name;
> --		struct var_entry *entry;
> --
> --		case YAML_MAPPING_START_EVENT:
> --		case YAML_SEQUENCE_START_EVENT:
> --			break;
> --		case YAML_MAPPING_END_EVENT:
> --			break;
> --		case YAML_SEQUENCE_END_EVENT:
> --			s->state = STATE_NAMESPACE_FIELDS;
> --			break;
> --		case YAML_SCALAR_EVENT:
> --			value = (char *)event->data.scalar.value;
> --
> --			/*
> --			 * Format is name:flags, split it into two values
> --			 */
> --			varflag = strchr(value, ':');
> --			if (!varflag || varflag > value + (strlen(value) - 1)) {
> --				s->error = YAML_BAD_VARLIST;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			*varflag++ = '\0';
> --
> --			/*
> --			 * Check there is not yet an entry for this variable
> --			 */
> --			LIST_FOREACH(entry, &s->ctx->writevarlist, next) {
> --				if (strcmp(entry->name, value) == 0) {
> --					s->error = YAML_DUPLICATE_VARLIST;
> --					s->event_type = event->type;
> --					return FAILURE;
> --				}
> --			}
> --
> --			/*
> --			 * Insert variable with its configuration into the list
> --			 * of modifiable vars
> --			 */
> --			entry = create_var_entry(value);
> --			if (!entry) {
> --				s->error = YAML_OOM;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			set_var_access_type(entry, varflag);
> --			LIST_INSERT_HEAD(&s->ctx->writevarlist, entry, next);
> --
> --#if !defined(NDEBUG)
> --			fprintf(stdout, "Writelist: %s flags %s\n", value, varflag);
> --#endif
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NPATH:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			dev = &s->ctx->envdevs[s->cdev];
> --			value = (char *)event->data.scalar.value;
> --			if (normalize_device_path(value, dev) < 0) {
> --				s->error = YAML_BAD_DEVNAME;
> --				s->event_type = event->type;
> --				return FAILURE;
> --			}
> --			dev->envsize = s->ctx->size;
> --			s->state = STATE_DEVVALUES;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NOFFSET:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			dev = &s->ctx->envdevs[s->cdev];
> --			value = (char *)event->data.scalar.value;
> --			dev->offset = strtoull(value, NULL, 0);
> --			s->state = STATE_DEVVALUES;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NSECTORSIZE:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			dev = &s->ctx->envdevs[s->cdev];
> --			value = (char *)event->data.scalar.value;
> --			dev->sectorsize = strtoull(value, NULL, 0);
> --			s->state = STATE_DEVVALUES;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --	case STATE_NUNLOCK:
> --		switch (event->type) {
> --		case YAML_SCALAR_EVENT:
> --			dev = &s->ctx->envdevs[s->cdev];
> --			value = (char *)event->data.scalar.value;
> --			if (!strcmp(value, "yes"))
> --				dev->disable_mtd_lock = 1;
> --			s->state = STATE_DEVVALUES;
> --			break;
> --		default:
> --			s->error = YAML_UNEXPECTED_STATE;
> --			s->event_type = event->type;
> --			return FAILURE;
> --		}
> --		break;
> --
> --    case STATE_STOP:
> --        break;
> --    }
> --    return SUCCESS;
> --}
> --
> --int parse_yaml_config(struct uboot_ctx **ctxlist, FILE *fp)
> --{
> --	yaml_parser_t parser;
> --	yaml_event_t  event;
> --	enum yaml_status status;
> --	struct parser_state state;
> --	struct uboot_ctx *ctx;
> --
> --	if (!yaml_parser_initialize(&parser))
> --		return -ENOMEM;
> --
> --	 /* Set input file */
> --	yaml_parser_set_input_file(&parser, fp);
> --	memset(&state, 0, sizeof(state));
> --	state.state = STATE_START;
> --	do {
> --		if (!yaml_parser_parse(&parser, &event)) {
> --			status = FAILURE;
> --			goto cleanup;
> --		}
> --		status = consume_event(&state, &event);
> --		yaml_event_delete(&event);
> --		if (status == FAILURE) {
> --			goto cleanup;
> --		}
> --	} while (state.state != STATE_STOP);
> --
> --	state.ctxsets[0].nelem = state.nelem;
> --
> --	for (int i = 0; i < state.nelem; i++) {
> --		ctx = &state.ctxsets[i];
> --		ctx->ctxlist = &state.ctxsets[0];
> --		if (ctx->redundant && !check_compatible_devices(ctx)) {
> --			status = FAILURE;
> --			break;
> --		}
> --	}
> --
> --
> --cleanup:
> --	yaml_parser_delete(&parser);
> --	if (status == FAILURE) {
> --		if (state.ctxsets) free (state.ctxsets);
> --		state.ctxsets = NULL;
> --	}
> --	*ctxlist = state.ctxsets;
> --	return status;
> --}
> --
> - #define LINE_LENGTH 2048
> - int libuboot_load_file(struct uboot_ctx *ctx, const char *filename)
> - {
> diff --git a/patches/libubootenv-0.3.6/0002-extended_config-fix-segfault-on-empty-config.patch b/patches/libubootenv-0.3.6/0002-extended_config-fix-segfault-on-empty-config.patch
> deleted file mode 100644
> index a4574ff5fef6..000000000000
> --- a/patches/libubootenv-0.3.6/0002-extended_config-fix-segfault-on-empty-config.patch
> +++ /dev/null
> @@ -1,40 +0,0 @@
> -From: James Hilliard <james.hilliard1@gmail.com>
> -Date: Thu, 24 Apr 2025 19:53:01 -0600
> -Subject: [PATCH] extended_config: fix segfault on empty config
> -
> -We need to validate that we have nelem and bail out if we don't.
> -
> -Fixes:
> -==245== Invalid write of size 4
> -==245==    at 0x4849E0C: parse_yaml_config (uboot_env.c:1390)
> -==245==    by 0x484A717: libuboot_read_config_ext (uboot_env.c:1484)
> -==245==    by 0x13F253: bootloader_initialize.constprop.0 (uboot.c:45)
> -==245==    by 0x13F457: do_env_set (uboot.c:72)
> -==245==    by 0x12B057: update_transaction_state (stream_interface.c:139)
> -==245==    by 0x12C367: extract_files (stream_interface.c:297)
> -==245==    by 0x12C367: network_initializer (stream_interface.c:658)
> -==245==    by 0x4EA89AF: ??? (in /usr/lib/libc.so.6)
> -==245==    by 0x4F0989B: ??? (in /usr/lib/libc.so.6)
> -==245==  Address 0x2e8 is not stack'd, malloc'd or (recently) free'd
> -
> -Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> ----
> - src/extended_config.c | 5 +++++
> - 1 file changed, 5 insertions(+)
> -
> -diff --git a/src/extended_config.c b/src/extended_config.c
> -index ec814f484efd..45df3ec7a7ca 100644
> ---- a/src/extended_config.c
> -+++ b/src/extended_config.c
> -@@ -428,6 +428,11 @@ int parse_yaml_config(struct uboot_ctx **ctxlist, FILE *fp)
> - 		}
> - 	} while (state.state != STATE_STOP);
> - 
> -+	if (state.nelem == 0) {
> -+		status = FAILURE;
> -+		goto cleanup;
> -+	}
> -+
> - 	state.ctxsets[0].nelem = state.nelem;
> - 
> - 	for (int i = 0; i < state.nelem; i++) {
> diff --git a/patches/libubootenv-0.3.6/0003-BUG-Fix-warning-when-copying-UBI-volume.patch b/patches/libubootenv-0.3.6/0003-BUG-Fix-warning-when-copying-UBI-volume.patch
> deleted file mode 100644
> index 1ead8954860b..000000000000
> --- a/patches/libubootenv-0.3.6/0003-BUG-Fix-warning-when-copying-UBI-volume.patch
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -From: Stefano Babic <stefano.babic@swupdate.org>
> -Date: Tue, 29 Apr 2025 13:49:15 +0200
> -Subject: [PATCH] BUG: Fix warning when copying UBI volume
> -MIME-Version: 1.0
> -Content-Type: text/plain; charset=UTF-8
> -Content-Transfer-Encoding: 8bit
> -
> -Fix:
> -
> -/home/stefano/SWUpdate/libubootenv/src/uboot_mtd.c: In function ‘libubootenv_ubi_update_name’:
> -/home/stefano/SWUpdate/libubootenv/src/uboot_mtd.c:283:17: warning: ‘memset’ writing 256 bytes into a region of size 236 overflows the destination [-Wstringop-overflow=]
> -  283 |                 memset(volume, 0, DEVNAME_MAX_LENGTH);
> -      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -/home/stefano/SWUpdate/libubootenv/src/uboot_mtd.c:223:14: note: destination object ‘volume’ of size 236
> -
> -This can lead to overwrite the buffer for the volumes.
> -
> -Signed-off-by: Stefano Babic <stefano.babic@swupdate.org>
> ----
> - src/uboot_mtd.c | 2 +-
> - 1 file changed, 1 insertion(+), 1 deletion(-)
> -
> -diff --git a/src/uboot_mtd.c b/src/uboot_mtd.c
> -index 81376e4ddc09..24e817d88944 100644
> ---- a/src/uboot_mtd.c
> -+++ b/src/uboot_mtd.c
> -@@ -280,7 +280,7 @@ int libubootenv_ubi_update_name(struct uboot_flash_env *dev)
> - 		memset(device, 0, DEVNAME_MAX_LENGTH);
> - 		memcpy(device, dev->devname, sep - dev->devname);
> - 
> --		memset(volume, 0, DEVNAME_MAX_LENGTH);
> -+		memset(volume, 0, VOLNAME_MAX_LENGTH);
> - 		sscanf(sep + 1, "%s", &volume[0]);
> - 
> - 		dev_id = ubi_get_dev_id(device);
> diff --git a/patches/libubootenv-0.3.6/0004-libubootenv-fix-segfault-due-to-uninitialized-pointe.patch b/patches/libubootenv-0.3.6/0004-libubootenv-fix-segfault-due-to-uninitialized-pointe.patch
> deleted file mode 100644
> index e7ae92fb8562..000000000000
> --- a/patches/libubootenv-0.3.6/0004-libubootenv-fix-segfault-due-to-uninitialized-pointe.patch
> +++ /dev/null
> @@ -1,32 +0,0 @@
> -From: Mohamed-nour Toumi <mohamed.toumi_ext@softathome.com>
> -Date: Mon, 28 Jul 2025 22:25:35 +0200
> -Subject: [PATCH] libubootenv: fix segfault due to uninitialized pointer in
> - config parser
> -
> -Issue: The issue was introduced in commit c478e8d9, which replaced the use of %ms in sscanf() with a calloc()-based workaround for platforms where %ms is not supported (e.g., FreeBSD).
> -However, this change inadvertently introduced a logic flaw: it uses calloc to emulate %ms% in sscanf() but also added 2 free instructions which could lead to free non-allocated memory on tmp when sscanf()
> -is used to perform the dynamic allocation.
> -
> -Fix: Ensure `tmp` is initialized to NULL before each call to sscanf with `%ms`
> -in `libuboot_read_config_ext()`. This prevents `free(tmp)` from crashing
> -when sscanf fails to allocate memory (e.g., due to malformed config lines).
> -
> -Fixes segmentation fault observed when running swupdate with a ubootenv config file.
> -
> -Signed-off-by: Mohamed-nour Toumi <mohamed.toumi_ext@softathome.com>
> ----
> - src/uboot_env.c | 1 +
> - 1 file changed, 1 insertion(+)
> -
> -diff --git a/src/uboot_env.c b/src/uboot_env.c
> -index d8b93dac7479..9641800f4bdc 100644
> ---- a/src/uboot_env.c
> -+++ b/src/uboot_env.c
> -@@ -871,6 +871,7 @@ int libuboot_read_config_ext(struct uboot_ctx **ctxlist, const char *config)
> - 				tmp,
> - #else
> - 		(void)len;
> -+		tmp = NULL;
> - 		ret = sscanf(line, "%ms %lli %zx %zx %lx %d",
> - 				&tmp,
> - #endif
> diff --git a/patches/libubootenv-0.3.6/0005-extended_config.c-Catch-NULL-pointer-for-calloc.patch b/patches/libubootenv-0.3.6/0005-extended_config.c-Catch-NULL-pointer-for-calloc.patch
> deleted file mode 100644
> index 9c89141c7a90..000000000000
> --- a/patches/libubootenv-0.3.6/0005-extended_config.c-Catch-NULL-pointer-for-calloc.patch
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -From: Steffen Kothe <steffen.kothe@skothe.net>
> -Date: Sun, 31 Aug 2025 19:07:56 +0000
> -Subject: [PATCH] extended_config.c: Catch NULL pointer for calloc
> -
> -calloc is not guaranteed to return a valid pointer to a free memory
> -area.
> -
> -Hence check for possible NULL return and fail immediately.
> -
> -Addresses possible CWE-690.
> -
> -Signed-off-by: Steffen Kothe <steffen.kothe@skothe.net>
> -Acked-by: Stefano Babic <stefano.babic@swupdate.org>
> ----
> - src/extended_config.c | 2 ++
> - 1 file changed, 2 insertions(+)
> -
> -diff --git a/src/extended_config.c b/src/extended_config.c
> -index 45df3ec7a7ca..c3782e1fba94 100644
> ---- a/src/extended_config.c
> -+++ b/src/extended_config.c
> -@@ -131,6 +131,8 @@ static int consume_event(struct parser_state *s, yaml_event_t *event)
> - 		case YAML_SCALAR_EVENT:
> - 			value = (char *)event->data.scalar.value;
> - 			newctx = calloc (s->nelem + 1, sizeof(*newctx));
> -+			if (newctx == NULL)
> -+				return FAILURE;
> - 			for (int i = 0; i < s->nelem; i++) {
> - 				newctx[i] = s->ctxsets[i];
> - 			}
> diff --git a/patches/libubootenv-0.3.6/series b/patches/libubootenv-0.3.6/series
> deleted file mode 100644
> index b9356ee68463..000000000000
> --- a/patches/libubootenv-0.3.6/series
> +++ /dev/null
> @@ -1,8 +0,0 @@
> -# generated by git-ptx-patches
> -#tag:base --start-number 1
> -0001-Make-libyaml-optional.patch
> -0002-extended_config-fix-segfault-on-empty-config.patch
> -0003-BUG-Fix-warning-when-copying-UBI-volume.patch
> -0004-libubootenv-fix-segfault-due-to-uninitialized-pointe.patch
> -0005-extended_config.c-Catch-NULL-pointer-for-calloc.patch
> -# 8a759d09e861f42f9d568274b3aeb30b  - git-ptx-patches magic
> diff --git a/rules/libubootenv.make b/rules/libubootenv.make
> index 1ec86693a4e3..8a317d6699eb 100644
> --- a/rules/libubootenv.make
> +++ b/rules/libubootenv.make
> @@ -14,8 +14,8 @@ PACKAGES-$(PTXCONF_LIBUBOOTENV) += libubootenv
>  #
>  # Paths and names
>  #
> -LIBUBOOTENV_VERSION	:= 0.3.6
> -LIBUBOOTENV_MD5		:= 7d6b623e8da435cf36e7fcd419a03e43
> +LIBUBOOTENV_VERSION	:= 0.3.7
> +LIBUBOOTENV_MD5		:= 593b3eb88062955042593eb6ec19e4e6
>  LIBUBOOTENV		:= libubootenv-$(LIBUBOOTENV_VERSION)
>  LIBUBOOTENV_SUFFIX	:= tar.gz
>  LIBUBOOTENV_URL		:= https://github.com/sbabic/libubootenv/archive/refs/tags/v$(LIBUBOOTENV_VERSION).$(LIBUBOOTENV_SUFFIX)



      reply	other threads:[~2026-03-02  9:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-12 10:09 [ptxdist] [PATCH] " Alexander Dahl via ptxdist
2026-03-02  9:25 ` Michael Olbrich [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260302092517.3502252-1-m.olbrich@pengutronix.de \
    --to=m.olbrich@pengutronix.de \
    --cc=ada@thorsis.com \
    --cc=ptxdist@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox