From 9e6093eb7b31a08d4dec98a956972afd08d9881f Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Thu, 16 Oct 2025 16:58:21 +0800 Subject: [PATCH 01/10] system/nxinit: Handle trailing file '\0' When ETC_ROMFS is disabled to reduce the bin size, we can provide the init.rc file via a pseudo-file in the boards/vendor directory. For example: - CONFIG_ETC_ROMFS=n - CONFIG_PSEUDOFS_FILE=y - CONFIG_DISABLE_PSEUDOFS_OPERATIONS=n ```C FAR const char *init_rc = "on init\n" " start console\n"; "service console sh\n" " restart_period 100\n"; int fd = open("/etc/init.d/init.rc", O_WRONLY | O_CREAT); /* ... */ ssize_t n = write(fd, init_rc, strlen(init_rc) + 1); /* ... */ close(fd); ``` The last character '\0' in the file content will be treated as a new line, and the number of parsed parameters will be zero (abnormal, there should be at least one keyword). Signed-off-by: wangjianyu3 --- system/nxinit/parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/nxinit/parser.c b/system/nxinit/parser.c index 3ffe4a5a6f2..cdd85362e49 100644 --- a/system/nxinit/parser.c +++ b/system/nxinit/parser.c @@ -178,6 +178,10 @@ int init_parse_config_file(FAR const struct parser_s *parser, *(nl++) = '\0'; n -= nl - buf; init_debug("Line %3d: '%s'", ++line, buf); + if (*buf == '\0') + { + continue; + } for (ret = 0; parser[ret].key; ret++) { From 0e928416d7f9982a025f702e02d654a06c22d559 Mon Sep 17 00:00:00 2001 From: fangpeina Date: Tue, 18 Nov 2025 22:50:15 +0800 Subject: [PATCH 02/10] system/nxinit: fix compilation errors in action.c action.c uses clock_gettime(CLOCK_MONOTONIC, ...) but did not pull in directly, which fails to build on configurations where the header is not transitively included. Add the missing #include. Signed-off-by: fangpeina --- system/nxinit/action.c | 1 + 1 file changed, 1 insertion(+) diff --git a/system/nxinit/action.c b/system/nxinit/action.c index 81716e571e7..b677e67600e 100644 --- a/system/nxinit/action.c +++ b/system/nxinit/action.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "action.h" #include "builtin.h" From 1edff9e37e481939b17b13151c211558ef56012c Mon Sep 17 00:00:00 2001 From: fangpeina Date: Tue, 18 Nov 2025 23:02:58 +0800 Subject: [PATCH 03/10] system/nxinit: fix uninitialized 'wstatus' warning reap_process() referenced an undeclared identifier 'wtatus' on the WIFSIGNALED branch (typo of 'wstatus'). Some toolchains then flagged a -Wmaybe-uninitialized on the surrounding wstatus use. Correct the typo so WIFSIGNALED/WTERMSIG operate on the actual wstatus value returned by waitpid(). Signed-off-by: fangpeina --- system/nxinit/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/nxinit/init.c b/system/nxinit/init.c index 1a542f79612..978b8a63ba2 100644 --- a/system/nxinit/init.c +++ b/system/nxinit/init.c @@ -90,7 +90,7 @@ static void reap_process(FAR struct service_manager_s *sm, status = "status"; ret = WEXITSTATUS(wstatus); } - else if (WIFSIGNALED(wtatus)) + else if (WIFSIGNALED(wstatus)) { status = "signal"; ret = WTERMSIG(wstatus); From c0815441d458d276917d56f3fa7661a85dd903db Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Thu, 4 Dec 2025 12:30:59 +0800 Subject: [PATCH 04/10] system/nxinit: Fix timespec incomplete error in action.h /.../apps/system/nxinit/action.h:72:19: error: field 'time_run' has incomplete type 72 | struct timespec time_run; | ^~~~~~~~ Signed-off-by: wangjianyu3 --- system/nxinit/action.c | 1 - system/nxinit/action.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/system/nxinit/action.c b/system/nxinit/action.c index b677e67600e..0975682b7e3 100644 --- a/system/nxinit/action.c +++ b/system/nxinit/action.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/system/nxinit/action.h b/system/nxinit/action.h index 672621d1351..908b907b44d 100644 --- a/system/nxinit/action.h +++ b/system/nxinit/action.h @@ -29,6 +29,8 @@ #include +#include + #include "parser.h" /**************************************************************************** From 825aeee19e5e7b16005c8c6eb0e5e1b9e0769d66 Mon Sep 17 00:00:00 2001 From: fangpeina Date: Thu, 4 Dec 2025 18:07:15 +0800 Subject: [PATCH 05/10] system/nxinit: prevent parser from reading past string boundry Any string ending with whitespace passed to init_parse_arguments() could cause the parser to advance past the string boundary and read unintended memory content. - " echo "A" \0& echo "B" should be parsed as a command with two argvs instand of five. - "command arg " may lead to uncertain results. Signed-off-by: fangpeina --- system/nxinit/parser.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/nxinit/parser.c b/system/nxinit/parser.c index cdd85362e49..58da5034081 100644 --- a/system/nxinit/parser.c +++ b/system/nxinit/parser.c @@ -46,7 +46,7 @@ int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv) bool new = true; int i = 0; - while (*buf != '\0') + for (; ; ) { while (isblank(*buf)) { @@ -91,6 +91,11 @@ int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv) } } + if (*buf == '\0') + { + break; + } + if (new) { argv[i++] = buf; From aed85cb99a859ce5664d5e7b6ba3abbca344f962 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Fri, 19 Dec 2025 21:54:19 +0800 Subject: [PATCH 06/10] system/nxinit: Avoid SIGCHLD race with ppoll() Pending all signals(SIGCHLD) when ppoll() is not invoked to avoid race conditions. Case reproduction Set examples/hello as a service that exits immediately after startup. ```init.rc on boot start hello service hello hello restart_period 0 ``` Log - without this patch: # Service hello only restarts about 100 times, ppoll is not woken up # after the hello process with PID 119 exits. [ 4.391274] [ 2] [ 0] init_main: service 'hello' pid 118 exited status 0 [ 4.401423] [ 2] [ 0] init_main: started service 'hello' pid 119 Log - with this patch: # ppoll() can still be woken up normally after tens of thousands of # restarts of service hello in stress test. [ 268.447747] [ 2] [ 0] init_main: service 'hello' pid 34503 exited status 0 Signed-off-by: wangjianyu3 --- system/nxinit/init.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/system/nxinit/init.c b/system/nxinit/init.c index 978b8a63ba2..cc1f181323e 100644 --- a/system/nxinit/init.c +++ b/system/nxinit/init.c @@ -154,9 +154,19 @@ int main(int argc, FAR char *argv[]) }; struct pollfd pfds[nitems(ev)]; + sigset_t mask; size_t i; int r; + sigfillset(&mask); + r = sigprocmask(SIG_BLOCK, &mask, NULL); + sigemptyset(&mask); + if (r < 0) + { + init_err("sigprocmask failed %d", errno); + return r; + } + #ifdef CONFIG_USBDEV_TRACE usbtrace_enable(TRACE_BITSET); #endif @@ -215,7 +225,7 @@ int main(int argc, FAR char *argv[]) break; } - r = ppoll(pfds, nitems(pfds), MS2TIMESPEC(&timeout, t), NULL); + r = ppoll(pfds, nitems(pfds), MS2TIMESPEC(&timeout, t), &mask); if (r < 0 && errno != EINTR) { init_err("Wait event"); From 2cc6d97dbbe1c0b3cb8339434765fbc8c5588c57 Mon Sep 17 00:00:00 2001 From: v-maomingju Date: Mon, 22 Dec 2025 22:30:53 +0800 Subject: [PATCH 07/10] system/nxinit: fix unused variable warning fix the unused variable warnings for name and status in init.c. Signed-off-by: v-maomingju --- system/nxinit/init.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/nxinit/init.c b/system/nxinit/init.c index cc1f181323e..6c7291e5e60 100644 --- a/system/nxinit/init.c +++ b/system/nxinit/init.c @@ -78,6 +78,11 @@ static void reap_process(FAR struct service_manager_s *sm, int ret; int pid; + /* prevent unused warning */ + + UNUSED(name); + UNUSED(status); + for (; ; ) { pid = waitpid(-1, &wstatus, WNOHANG); From 617497a825fd29e69fdba6f3ed82ad33571fbe12 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Fri, 26 Dec 2025 11:58:03 +0800 Subject: [PATCH 08/10] system/nxinit: Fix missing check for import argument Add missing return value check for init_parse_arguments function. Signed-off-by: wangjianyu3 --- system/nxinit/import.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/nxinit/import.c b/system/nxinit/import.c index ca389d396b1..2b656c05937 100644 --- a/system/nxinit/import.c +++ b/system/nxinit/import.c @@ -42,7 +42,13 @@ int init_import_parse(FAR const struct parser_s *parser, if (create) { - init_parse_arguments(buf, false, nitems(argv), argv); + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("parse import: %s", buf); + return -EINVAL; + } + ret = init_parse_config_file(parser, argv[1]); if (ret < 0) { From 75e0f9d0335d8ef19ab743b8ea892f95af23ecf5 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Thu, 25 Dec 2025 15:22:48 +0800 Subject: [PATCH 09/10] system/nxinit: Fix signal mask inheritance The init process has blocked all signals, spawned services would inherit that mask. This could cause services to miss important signals like SIGTERM during graceful shutdown. Signed-off-by: wangjianyu3 --- system/nxinit/builtin.c | 72 ++++++++++++++++++++++++++++++----------- system/nxinit/service.c | 29 ++++++++++++++++- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/system/nxinit/builtin.c b/system/nxinit/builtin.c index d300457f72b..ba7a41bcf68 100644 --- a/system/nxinit/builtin.c +++ b/system/nxinit/builtin.c @@ -183,6 +183,10 @@ static int cmd_exec(FAR struct action_manager_s *am, int init_builtin_run(FAR struct action_manager_s *am, int argc, FAR char **argv) { + char cmd[CONFIG_SYSTEM_NXINIT_RC_LINE_MAX]; + posix_spawnattr_t attr; + FAR char *args[4]; + sigset_t mask; pid_t pid; size_t i; int ret; @@ -203,35 +207,65 @@ int init_builtin_run(FAR struct action_manager_s *am, } } - ret = posix_spawnp(&pid, argv[0], NULL, NULL, argv, NULL); + ret = posix_spawnattr_init(&attr); if (ret != 0) { -#ifdef CONFIG_SYSTEM_SYSTEM - char cmd[CONFIG_SYSTEM_NXINIT_RC_LINE_MAX]; + init_err("posix_spawnattr_init %d", ret); + return -ret; + } - for (i = 0, cmd[i] = '\0'; i < argc; i++) + ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK); + if (ret != 0) + { + init_err("posix_spawnattr_setflags %d", ret); + posix_spawnattr_destroy(&attr); + return -ret; + } + + sigemptyset(&mask); + ret = posix_spawnattr_setsigmask(&attr, &mask); + if (ret != 0) + { + init_err("posix_spawnattr_setsigmask %d", ret); + posix_spawnattr_destroy(&attr); + return -ret; + } + + for (i = 0, cmd[i] = '\0'; i < argc; i++) + { + strlcat(cmd, argv[i], sizeof(cmd)); + if (i < argc - 1) { - strlcat(cmd, argv[i], sizeof(cmd)); - if (i < argc - 1) - { - strcat(cmd, " "); - } + strcat(cmd, " "); + } + } + + for (; ; ) + { + ret = posix_spawnp(&pid, argv[0], NULL, &attr, argv, NULL); + if (ret == 0) + { + init_debug("executed command '%s' pid %d", cmd, pid); + break; } - init_debug("Executing nsh command '%s'", cmd); - ret = system(cmd); - if (WIFEXITED(ret)) + if (!strcmp("sh", argv[0])) { - init_debug("NSH command '%s' exited %d", cmd, WEXITSTATUS(ret)); - return -WEXITSTATUS(ret); + init_err("executing command '%s': %d", cmd, ret); + init_dump_args(argc, argv); + pid = -ret; + break; } -#endif - init_err("Executing command '%s': %d", argv[0], ret); - init_dump_args(argc, argv); - return -ret; + init_debug("command '%s': %d", argv[0], ret); + args[0] = "sh"; + args[1] = "-c"; + args[2] = cmd; + args[3] = NULL; + argc = nitems(args) - 1; + argv = args; } - init_debug("Executed command '%s' pid %d", argv[0], pid); + posix_spawnattr_destroy(&attr); return pid; } diff --git a/system/nxinit/service.c b/system/nxinit/service.c index 7f582e6e4fb..7e840e7e722 100644 --- a/system/nxinit/service.c +++ b/system/nxinit/service.c @@ -427,6 +427,8 @@ void init_service_reap(FAR struct service_s *service, int status) int init_service_start(FAR struct service_s *service) { + posix_spawnattr_t attr; + sigset_t mask; int ret; int pid; @@ -439,8 +441,33 @@ int init_service_start(FAR struct service_s *service) return service->pid; } - ret = posix_spawnp(&pid, service->argv[2], NULL, NULL, &service->argv[2], + ret = posix_spawnattr_init(&attr); + if (ret != 0) + { + init_err("posix_spawnattr_init %d", ret); + return -ret; + } + + ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK); + if (ret != 0) + { + init_err("posix_spawnattr_setflags %d", ret); + posix_spawnattr_destroy(&attr); + return -ret; + } + + sigemptyset(&mask); + ret = posix_spawnattr_setsigmask(&attr, &mask); + if (ret != 0) + { + init_err("posix_spawnattr_setsigmask %d", ret); + posix_spawnattr_destroy(&attr); + return -ret; + } + + ret = posix_spawnp(&pid, service->argv[2], NULL, &attr, &service->argv[2], environ); + posix_spawnattr_destroy(&attr); if (ret != 0) { init_err("Starting service '%s': %d", service->argv[1], ret); From 58045449ef1815169db76b2a44438b3d8bf0d081 Mon Sep 17 00:00:00 2001 From: fangpeina Date: Wed, 28 Jan 2026 19:48:25 +0800 Subject: [PATCH 10/10] system/nxinit: fix init parser to handle multiple quoted arguments Fix argument parsing in init_parse_arguments() to properly handle multiple quoted arguments like 'echo "arg1" "arg2"' by skipping quote characters after processing them. Signed-off-by: fangpeina --- system/nxinit/parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/system/nxinit/parser.c b/system/nxinit/parser.c index 58da5034081..60b189afd4a 100644 --- a/system/nxinit/parser.c +++ b/system/nxinit/parser.c @@ -82,6 +82,7 @@ int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv) if (quote) { quote = false; + buf++; } else {