This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 84e87a5158134b867480a9ac01070e6917ff5311
Author: wangjianyu3 <[email protected]>
AuthorDate: Fri Oct 10 21:48:38 2025 +0800

    system/nxinit: Add reboot_on_failure for service
    
    Add support for the reboot_on_failure option to the service.
    
    When the execution of a command within a certain action fails (returning
    a non-zero status code), NxInit will continue to execute subsequent 
commands or
    actions and will not proactively terminate the startup process. To implement
    the functionality of "terminating the startup process after a command
    execution fails", there are two methods:
    a. Execute conditional statements (if/then/else/fi) via exec command,
       but this depends on sh:
       ```
       on init
           exec -- set +e; \
                   mount -t fatfs /dev/data /data ; \
                   if [ $? -ne 0 ] ; \
                   then \
                     echo "failed" ; \
                     reboot ; \
                   else \
                     echo "succeed" ; \
                   fi;
       ```
    b. Via service's oneshot + reboot_on_failure:
       /* Although the example uses sh, it does not depend on it and can be
        * replaced with any other Builtin Apps.
        */
       ```
       on init
           exec_start mkdir_tmp
           ls /tmp
    
       service mkdir_tmp sh -c "mkdir /tmp"
           reboot_on_failure 0
           oneshot
       ```
    
    Test
      - RC
          service console sh
              class core
              override
        >     reboot_on_failure 0
              restart_period 10000
      - Runtime
          [    0.150000] [ 3] [ 0] init_main: == Dump Services ==
          ...
          [    0.170000] [ 3] [ 0] init_main: Service 0x40486ea0 name 'console' 
