From patchwork Sun Mar 26 12:41:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Babic X-Patchwork-Id: 1761233 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::138; helo=mail-lf1-x138.google.com; envelope-from=swupdate+bncbcxploxj6ikrb3x2qcqqmgqepz54vva@googlegroups.com; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20210112 header.b=dG4b5/az; dkim-atps=neutral Received: from mail-lf1-x138.google.com (mail-lf1-x138.google.com [IPv6:2a00:1450:4864:20::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PkwYN5Tb1z1yXv for ; Sun, 26 Mar 2023 23:41:26 +1100 (AEDT) Received: by mail-lf1-x138.google.com with SMTP id a14-20020a19ca0e000000b004e95c80075asf2309732lfg.3 for ; Sun, 26 Mar 2023 05:41:26 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1679834479; cv=pass; d=google.com; s=arc-20160816; b=YdqEbyE08yC5qJiDujb50O+QXBi7TyrkihmyW8ygFlp9RuY7v/ghLuNguCr3YGbuL0 FfjDPCasDES5J4ja0ED4LXVR5jQXzh+hrlK0rQCx8iXFRnWfHa+2wWRnugduSq/85AkL YqzuBMgqVX6CawiTq1YWlWjxOe5vH3vqP/Z6088lcH/vAqLcfUQuG/yu8rWbX7mnPpNz UGwt61KedKMx5jNhk4JwvbygkFWRuEEXnwQRs4N5pT3UejuUGsXS+EzPrcwmHlRbsTkw VZ4UaU5D+JKjQEi3/HAwK9aDuviFc4hfx8id3IzNojd9uLcAbZ4MGdMv4iZa1qkeH8hQ luEw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:message-id:date :subject:cc:to:from:sender:dkim-signature; bh=2wVYUufBx9CSD9/wItmCsyWTy7rxqptTy0S3ZBSyqYM=; b=Op/DGvjyBmQ9Pzs4g+MLiw/ffPUEIW0PiAz0qG6gdAxPyS/vykWhbHqPdhx9mKQbYF nSmTQem7ttxg6CqILdQRq0HXKOGipHJ9c0g6yc2SuGA1TGNNKqaYiYIGiRP8s2CR1ztN 64vCiKsCsNy4DAVVE6/nn6Th4Dwz888rKK227v4kAywn8xgmvbikIdsAH87yf1rxhz69 vLMkxlW2R1dM5WHbVw3kHi4o1nhotMsx0bzGE5VlJtMUxyLJp6wpZGoLRxBm8XFOG7GU 7byNjJvhB2CsGZg/R8bG3A55VM0VhPN43fyBx4fd4dZsafSgON4Ek9VxfL12nn+Mxfe3 pVVA== ARC-Authentication-Results: i=2; gmr-mx.google.com; spf=neutral (google.com: 212.18.0.9 is neither permitted nor denied by domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20210112; t=1679834479; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:message-id:date:subject:cc:to:from :sender:from:to:cc:subject:date:message-id:reply-to; bh=2wVYUufBx9CSD9/wItmCsyWTy7rxqptTy0S3ZBSyqYM=; b=dG4b5/az9HdqIe7r0CrT6RvEbIwZ3bc8AvLLRRqD5X+XikYvgawlNvrDeGOg7plhAh LN1e6u6JmrUvmadXaJSx+S3Fe6mhH5epxUA+e4VL12/Elhk4os/v+olXn1mZrXyUeW0c ADCzyDhVUj4er5xkyy67AO85PrqAuDYbNWgSNpkOKGf6M+DaniPlB5NG9CzCEwhdmSi9 5Lo5j0FykApyqlxLQdruAxZ3xUwsSlMzsn4IjAQzYLeWoVYauMNSbf6a6IYUcp06HzNX r0mgNjIVxPoHu9u2CGM1yvvjKa+sU0QpdewicTuuXOa7WToUJmFc5b77HKYSEGFvvqH2 p3zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679834479; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :message-id:date:subject:cc:to:from:x-gm-message-state:sender:from :to:cc:subject:date:message-id:reply-to; bh=2wVYUufBx9CSD9/wItmCsyWTy7rxqptTy0S3ZBSyqYM=; b=aVI51cJ2P3aQEh29eqHUUvF3A7qID2y5FtoUAgq+D18Wcitfzvpmq/orJAHCGaUg31 pB3Si49NRHLyYRFH4qY10UY9Yay1vh4OXhGLnXm3sevgom7YfG+XJvTQyT6ldYIkbWqi r9QYiYgKo9houLGruijzHvEel7erM4k9/uwmTVKD5dfSxLvqMAXpGjh4WNc+je8wwyck w+7wYUGI+P6+Bm7zwCEhuXBZIJXCeYIgzRUlZ1OXMUfVYStwuY3IY9/+ZbgLk03tRWM3 +1OB0sB0lgWvzq6D2AiZon/OE8DBhImF7PfhmSasH/dWg/oLRWbt3405IAzUmnpFfb0x KB2Q== Sender: swupdate@googlegroups.com X-Gm-Message-State: AAQBX9dFggXlw/DYPShYi+KNF2IV/vNHR1dpXUSCgUy7JBDDqf3AXrLg okG1FplRFhM6HobL+CngJIU= X-Google-Smtp-Source: AKy350Z8yd+bAzFSVD1gBygatV2s8vLyDEAgT6EuPF63j+e8OK1HHhAqdJ1Hcxc03surCMOGTNlRsA== X-Received: by 2002:a19:ee1a:0:b0:4d5:ca32:689b with SMTP id g26-20020a19ee1a000000b004d5ca32689bmr2452413lfb.0.1679834479063; Sun, 26 Mar 2023 05:41:19 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6512:1585:b0:4e9:c006:ce26 with SMTP id bp5-20020a056512158500b004e9c006ce26ls226775lfb.3.-pod-prod-gmail; Sun, 26 Mar 2023 05:41:17 -0700 (PDT) X-Received: by 2002:ac2:4c95:0:b0:4e7:fa8a:886e with SMTP id d21-20020ac24c95000000b004e7fa8a886emr2822795lfl.51.1679834477267; Sun, 26 Mar 2023 05:41:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679834477; cv=none; d=google.com; s=arc-20160816; b=0qOaRlJ1xFnWgiHn2r9lCNoQ83y2xHyCR++vmXDzPCJT4fdkXXHFeDvBWEWlDupfb+ B/1LsB/s1jZzk2f9ZqVGyT7049QgMJ5lRCuAHtc4PRYU01Fi4s0w/B3PxEd5UJSjlexk t0hJ2xqlpLv4r3jlWSKsj0006m1TWz02XvAD+StygskSMAOe9kPe+6U+rfQONQgRRyAL XyCOfObkaD5qGL4PiDWrxc6OM78liHFnemZl3Sjf0UvgFvnugNKKm0/QJ0jni3gOcs+k SzjIYAlpL9gmL84BeVCzzTiZKbYW64R4r1jUYtJR0x4hax1s6Hd3tdPZRqZp666n1zAm 4L1g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from; bh=4kSfHbGixWpXnVvPZL1IS65u66JPL98OtHzZGEXOS74=; b=F4g2Ny5qcKPDDH5BwStU4X84D6UQH4e6FiTNayy9SJpANiEjC6/F/KHbT9GZOT7VM8 ZtrbnEP57qR7D6Cp+qKZKK/8QUgae3G7J3AnFJZG/jFopQXjlb+b9R14sF+yfdzHOtdV b0541ZuMNE+1VVJJ9Sb2GSs8WIBE6SP9IOSpmu8FjsAXjcDjKvim7Z+2m2QsXBIXNajT 0S+2urlG7UajT/0eUYOVed5+ZsW2QSOiNVtM5WWMJUmnRo5pimp7owdU73Hi89NJvIbn ktl/Yqaq5kZj2ppI9/Ex8va9YQ4I5cqvCwYB3YHY3oxoXnqzFbA0fjy+Bx8vsB5kOU1J Kfvg== ARC-Authentication-Results: i=1; gmr-mx.google.com; spf=neutral (google.com: 212.18.0.9 is neither permitted nor denied by domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de Received: from mail-out.m-online.net (mail-out.m-online.net. [212.18.0.9]) by gmr-mx.google.com with ESMTPS id h4-20020a056512220400b004dd84067a4asi1264650lfu.4.2023.03.26.05.41.17 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 26 Mar 2023 05:41:17 -0700 (PDT) Received-SPF: neutral (google.com: 212.18.0.9 is neither permitted nor denied by domain of sbabic@denx.de) client-ip=212.18.0.9; Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4PkwY83rhJz1r1fc; Sun, 26 Mar 2023 14:41:16 +0200 (CEST) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4PkwY83c48z1qqlS; Sun, 26 Mar 2023 14:41:16 +0200 (CEST) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id p9PMKNn6I2kQ; Sun, 26 Mar 2023 14:41:14 +0200 (CEST) Received: from babic.homelinux.org (host-88-217-136-221.customer.m-online.net [88.217.136.221]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPS; Sun, 26 Mar 2023 14:41:14 +0200 (CEST) Received: from localhost (mail.babic.homelinux.org [127.0.0.1]) by babic.homelinux.org (Postfix) with ESMTP id BFB444540B90; Sun, 26 Mar 2023 14:41:13 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at babic.homelinux.org Received: from babic.homelinux.org ([127.0.0.1]) by localhost (mail.babic.homelinux.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HOoEBUmo--Qa; Sun, 26 Mar 2023 14:41:10 +0200 (CEST) Received: from paperino.fritz.box (paperino.fritz.box [192.168.178.48]) by babic.homelinux.org (Postfix) with ESMTP id 9BEF54540625; Sun, 26 Mar 2023 14:41:10 +0200 (CEST) From: Stefano Babic To: swupdate@googlegroups.com Cc: Stefano Babic Subject: [swupdate] [libubootenv][PATCH] Add new configuration file in YAML Date: Sun, 26 Mar 2023 14:41:08 +0200 Message-Id: <20230326124108.152837-1-sbabic@denx.de> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Original-Sender: sbabic@denx.de X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 212.18.0.9 is neither permitted nor denied by domain of sbabic@denx.de) smtp.mailfrom=sbabic@denx.de Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Legacy configuration file was taken by U-Boot project. Its format is very simple, but unflexible and it cannot be extended. Changes in the format could lead to uncompatibility with U-Boot tools, tht are still part of U-Boot. This introduce a new format, letting the old format as fallback if YAML cannot be parsed. It uses the libyaml library. Multiple sets can be configured - an environment is not bound with the bootloader, and can be used for other purposes, but still having the features provided by the handling for the bootloader (redundancy, power-cut safe). See documentation for the format of the yaml file. Each not recogniyed keyword generates an error. Signed-off-by: Stefano Babic --- docs/fw_env_config.md | 40 ++++- src/CMakeLists.txt | 2 +- src/fw_printenv.c | 37 +++- src/libuboot.h | 17 ++ src/uboot_env.c | 399 +++++++++++++++++++++++++++++++++++++++++- src/uboot_private.h | 9 + 6 files changed, 489 insertions(+), 15 deletions(-) diff --git a/docs/fw_env_config.md b/docs/fw_env_config.md index d9a212c..757f06d 100644 --- a/docs/fw_env_config.md +++ b/docs/fw_env_config.md @@ -3,10 +3,12 @@ SPDX-FileCopyrightText: 2019-2021 Stefano Babic SPDX-License-Identifier: LGPL-2.1-or-later --> -fw_env.config Configuration File -================================ +fw_env.config Configuration File- Legacy format +================================================ + +This is the configuration file for fw_{printenv,setenv} utility. It was defined in U-Boot project +and it is defined here as legacy format. -This is the configuration file for fw_{printenv,setenv} utility. Up to two entries are valid, in this case the redundant environment sector is assumed present. Notice, that the "Number of Sectors" is not required on NOR and SPI dataflash. @@ -94,3 +96,35 @@ UBI Volume by Name Example |------------------|---------------|------------------|-------------------|-------------------|------------------------| | /dev/ubi0:env | 0x0 | 0x1f000 | 0x1f000 | | | | /dev/ubi0:redund | 0x0 | 0x1f000 | 0x1f000 | | | + +Configuration File in YAML +========================== + +A YAML format is defined to allow multiple sets of variable. This lets have same features (redundancy, power-cut safe) for +environment that are not bound to the U-Boot bootloader. + +uboot: + size : 0x4000 + lockfile : /var/lock/fw_printenv.lock + devices: + - path : /dev/mtd0 + offset : 0xA0000 + sectorsize : 0x10000 + unlock : yes + - path : /dev/mtd0 + offset : 0xB0000 + sectorsize : 0x10000 + disable-lock : yes + +appvar: + size : 0x4000 + lockfile : /var/lock/appvar.lock + devices: + - path : /dev/mtd1 + offset : 0 + sectorsize : 0x10000 + unlock : yes + - path : /dev/mtd1 + offset : 0x10000 + sectorsize : 0x10000 + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index de4162b..ababe0f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,7 @@ 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) +target_link_libraries(ubootenv z yaml) 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/fw_printenv.c b/src/fw_printenv.c index b2d3599..1d9a35e 100644 --- a/src/fw_printenv.c +++ b/src/fw_printenv.c @@ -37,6 +37,7 @@ static struct option long_options[] = { {"config", required_argument, NULL, 'c'}, {"defenv", required_argument, NULL, 'f'}, {"script", required_argument, NULL, 's'}, + {"namespace", required_argument, NULL, 'm'}, {NULL, 0, NULL, 0} }; @@ -49,6 +50,7 @@ static void usage(char *program, bool setprogram) " -h, --help : print this help\n" " -c, --config : configuration file (by default: " DEFAULT_CFG_FILE ")\n" " -f, --defenv : default environment if no one found (by default: " DEFAULT_ENV_FILE ")\n" + " -m, --namespace : chose one of sets in the YAML file, default first in YAML\n" " -V, --version : print version and exit\n" ); if (!setprogram) @@ -74,11 +76,12 @@ static void usage(char *program, bool setprogram) } int main (int argc, char **argv) { - struct uboot_ctx *ctx; - char *options = "Vc:f:s:nh"; + struct uboot_ctx *ctx = NULL; + char *options = "Vc:f:s:nhm:"; char *cfgfname = NULL; char *defenvfile = NULL; char *scriptfile = NULL; + char *namespace = NULL; int c, i; int ret = 0; void *tmp; @@ -120,6 +123,9 @@ int main (int argc, char **argv) { case 'f': defenvfile = strdup(optarg); break; + case 'm': + namespace = strdup(optarg); + break; case 's': scriptfile = strdup(optarg); break; @@ -129,17 +135,30 @@ int main (int argc, char **argv) { argc -= optind; argv += optind; - if (libuboot_initialize(&ctx, NULL) < 0) { - fprintf(stderr, "Cannot initialize environment\n"); - exit(1); - } if (!cfgfname) cfgfname = DEFAULT_CFG_FILE; - if ((ret = libuboot_read_config(ctx, cfgfname)) < 0) { - fprintf(stderr, "Configuration file wrong or corrupted\n"); - exit (ret); + /* + * Try first new format, fallback to legacy + */ + ret = libuboot_read_multiple_config(&ctx, cfgfname); + if (ret) { + if (libuboot_initialize(&ctx, NULL) < 0) { + fprintf(stderr, "Cannot initialize environment\n"); + exit(1); + } + if ((ret = libuboot_read_config(ctx, cfgfname)) < 0) { + fprintf(stderr, "Configuration file wrong or corrupted\n"); + exit (ret); + } + } else { + if (namespace) + ctx = libuboot_get_namespace(ctx, namespace); + if (!ctx) { + fprintf(stderr, "Namespace %s not found\n", namespace); + exit (1); + } } if (!defenvfile) diff --git a/src/libuboot.h b/src/libuboot.h index e59d0c4..f7a5fb9 100644 --- a/src/libuboot.h +++ b/src/libuboot.h @@ -43,6 +43,23 @@ struct uboot_env_device { */ int libuboot_read_config(struct uboot_ctx *ctx, const char *config); +/** @brief Read multiple environment configuration from a file + * + * @param[in] ctx libuboot context + * @param[in] config path to the configuration file in yaml format + * @return 0 in case of success, else negative value + */ +int libuboot_read_multiple_config(struct uboot_ctx **ctxlist, const char *config); + +/** @brief Get ctx from list + * + * @param[in] ctxlist libuboot context array + * @param[in] name name identifier for the single ctx + * @return 0 in case of success, else negative value + */ +struct uboot_ctx *libuboot_get_namespace(struct uboot_ctx *ctxlist, const char *name); + + /** @brief Read U-Boot environment configuration from structure * * @param[in] ctx libuboot context diff --git a/src/uboot_env.c b/src/uboot_env.c index a8e2e50..1662ba8 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c @@ -9,7 +9,7 @@ * @file uboot_env.c * * @brief This is the implementation of libubootenv library - * + * */ #define _GNU_SOURCE @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -56,11 +57,54 @@ #define MTDUNLOCK(dev, psector) \ if (!dev->disable_mtd_lock) ioctl (dev->fd, MEMUNLOCK, psector) +/* 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_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_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 */ +}; + /* * The lockfile is the same as defined in U-Boot for * the fw_printenv utilities */ -static const char *lockname = "/var/lock/fw_printenv.lock"; + static const char *lockname = "/var/lock/fw_printenv.lock"; static int libuboot_lock(struct uboot_ctx *ctx) { int lockfd = -1; @@ -1146,6 +1190,315 @@ static int libuboot_load(struct uboot_ctx *ctx) return ctx->valid ? 0 : -ENODATA; } +int consume_event(struct parser_state *s, yaml_event_t *event) +{ + char *value; + struct uboot_flash_env *dev; + 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: + struct uboot_ctx *newctx; + 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 { + 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_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 1024 int libuboot_load_file(struct uboot_ctx *ctx, const char *filename) { @@ -1198,6 +1551,24 @@ int libuboot_load_file(struct uboot_ctx *ctx, const char *filename) return 0; } +int libuboot_read_multiple_config(struct uboot_ctx **ctxlist, const char *config) +{ + FILE *fp; + int ret; + + if (!config) + return -EINVAL; + + fp = fopen(config, "r"); + if (!fp) + return -EBADF; + + ret = parse_yaml_config(ctxlist, fp); + fclose(fp); + + return ret; +} + int libuboot_read_config(struct uboot_ctx *ctx, const char *config) { FILE *fp; @@ -1466,6 +1837,28 @@ int libuboot_configure(struct uboot_ctx *ctx, return 0; } +struct uboot_ctx *libuboot_get_namespace(struct uboot_ctx *ctxlist, const char *name) +{ + struct uboot_ctx *ctx; + int i; + + if (!ctxlist) + return NULL; + + /* + * Be sure to get the whole list, pointer is stored into each + * CTX pointer in the list + */ + if (ctxlist->ctxlist) + ctxlist = ctxlist->ctxlist; + for (i = 0, ctx = ctxlist; i < ctxlist->nelem; i++, ctx++) { + if (!strcmp(ctx->name, name)) + return ctx; + } + + return NULL; +} + int libuboot_initialize(struct uboot_ctx **out, struct uboot_env_device *envdevs) { struct uboot_ctx *ctx; @@ -1515,5 +1908,7 @@ void libuboot_close(struct uboot_ctx *ctx) { } void libuboot_exit(struct uboot_ctx *ctx) { + if (ctx->ctxlist) + ctx = ctx->ctxlist; free(ctx); } diff --git a/src/uboot_private.h b/src/uboot_private.h index 25cc468..40e5446 100644 --- a/src/uboot_private.h +++ b/src/uboot_private.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "libuboot.h" @@ -125,4 +126,12 @@ struct uboot_ctx { int lock; /** pointer to the internal db */ struct vars varlist; + /** name of the set */ + char *name; + /** lockfile */ + char *lockfile; + /** Number of namespaces */ + int nelem; + /** private pointer to list */ + struct uboot_ctx *ctxlist; };