From a7c95cd3c614a34d130961ace3828dc63167bdb7 Mon Sep 17 00:00:00 2001 From: Peter Woxblom Date: Mon, 17 Aug 2026 08:15:52 +0200 Subject: [PATCH] confd: set IITO startup/failure conditions (fixes status LEDs) The product and common iitod.json configurations reference finit conditions to drive the status LEDs, but nothing ever creates them, so the LEDs stay dark on every boot. confd now signals the outcome of the bootstrap sequence via finit conditions in the usr/ namespace: usr/bootstrap bootstrap entered (Finit guarantees /run/finit/cond/usr exists) usr/startup-config-ok startup-config applied cleanly usr/startup-config-error startup-config failed, fail-secure mode usr/failure-config-ok failure-config (or factory default) loaded usr/failure-config-error failure-config could not be applied The IITO configuration is updated to reference the new condition names, and the failure paths now emit a CRITICAL ERROR banner so the user always gets feedback when the system is left without a defined configuration. Co-authored-by: Jarvis (Hermes Agent) --- .../friendlyarm,nanopi-r2s/etc/iitod.json | 6 ++--- board/common/rootfs/etc/iitod.json | 6 ++--- src/confd/src/main.c | 27 +++++++++++++++++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/iitod.json b/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/iitod.json index ef95038ab..714010f03 100644 --- a/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/iitod.json +++ b/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/iitod.json @@ -15,9 +15,9 @@ "wan-up": { "path": "/run/led/wan-up" }, - "startup": { "path": "/run/finit/cond/run/startup/success" }, - "fail-safe": { "path": "/run/finit/cond/run/failure/success" }, - "panic": { "path": "/run/finit/cond/run/failure/failure" } + "startup": { "path": "/run/finit/cond/usr/startup-config-ok" }, + "fail-safe": { "path": "/run/finit/cond/usr/failure-config-ok" }, + "panic": { "path": "/run/finit/cond/usr/failure-config-error" } }, "udev": { "power-a": { "subsystem": "power_supply" }, diff --git a/board/common/rootfs/etc/iitod.json b/board/common/rootfs/etc/iitod.json index d214be9b3..047c341a4 100644 --- a/board/common/rootfs/etc/iitod.json +++ b/board/common/rootfs/etc/iitod.json @@ -18,9 +18,9 @@ "lan-err": { "path": "/run/led/lan-err" }, "lan-crit": { "path": "/run/led/lan-crit" }, - "startup": { "path": "/run/finit/cond/run/startup/success" }, - "fail-safe": { "path": "/run/finit/cond/run/failure/success" }, - "panic": { "path": "/run/finit/cond/run/failure/failure" } + "startup": { "path": "/run/finit/cond/usr/startup-config-ok" }, + "fail-safe": { "path": "/run/finit/cond/usr/failure-config-ok" }, + "panic": { "path": "/run/finit/cond/usr/failure-config-error" } }, "udev": { "power-a": { "subsystem": "power_supply" }, diff --git a/src/confd/src/main.c b/src/confd/src/main.c index f679d9df6..f87442b0f 100644 --- a/src/confd/src/main.c +++ b/src/confd/src/main.c @@ -49,6 +49,23 @@ */ #define SENTINEL_PATH "/run/confd.boot" +/* + * Set a finit condition in the usr/ namespace, e.g. + * "usr/startup-config-ok", used to signal IITO (and finit services) about + * the outcome of the bootstrap/startup sequence. Finit guarantees + * /run/finit/cond/usr exists (via its tmpfiles snippet), so no parent + * directories are created here. + */ +static void set_finit_cond(const char *cond) +{ + char path[128]; + snprintf(path, sizeof(path), "/run/finit/cond/usr/%s", cond); + + + if (symlink("/run/finit/cond/reconf", path) && errno != EEXIST) + WARN("Failed to set finit condition %s: %m", path); +} + /* Callback type names from sysrepo plugin API */ #define SRP_INIT_CB "sr_plugin_init_cb" #define SRP_CLEANUP_CB "sr_plugin_cleanup_cb" @@ -505,27 +522,32 @@ static void handle_startup_failure(sr_session_ctx_t *sess, const char *failure_p int r; ERROR("Failed loading startup-config, reverting to Fail Secure mode!"); + set_finit_cond("startup-config-error"); /* Reset to factory-default */ r = sr_copy_config(sess, NULL, SR_DS_FACTORY_DEFAULT, timeout_ms); if (r != SR_ERR_OK) { ERROR("sr_copy_config(factory-default) failed: %s", sr_strerror(r)); /* Nuclear option: wipe everything */ + banner_append("CRITICAL ERROR: Logins are disabled, no credentials available"); systemf("rm -f /etc/sysrepo/data/*startup* /etc/sysrepo/data/*running* /dev/shm/sr_*"); + set_finit_cond("failure-config-error"); return; } /* Load failure-config on top */ if (fexist(failure_path)) { if (load_config(conn, sess, failure_path, timeout_ms)) { - ERROR("Failed loading failure-config, aborting!"); + ERROR("failed applying failure-config, aborting!"); banner_append("CRITICAL ERROR: Logins are disabled, no credentials available"); systemf("initctl -nbq runlevel 9"); + set_finit_cond("failure-config-error"); return; } } banner_append("ERROR: Corrupt startup-config, system has reverted to default login credentials"); + set_finit_cond("failure-config-ok"); } /* @@ -587,6 +609,7 @@ static int bootstrap_config(sr_conn_ctx_t *conn, sr_session_ctx_t *sess, if (r != SR_ERR_OK) WARN("Failed to sync startup datastore: %s", sr_strerror(r)); + set_finit_cond("startup-config-ok"); return 0; } @@ -841,7 +864,7 @@ int main(int argc, char **argv) quiet_now(); /* Signal that bootstrap is complete (dbus, resolvconf depend on this) */ - symlink("/run/finit/cond/reconf", "/run/finit/cond/usr/bootstrap"); + set_finit_cond("bootstrap"); /* * Write restart sentinel. From this point on, sysrepo and the system