path 'sh'
          [    0.170000] [ 3] [ 0] init_main:   pid: 0
          [    0.170000] [ 3] [ 0] init_main:   arguments:
          [    0.170000] [ 3] [ 0] init_main:       [0] 'service'
          [    0.170000] [ 3] [ 0] init_main:       [1] 'console'
          [    0.170000] [ 3] [ 0] init_main:       [2] 'sh'
          [    0.170000] [ 3] [ 0] init_main:   classes:
          [    0.170000] [ 3] [ 0] init_main:     'core'
          [    0.170000] [ 3] [ 0] init_main:   restart_period: 10000
        > [    0.170000] [ 3] [ 0] init_main:   reboot_on_failure: 0
          [    0.170000] [ 3] [ 0] init_main:   flags:
          [    0.170000] [ 3] [ 0] init_main:     'override'
          ...
          [    0.380000] [ 3] [ 0] init_main: started service 'console' pid 4
          ...
          nsh> kill -9 4
          [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000004 
add 0x4
          [    8.060000] [ 3] [ 0] init_main:   -flag 'running'
          [    8.060000] [ 3] [ 0] init_main: service 'console' flag 0x20000000 
add 0x8
          [    8.060000] [ 3] [ 0] init_main:   +flag 'restarting'
        > [    8.060000] [ 3] [ 0] init_main: Error reboot on failure of 
service 'console' reason 0
    
    Signed-off-by: wangjianyu3 <[email protected]>
---
 system/nxinit/init.c    |  9 +++++----
 system/nxinit/service.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 system/nxinit/service.h |  8 +++++++-
 3 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/system/nxinit/init.c b/system/nxinit/init.c
index 52b71728f..a1482f693 100644
--- a/system/nxinit/init.c
+++ b/system/nxinit/init.c
@@ -75,6 +75,7 @@ static void reap_process(FAR struct service_manager_s *sm,
   FAR const char *status;
   FAR struct service_s *service;
   int wstatus;
+  int ret;
   int pid;
 
   for (; ; )
@@ -93,12 +94,12 @@ static void reap_process(FAR struct service_manager_s *sm,
       else if (WIFEXITED(wstatus))
         {
           status = "status";
-          wstatus = WEXITSTATUS(wstatus);
+          ret = WEXITSTATUS(wstatus);
         }
       else if (WIFSIGNALED(wtatus))
         {
           status = "signal";
-          wstatus = WTERMSIG(wstatus);
+          ret = WTERMSIG(wstatus);
         }
       else
         {
@@ -115,12 +116,12 @@ static void reap_process(FAR struct service_manager_s *sm,
       if (service != NULL)
         {
           name = service->argv[1];
-          init_service_reap(service);
+          init_service_reap(service, ret);
         }
 
       init_log(service ? LOG_WARNING : LOG_DEBUG,
                "%s '%s' pid %d exited %s %d",
-               service ? "Service" : "Command", name, pid, status, wstatus);
+               service ? "Service" : "Command", name, pid, status, ret);
     }
 }
 
diff --git a/system/nxinit/service.c b/system/nxinit/service.c
index 49f4d4c49..0d39bb614 100644
--- a/system/nxinit/service.c
+++ b/system/nxinit/service.c
@@ -25,6 +25,7 @@
  ****************************************************************************/
 
 #include <nuttx/clock.h>
+#include <sys/boardctl.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -99,6 +100,10 @@ static int option_override(FAR struct service_manager_s *sm,
                            int argc, FAR char **argv);
 static int option_oneshot(FAR struct service_manager_s *sm,
                           int argc, FAR char **argv);
+#ifdef CONFIG_BOARDCTL_RESET
+static int option_reboot_on_failure(FAR struct service_manager_s *sm,
+                                    int argc, FAR char **argv);
+#endif
 
 /****************************************************************************
  * Private Data
@@ -111,6 +116,9 @@ static const struct cmd_map_s g_option[] =
   {"restart_period", 2, 2, option_restart_period},
   {"override", 1, 1, option_override},
   {"oneshot", 1, 1, option_oneshot},
+#ifdef CONFIG_BOARDCTL_RESET
+  {"reboot_on_failure", 2, 2, option_reboot_on_failure},
+#endif
 };
 
 #ifdef CONFIG_SYSTEM_NXINIT_DEBUG
@@ -159,7 +167,7 @@ static int kill_service(FAR struct service_s *service, int 
signo)
       ret = -errno;
       if (ret == -ESRCH)
         {
-          init_service_reap(service);
+          init_service_reap(service, 0);
         }
     }
 
@@ -261,6 +269,17 @@ static int option_oneshot(FAR struct service_manager_s *sm,
   return 0;
 }
 
+#ifdef CONFIG_BOARDCTL_RESET
+static int option_reboot_on_failure(FAR struct service_manager_s *sm,
+                                    int argc, FAR char **argv)
+{
+  FAR struct service_s *s = list_last_entry(&sm->services, struct service_s,
+                                            node);
+  s->reset_reason = atoi(argv[1]);
+  return 0;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -371,8 +390,25 @@ init_service_find_by_pid(FAR struct service_manager_s *sm, 
const int pid)
   return NULL;
 }
 
-void init_service_reap(FAR struct service_s *service)
+void init_service_reap(FAR struct service_s *service, int status)
 {
+#ifdef CONFIG_BOARDCTL_RESET
+  int ret;
+
+  if (status && service->reset_reason >= 0)
+    {
+      init_err("Reboot on failure of service '%s' reason %d",
+               service->argv[1], service->reset_reason);
+      ret = boardctl(BOARDIOC_RESET, service->reset_reason);
+      if (ret < 0)
+        {
+          init_err("Reset failed %d", errno);
+        }
+    }
+#else
+  UNUSED(status);
+#endif
+
   remove_flags(service, SVC_RUNNING);
   if (check_flags(service, SVC_ONESHOT))
     {
@@ -404,6 +440,7 @@ int init_service_start(FAR struct service_s *service)
   if (ret != 0)
     {
       init_err("Starting service '%s': %d", service->argv[1], ret);
+      init_service_reap(service, ret);
       return -ret;
     }
 
@@ -536,6 +573,9 @@ int init_service_parse(FAR const struct parser_s *parser,
         }
 
       s->restart_period = CONFIG_SYSTEM_NXINIT_SERVICE_RESTART_PERIOD;
+#ifdef CONFIG_BOARDCTL_RESET
+      s->reset_reason = -1;
+#endif
       list_initialize(&s->classes);
       list_add_tail(&sm->services, &s->node);
     }
@@ -618,6 +658,9 @@ void init_dump_service(FAR struct service_s *s)
     }
 
   init_debug("  restart_period: %d", s->restart_period);
+#ifdef CONFIG_BOARDCTL_RESET
+  init_debug("  reboot_on_failure: %d", s->reset_reason);
+#endif
 
   if (s->flags)
     {
diff --git a/system/nxinit/service.h b/system/nxinit/service.h
index 303a44584..d76406e56 100644
--- a/system/nxinit/service.h
+++ b/system/nxinit/service.h
@@ -100,6 +100,12 @@ struct service_s
   struct timespec time_kill;
   int restart_period;
   pid_t pid;
+
+  /* The "target" of service option "reboot_on_failure" */
+
+#ifdef CONFIG_BOARDCTL_RESET
+  int reset_reason;
+#endif
 };
 
 struct service_manager_s
@@ -112,7 +118,7 @@ struct service_manager_s
  ****************************************************************************/
 
 int  init_service_refresh(FAR struct service_manager_s *sm);
-void init_service_reap(FAR struct service_s *service);
+void init_service_reap(FAR struct service_s *service, int status);
 int  init_service_start(FAR struct service_s *service);
 int  init_service_stop(FAR struct service_s *service);
 int  init_service_start_by_class(FAR struct service_manager_s *sm,

Reply via email to