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 4cb00687327824f63f41c92f78290fde6d65e55b
Author: fangpeina <[email protected]>
AuthorDate: Tue Dec 2 17:06:17 2025 +0800

    system/nxinit: support compound command execution
    
    Example in init.rc:
      echo "start" && hello && echo "done"
      ls /missing || echo "not found"
      echo "A" && echo "B" || echo "fallback"
    
    Signed-off-by: fangpeina <[email protected]>
---
 system/nxinit/action.c | 115 ++++++++++++++++++++++++++++++++++++++++---------
 system/nxinit/action.h |  11 ++++-
 system/nxinit/init.c   |   2 +-
 3 files changed, 106 insertions(+), 22 deletions(-)

diff --git a/system/nxinit/action.c b/system/nxinit/action.c
index f1d1d2bfd..6b2d166b7 100644
--- a/system/nxinit/action.c
+++ b/system/nxinit/action.c
@@ -223,6 +223,83 @@ static int event_callback(FAR struct action_manager_s *am,
   return event->pending;
 }
 
+static FAR char *parse_operator(FAR char *pos,
+                                FAR enum action_cmd_op_e *op)
+{
+  bool in_quotes = false;
+
+  for (; *pos != '\0'; pos++)
+    {
+      if (*pos == '"')
+        {
+          in_quotes = !in_quotes;
+          continue;
+        }
+
+      if (in_quotes)
+        {
+          continue;
+        }
+
+      if (*pos == '&' && *(pos + 1) == '&')
+        {
+          *op = CMD_OP_AND;
+          *pos = '\0';
+          return pos + 2;
+        }
+
+      if (*pos == '|' && *(pos + 1) == '|')
+        {
+          *op = CMD_OP_OR;
+          *pos = '\0';
+          return pos + 2;
+        }
+    }
+
+  *op = CMD_OP_NONE;
+  return pos;
+}
+
+static int parse_command(FAR char *pos,
+                         FAR struct list_node *cmds)
+{
+  FAR enum action_cmd_op_e op = CMD_OP_NONE;
+  FAR enum action_cmd_op_e next_op;
+  FAR struct action_cmd_s *cmd;
+  FAR char *next_pos;
+
+  while (*pos)
+    {
+      next_pos = parse_operator(pos, &next_op);
+
+      cmd = calloc(1, sizeof(*cmd));
+      if (cmd == NULL)
+        {
+          return -errno;
+        }
+
+      cmd->argc = init_parse_arguments(pos, true,
+                                       nitems(cmd->argv) - 1,
+                                       cmd->argv);
+      if (cmd->argc < 1)
+        {
+          free(cmd);
+          init_err("invalid argument");
+          return -EINVAL;
+        }
+
+      cmd->op = op;
+      list_add_tail(cmds, &cmd->node);
+      init_debug("add command %p(%s) to list %p", cmd, cmd->argv[0], cmds);
+      init_dump_args(cmd->argc, cmd->argv);
+
+      op = next_op;
+      pos = next_pos;
+    }
+
+  return 0;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -315,6 +392,15 @@ int init_action_run_command(FAR struct action_manager_s 
*am)
                                         struct action_cmd_s, node);
     }
 
+  if ((am->running->op == CMD_OP_AND && ready->prev_ret != 0) ||
+      (am->running->op == CMD_OP_OR && ready->prev_ret == 0))
+    {
+      init_debug("Skipping command due to op (prev_ret %d)",
+                 ready->prev_ret);
+      init_action_reap_command(am, ready->prev_ret);
+      return 0;
+    }
+
 #if defined(CONFIG_SYSTEM_NXINIT_ACTION_WARN_SLOW) && \
     CONFIG_SYSTEM_NXINIT_ACTION_WARN_SLOW > 0
   clock_gettime(CLOCK_MONOTONIC, &am->time_run);
@@ -326,13 +412,13 @@ int init_action_run_command(FAR struct action_manager_s 
*am)
     }
   else
     {
-      init_action_reap_command(am);
+      init_action_reap_command(am, ret);
     }
 
   return 0;
 }
 
-void init_action_reap_command(FAR struct action_manager_s *am)
+void init_action_reap_command(FAR struct action_manager_s *am, int ret)
 {
   FAR struct action_s *ready = list_peek_head_type(&am->ready_actions,
                                                    struct action_s,
@@ -361,6 +447,7 @@ void init_action_reap_command(FAR struct action_manager_s 
*am)
 #endif
 
   am->pid_running = -1;
+  ready->prev_ret = ret;
   if (list_is_tail(&ready->cmds, &am->running->node))
     {
       am->running = NULL;
@@ -377,7 +464,6 @@ int init_action_parse(FAR const struct parser_s *parser,
 {
   FAR struct action_manager_s *am = parser->priv;
   FAR char *argv[2 * CONFIG_SYSTEM_NXINIT_ACTION_EVENTS_MAX];
-  FAR struct action_cmd_s *cmd;
   FAR struct action_s *a;
   int ret;
 
@@ -435,26 +521,15 @@ int init_action_parse(FAR const struct parser_s *parser,
     }
   else
     {
-      cmd = calloc(1, sizeof(*cmd));
-      if (cmd == NULL)
-        {
-          init_err("Alloc action command");
-          return -errno;
-        }
-
-      cmd->argc = init_parse_arguments(buf, true, nitems(cmd->argv) - 1,
-                                       cmd->argv);
-      if (cmd->argc < 1)
+      a = list_last_entry(&am->actions, struct action_s, node);
+      ret = parse_command(buf, &a->cmds);
+      if (ret < 0)
         {
-          free(cmd);
-          init_err("Invalid command argument");
-          return -EINVAL;
+          init_err("failed to parse command line: %s", buf);
+          return ret;
         }
 
-      a = list_last_entry(&am->actions, struct action_s, node);
-      list_add_tail(&a->cmds, &cmd->node);
-      init_debug("Add command %p(%s) to action %p", cmd, cmd->argv[0], a);
-      init_dump_args(cmd->argc, cmd->argv);
+      init_debug("add command line to action %p", a);
     }
 
   return 0;
diff --git a/system/nxinit/action.h b/system/nxinit/action.h
index a13637ed2..48f672951 100644
--- a/system/nxinit/action.h
+++ b/system/nxinit/action.h
@@ -37,11 +37,19 @@
  * Public Types
  ****************************************************************************/
 
+enum action_cmd_op_e
+{
+  CMD_OP_NONE,
+  CMD_OP_AND,
+  CMD_OP_OR,
+};
+
 struct action_cmd_s
 {
   struct list_node node;          /* Command list node */
   int argc;
   FAR char *argv[CONFIG_SYSTEM_NXINIT_ACTION_CMD_ARGS_MAX];
+  enum action_cmd_op_e op;
 };
 
 struct action_event_s
@@ -58,6 +66,7 @@ struct action_s
   struct list_node ready_node;    /* Ready list node */
   struct action_event_s events[CONFIG_SYSTEM_NXINIT_ACTION_EVENTS_MAX];
   struct list_node cmds;          /* Command header, struct action_cmd_s */
+  int prev_ret;
 };
 
 struct action_manager_s
@@ -102,7 +111,7 @@ typedef CODE int (*init_action_event_cb)(FAR struct 
action_manager_s *,
 int  init_action_add_event(FAR struct action_manager_s *am,
                            FAR const char *name);
 int  init_action_run_command(FAR struct action_manager_s *am);
-void init_action_reap_command(FAR struct action_manager_s *am);
+void init_action_reap_command(FAR struct action_manager_s *am, int ret);
 int  init_action_parse(FAR const struct parser_s *parser,
                        bool create, FAR char *buf);
 int  init_action_foreach_event(FAR struct action_manager_s *am,
diff --git a/system/nxinit/init.c b/system/nxinit/init.c
index 2c2bcb166..8f8be4e29 100644
--- a/system/nxinit/init.c
+++ b/system/nxinit/init.c
@@ -91,7 +91,7 @@ static void reap_process(FAR struct service_manager_s *sm,
       if (pid == am->pid_running)
         {
           name = am->running->argv[0];
-          init_action_reap_command(am);
+          init_action_reap_command(am, ret);
         }
 
       service = init_service_find_by_pid(sm, pid);

Reply via email to