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 492a86691d5b25a2de8510c15db8eaf73fe550f2
Author: wangjianyu3 <[email protected]>
AuthorDate: Thu Aug 14 21:45:53 2025 +0800

    system/nxinit: Add NuttX Init
    
    This component (abbreviated as "NxInit") is specifically developed
    for NuttX and intended for system initialization. While we have
    adopted the Android Init Language among various syntax options,
    this is a brand-new implementation—it is not a port or variant of
    Android Init.
    
    Refer to the implementation of Android Init Language, consists of five broad
    classes of statements: Actions, Commands, Services, Options, and Imports.
    
    Actions support two types of triggers: event and action. Action triggers 
also
    support runtime triggering. Services support lifecycle management, including
    automatic restart (at specified intervals), and starting/stopping
    individually or by class. Import supports files or directories, and we may
    add a static method in the future. The following are some differences:
      1. The Android Init Language treats lines starting with `#` as comments,
         while we use a preprocessor to handle comments.
      2. For action commands, we can omit "exec" and directly execute
         built-in apps or nsh builtins.
      3. Regarding the property service, users can either adapt it by self or
         directly use the preset NVS-based properties.
      4. Only part of standard action commands and service options are
         implemented currlently.
    
    To enable system/nxinit:
      ```diff
      -CONFIG_INIT_ENTRYPOINT="nsh_main"
      +CONFIG_INIT_ENTRYPOINT="init_main"
      +CONFIG_SYSTEM_NXINIT=y
      ```
    
    For format and additional details, refer to:
      https://android.googlesource.com/platform/system/core/+/
      master/init/README.md
    
    Signed-off-by: wangjianyu3 <[email protected]>
---
 system/nxinit/CMakeLists.txt |  39 +++
 system/nxinit/Kconfig        | 118 ++++++++
 system/nxinit/Make.defs      |  25 ++
 system/nxinit/Makefile       |  39 +++
 system/nxinit/action.c       | 320 ++++++++++++++++++++++
 system/nxinit/action.h       |  85 ++++++
 system/nxinit/builtin.c      | 184 +++++++++++++
 system/nxinit/builtin.h      |  38 +++
 system/nxinit/import.c       |  60 +++++
 system/nxinit/import.h       |  38 +++
 system/nxinit/init.c         | 252 ++++++++++++++++++
 system/nxinit/init.h         |  91 +++++++
 system/nxinit/parser.c       | 288 ++++++++++++++++++++
 system/nxinit/parser.h       |  60 +++++
 system/nxinit/service.c      | 622 +++++++++++++++++++++++++++++++++++++++++++
 system/nxinit/service.h      | 138 ++++++++++
 16 files changed, 2397 insertions(+)

diff --git a/system/nxinit/CMakeLists.txt b/system/nxinit/CMakeLists.txt
new file mode 100644
index 000000000..5aef892e9
--- /dev/null
+++ b/system/nxinit/CMakeLists.txt
@@ -0,0 +1,39 @@
+# 
##############################################################################
+# apps/system/nxinit/CMakeLists.txt
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor
+# license agreements.  See the NOTICE file distributed with this work for
+# additional information regarding copyright ownership.  The ASF licenses this
+# file to you under the Apache License, Version 2.0 (the "License"); you may 
not
+# use this file except in compliance with the License.  You may obtain a copy 
of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# 
##############################################################################
+
+if(CONFIG_SYSTEM_NXINIT)
+
+  set(CSRCS init.c action.c builtin.c import.c parser.c service.c)
+
+  nuttx_add_application(
+    MODULE
+    ${CONFIG_SYSTEM_NXINIT}
+    NAME
+    ${CONFIG_SYSTEM_NXINIT_PROGNAME}
+    STACKSIZE
+    ${CONFIG_SYSTEM_NXINIT_STACKSIZE}
+    PRIORITY
+    ${CONFIG_SYSTEM_NXINIT_PRIORITY}
+    SRCS
+    ${CSRCS})
+
+endif()
diff --git a/system/nxinit/Kconfig b/system/nxinit/Kconfig
new file mode 100644
index 000000000..8b1bb6b22
--- /dev/null
+++ b/system/nxinit/Kconfig
@@ -0,0 +1,118 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config SYSTEM_NXINIT
+       tristate "NuttX Init"
+       default n
+       depends on LIBC_EXECFUNCS
+       depends on SCHED_CHILD_STATUS
+       ---help---
+               Enable NxInit(NuttX Init) component for system initialization.
+               The script of NxInit(init.rc) is compatible with the Android 
Init Language syntax.
+
+if SYSTEM_NXINIT
+
+#
+# Basic
+#
+
+config SYSTEM_NXINIT_PRIORITY
+       int "Thread priority"
+       default 100
+
+config SYSTEM_NXINIT_STACKSIZE
+       int "Stack size"
+       default DEFAULT_TASK_STACKSIZE
+
+config SYSTEM_NXINIT_PROGNAME
+       string "Program name"
+       default "init"
+
+#
+# RC
+#
+
+config SYSTEM_NXINIT_RC_LINE_MAX
+       int "Max line length of RC file"
+       default 128
+       ---help---
+               Maximum line length of RC file.
+               More details: 
https://android.googlesource.com/platform/system/core/+/master/init/README.md
+
+#
+# Action
+#
+
+config SYSTEM_NXINIT_ACTION_CMD_ARGS_MAX
+       int "Max number of command arguments"
+       default 8
+       ---help---
+               Maximum number of command arguments.
+               Form:
+               ```
+               on <trigger>
+                  <command>
+                  <command>
+                  <command>
+                  ...
+               ```
+
+config SYSTEM_NXINIT_ACTION_MANAGER_EVENT_MAX
+       int "Max number of action manager events"
+       default 32
+       ---help---
+               Maximum number of action manager events.
+               ```
+               struct action_manager_s
+               {
+                 ...
+                 FAR char 
*events[CONFIG_SYSTEM_NXINIT_ACTION_MANAGER_EVENT_MAX];
+                 ...
+               };
+               ```
+
+#
+# Service
+#
+
+config SYSTEM_NXINIT_SERVICE_ARGS_MAX
+       int "Max number of service arguments"
+       default 8
+       range 3 64
+       ---help---
+               Maximum number of service arguments,
+               including "name", "pathname" and key word "service"(at least 
3). Form:
+               ```
+               service <name> <pathname> [ <argument> ]*
+                  <option>
+                  <option>
+                  ...
+               ```
+
+config SYSTEM_NXINIT_SERVICE_RESTART_PERIOD
+       int "Service restart period in ms"
+       default 5000
+
+#
+# Log level
+#
+
+config SYSTEM_NXINIT_ERR
+       bool "Enable error log"
+       default !DEFAULT_SMALL
+
+config SYSTEM_NXINIT_WARN
+       bool "Enable warning log"
+       depends on SYSTEM_NXINIT_ERR
+
+config SYSTEM_NXINIT_INFO
+       bool "Enable info log"
+       depends on SYSTEM_NXINIT_WARN
+
+config SYSTEM_NXINIT_DEBUG
+       bool "Enable debug log"
+       depends on SYSTEM_NXINIT_INFO
+
+endif
diff --git a/system/nxinit/Make.defs b/system/nxinit/Make.defs
new file mode 100644
index 000000000..6efb435bc
--- /dev/null
+++ b/system/nxinit/Make.defs
@@ -0,0 +1,25 @@
+############################################################################
+# apps/system/nxinit/Make.defs
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_SYSTEM_NXINIT),)
+CONFIGURED_APPS += $(APPDIR)/system/nxinit
+endif
diff --git a/system/nxinit/Makefile b/system/nxinit/Makefile
new file mode 100644
index 000000000..e1f6ae894
--- /dev/null
+++ b/system/nxinit/Makefile
@@ -0,0 +1,39 @@
+############################################################################
+# apps/system/nxinit/Makefile
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# NuttX Init
+
+MAINSRC = init.c
+CSRCS += builtin.c
+CSRCS += parser.c
+CSRCS += action.c
+CSRCS += service.c
+CSRCS += import.c
+
+PROGNAME = $(CONFIG_SYSTEM_NXINIT_PROGNAME)
+PRIORITY = $(CONFIG_SYSTEM_NXINIT_PRIORITY)
+STACKSIZE = $(CONFIG_SYSTEM_NXINIT_STACKSIZE)
+MODULE = $(CONFIG_SYSTEM_NXINIT)
+
+include $(APPDIR)/Application.mk
diff --git a/system/nxinit/action.c b/system/nxinit/action.c
new file mode 100644
index 000000000..5a1140e10
--- /dev/null
+++ b/system/nxinit/action.c
@@ -0,0 +1,320 @@
+/****************************************************************************
+ * apps/system/nxinit/action.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "action.h"
+#include "builtin.h"
+#include "init.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Maximum number of parameters for the action trigger.
+ * Format: `on <trigger>`
+ */
+
+#define ACTION_ARGUMENTS_MAX 2
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+static void init_dump_action(FAR struct action_s *action);
+#else
+#  define init_dump_action(a)
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+static void init_dump_action(FAR struct action_s *action)
+{
+  FAR struct action_cmd_s *cmd;
+
+  init_debug("Action %p", action);
+  init_debug("  event trigger: '%s'", action->event ? action->event : "");
+  list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node)
+    {
+      init_dump_args(cmd->argc, cmd->argv);
+    }
+}
+#endif
+
+static void add_ready(FAR struct action_manager_s *am,
+                      FAR struct action_s *a)
+{
+  FAR struct action_s *ready;
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+  FAR struct action_cmd_s *cmd;
+
+  list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node)
+    {
+      init_debug("Add ready %p %s", cmd, cmd->argv[0]);
+    }
+#endif
+
+  list_for_every_entry(&am->ready_actions, ready, struct action_s,
+                       ready_node)
+    {
+      if (ready == a)
+        {
+          init_debug("Action %p(%s) already on the queue", a,
+                     a->event ? a->event : "");
+          init_dump_action(a);
+          return;
+        }
+    }
+
+  list_add_tail(&am->ready_actions, &a->ready_node);
+}
+
+static void update_ready(FAR struct action_manager_s *am)
+{
+  size_t i;
+
+  /* Actions with event trigger */
+
+  for (i = 0; i < nitems(am->events); i++)
+    {
+      if (!am->events[i])
+        {
+          continue;
+        }
+
+      am->current = list_prepare_entry(am->current, &am->actions,
+                                       struct action_s, node);
+      list_for_every_entry_continue(am->current, &am->actions,
+                                    struct action_s, node)
+        {
+          if (am->current->event && !strcmp(am->current->event,
+                                            am->events[i]))
+            {
+              add_ready(am, am->current);
+              return;
+            }
+        }
+
+      init_debug("Remove event [%zu] '%s'", i, am->events[i]);
+      am->current = NULL;
+      free(am->events[i]);
+      am->events[i] = NULL;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int init_action_add_event(FAR struct action_manager_s *am,
+                          FAR const char *event)
+{
+  int ret = -ENOBUFS;
+  size_t i;
+
+  for (i = 0; i < nitems(am->events); i++)
+    {
+      if (am->events[i])
+        {
+          continue;
+        }
+
+      am->events[i] = strdup(event);
+      if (am->events[i])
+        {
+          init_debug("Add event [%zu] '%s'", i, am->events[i]);
+          return 0;
+        }
+
+      ret = -errno;
+      break;
+    }
+
+  init_warn("Drop event '%s' %d", event, ret);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: init_action_run_command
+ *
+ * Description:
+ *   Execute the ready commands in the action.
+ *
+ * Input Parameters:
+ *   am - Instance of Action Manager
+ *
+ * Returned Value:
+ *   The expected next call interval (in milliseconds), where INT_MAX
+ *   indicates blocking.
+ ****************************************************************************/
+
+int init_action_run_command(FAR struct action_manager_s *am)
+{
+  FAR struct action_s *ready;
+  int ret;
+
+  if (am->pid_running != -1)
+    {
+      init_debug("Waiting '%s' pid %d", am->running->argv[0],
+                 am->pid_running);
+      return INT_MAX;
+    }
+
+  update_ready(am);
+  if (list_is_empty(&am->ready_actions))
+    {
+      return INT_MAX;
+    }
+
+  ready = list_peek_head_type(&am->ready_actions, struct action_s,
+                              ready_node);
+
+  if (!am->running)
+    {
+      am->running = list_peek_head_type(&ready->cmds,
+                                        struct action_cmd_s, node);
+    }
+
+  ret = init_builtin_run(am, am->running->argc, am->running->argv);
+  if (ret > 0)
+    {
+      am->pid_running = ret;
+    }
+  else
+    {
+      init_action_reap_command(am);
+    }
+
+  return 0;
+}
+
+void init_action_reap_command(FAR struct action_manager_s *am)
+{
+  FAR struct action_s *ready = list_peek_head_type(&am->ready_actions,
+                                                   struct action_s,
+                                                   ready_node);
+
+  am->pid_running = -1;
+  if (list_is_tail(&ready->cmds, &am->running->node))
+    {
+      am->running = NULL;
+      list_delete(&ready->ready_node);
+    }
+  else
+    {
+      am->running = list_next_entry(am->running, struct action_cmd_s, node);
+    }
+}
+
+int init_action_parse(FAR const struct parser_s *parser,
+                      bool create, FAR char *buf)
+{
+  FAR struct action_manager_s *am = parser->priv;
+  FAR char *argv[ACTION_ARGUMENTS_MAX];
+  FAR struct action_cmd_s *cmd;
+  FAR struct action_s *a;
+  int ret;
+
+  if (create)
+    {
+      ret = init_parse_arguments(buf, false, nitems(argv), argv);
+      if (ret < 2)
+        {
+          init_err("Invalid argument: %s", buf);
+          return -EINVAL;
+        }
+
+      a = calloc(1, sizeof(*a));
+      if (a == NULL)
+        {
+          init_err("Alloc action");
+          return -errno;
+        }
+
+      list_initialize(&a->cmds);
+
+      a->event = strdup(argv[--ret]);
+      if (a->event == NULL)
+        {
+          init_err("Event trigger");
+          free(a);
+          return -errno;
+        }
+
+      list_add_tail(&am->actions, &a->node);
+      init_debug("Add action %p(%s) to manager %p", a, argv[1], am);
+    }
+  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)
+        {
+          free(cmd);
+          init_err("Invalid command argument");
+          return -EINVAL;
+        }
+
+      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);
+    }
+
+  return 0;
+}
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+void init_dump_actions(FAR struct list_node *head)
+{
+  FAR struct action_s *action;
+
+  init_debug("== Dump Actions ==");
+  list_for_every_entry(head, action, struct action_s, node)
+    {
+      init_dump_action(action);
+    }
+}
+#endif
diff --git a/system/nxinit/action.h b/system/nxinit/action.h
new file mode 100644
index 000000000..3f1cd287a
--- /dev/null
+++ b/system/nxinit/action.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * apps/system/nxinit/action.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_ACTION_H
+#define __APPS_SYSTEM_NXINIT_ACTION_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/list.h>
+
+#include "parser.h"
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct action_cmd_s
+{
+  struct list_node node;          /* Command list node */
+  int argc;
+  FAR char *argv[CONFIG_SYSTEM_NXINIT_ACTION_CMD_ARGS_MAX];
+};
+
+struct action_s
+{
+  struct list_node node;          /* Action list node */
+  struct list_node ready_node;    /* Ready list node */
+
+  /* Event trigger */
+
+  FAR const char *event;
+
+  struct list_node cmds;          /* Command header, struct action_cmd_s */
+};
+
+struct action_manager_s
+{
+  struct list_node actions;       /* Action header, struct action_s */
+  struct list_node ready_actions; /* Ready header, struct action_s */
+
+  FAR char *events[CONFIG_SYSTEM_NXINIT_ACTION_MANAGER_EVENT_MAX];
+  FAR struct action_s *current;
+
+  FAR struct action_cmd_s *running;
+  int pid_running;
+  FAR struct service_manager_s *sm;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+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);
+int  init_action_parse(FAR const struct parser_s *parser,
+                       bool create, FAR char *buf);
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+void init_dump_actions(FAR struct list_node *head);
+#else
+#  define init_dump_actions(h)
+#endif
+#endif /* __APPS_SYSTEM_NXINIT_ACTION_H */
diff --git a/system/nxinit/builtin.c b/system/nxinit/builtin.c
new file mode 100644
index 000000000..34a514bf3
--- /dev/null
+++ b/system/nxinit/builtin.c
@@ -0,0 +1,184 @@
+/****************************************************************************
+ * apps/system/nxinit/builtin.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <spawn.h>
+#include <sys/param.h>
+
+#include "builtin.h"
+#include "init.h"
+#include "service.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct cmd_map_s
+{
+  FAR const char *cmd;
+  uint8_t minargs;
+  uint8_t maxargs;
+  CODE int (*func)(FAR struct action_manager_s *, int, FAR char **);
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int cmd_trigger(FAR struct action_manager_s *am,
+                       int argc, FAR char **argv);
+static int cmd_start(FAR struct action_manager_s *am,
+                     int argc, FAR char **argv);
+static int cmd_stop(FAR struct action_manager_s *am,
+                    int argc, FAR char **argv);
+static int cmd_exec(FAR struct action_manager_s *am,
+                    int argc, FAR char **argv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct cmd_map_s g_builtin[] =
+{
+  {"exec", 3, 99, cmd_exec},
+  {"start", 2, 2, cmd_start},
+  {"stop", 2, 2, cmd_stop},
+  {"trigger", 2, 2, cmd_trigger},
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int cmd_start(FAR struct action_manager_s *am,
+                     int argc, FAR char **argv)
+{
+  FAR struct service_s *service;
+
+  service = init_service_find_by_name(am->sm, argv[1]);
+  if (service == NULL)
+    {
+      init_err("No such service '%s'", argv[1]);
+      return -EINVAL;
+    }
+
+  return init_service_start(service);
+}
+
+static int cmd_stop(FAR struct action_manager_s *am,
+                    int argc, FAR char **argv)
+{
+  FAR struct service_s *service;
+
+  service = init_service_find_by_name(am->sm, argv[1]);
+  if (service == NULL)
+    {
+      init_err("No such service '%s'", argv[1]);
+      return -EINVAL;
+    }
+
+  return init_service_stop(service);
+}
+
+static int cmd_trigger(FAR struct action_manager_s *am,
+                       int argc, FAR char **argv)
+{
+  return init_action_add_event(am, argv[1]);
+}
+
+static int cmd_exec(FAR struct action_manager_s *am,
+                    int argc, FAR char **argv)
+{
+  int i;
+
+  for (i = 0; i < argc; i++)
+    {
+      if (!strcmp(argv[i], "--"))
+        {
+          i++;
+          return init_builtin_run(am, argc - i, &argv[i]);
+        }
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: init_builtin_run
+ *
+ * Description:
+ *   Execute the builtin command of NxInit, builtin App, or NSH builtin.
+ *
+ * Input Parameters:
+ *   am   - Instance of Action Manager.
+ *   argc - Argument count.
+ *   argv - A pointer to an array of string arguments. The end of the array
+ *          is indicated with a NULL entry.
+ *
+ * Returned Value:
+ *   Returns 0 (for NxInit builtin) or a PID (for builtin App or NSH builtin)
+ *   on success; Returns the negative value of errno on failure.
+ ****************************************************************************/
+
+int init_builtin_run(FAR struct action_manager_s *am,
+                     int argc, FAR char **argv)
+{
+  pid_t pid;
+  size_t i;
+  int ret;
+
+  for (i = 0; i < nitems(g_builtin); i++)
+    {
+      if (!strcmp(g_builtin[i].cmd, argv[0]))
+        {
+          if (argc < g_builtin[i].minargs || argc > g_builtin[i].maxargs)
+            {
+              init_err("Executing command '%s': invalid argument", argv[0]);
+              init_dump_args(argc, argv);
+              return -EINVAL;
+            }
+
+          init_info("Executing command '%s'", argv[0]);
+          return g_builtin[i].func(am, argc, argv);
+        }
+    }
+
+  ret = posix_spawnp(&pid, argv[0], NULL, NULL, argv, NULL);
+  if (ret != 0)
+    {
+      init_err("Executing command '%s': %d", argv[0], ret);
+      init_dump_args(argc, argv);
+      return -ret;
+    }
+
+  init_debug("Executed command '%s' pid %d", argv[0], pid);
+  return pid;
+}
diff --git a/system/nxinit/builtin.h b/system/nxinit/builtin.h
new file mode 100644
index 000000000..94cfef763
--- /dev/null
+++ b/system/nxinit/builtin.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+ * apps/system/nxinit/builtin.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_BUILTIN_H
+#define __APPS_SYSTEM_NXINIT_BUILTIN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "action.h"
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int init_builtin_run(FAR struct action_manager_s *am,
+                     int argc, FAR char **argv);
+#endif
diff --git a/system/nxinit/import.c b/system/nxinit/import.c
new file mode 100644
index 000000000..ca389d396
--- /dev/null
+++ b/system/nxinit/import.c
@@ -0,0 +1,60 @@
+/****************************************************************************
+ * apps/system/nxinit/import.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <errno.h>
+#include <sys/param.h>
+
+#include "import.h"
+#include "init.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int init_import_parse(FAR const struct parser_s *parser,
+                      bool create, FAR char *buf)
+{
+  FAR char *argv[2];
+  int ret;
+
+  if (create)
+    {
+      init_parse_arguments(buf, false, nitems(argv), argv);
+      ret = init_parse_config_file(parser, argv[1]);
+      if (ret < 0)
+        {
+          init_err("Import %s", argv[1]);
+          return ret;
+        }
+    }
+  else
+    {
+      init_err("Parse import");
+      return -EINVAL;
+    }
+
+  return 0;
+}
diff --git a/system/nxinit/import.h b/system/nxinit/import.h
new file mode 100644
index 000000000..05c1d6bdc
--- /dev/null
+++ b/system/nxinit/import.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+ * apps/system/nxinit/import.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_IMPORT_H
+#define __APPS_SYSTEM_NXINIT_IMPORT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "parser.h"
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int init_import_parse(FAR const struct parser_s *parser,
+                      bool create, FAR char *buf);
+#endif /* __APPS_SYSTEM_NXINIT_IMPORT_H */
diff --git a/system/nxinit/init.c b/system/nxinit/init.c
new file mode 100644
index 000000000..1f5396265
--- /dev/null
+++ b/system/nxinit/init.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+ * apps/system/nxinit/init.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <sys/param.h>
+#include <sys/boardctl.h>
+#include <sys/wait.h>
+
+#include <netutils/netinit.h>
+
+#include "action.h"
+#include "builtin.h"
+#include "init.h"
+#include "import.h"
+#include "service.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MS2TIMESPEC(ts, ms) \
+          ((ms) == INT_MAX ? NULL \
+                           : ((ts)->tv_sec = (ms) / 1000, \
+                              (ts)->tv_nsec = ((ms) % 1000) * 1000000, (ts)))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct init_event_s
+{
+  FAR struct pollfd *pfd;
+  FAR void *priv;
+  FAR struct service_manager_s *sm;
+  FAR struct action_manager_s *am;
+  CODE int  (*init)   (FAR struct init_event_s *);
+  CODE void (*handle) (FAR struct init_event_s *);
+  CODE void (*deinit) (FAR struct init_event_s *);
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void reap_process(FAR struct service_manager_s *sm,
+                         FAR struct action_manager_s *am)
+{
+  FAR const char *name = "unknown";
+  FAR const char *status;
+  FAR struct service_s *service;
+  int wstatus;
+  int pid;
+
+  for (; ; )
+    {
+      pid = waitpid(-1,
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+                    &wstatus,
+#else
+                    NULL,
+#endif
+                    WNOHANG);
+      if (pid <= 0)
+        {
+          break;
+        }
+      else if (WIFEXITED(wstatus))
+        {
+          status = "status";
+          wstatus = WEXITSTATUS(wstatus);
+        }
+      else if (WIFSIGNALED(wtatus))
+        {
+          status = "signal";
+          wstatus = WTERMSIG(wstatus);
+        }
+      else
+        {
+          continue;
+        }
+
+      service = init_service_find_by_pid(sm, pid);
+      if (service != NULL)
+        {
+          name = service->argv[1];
+          init_service_reap(service);
+        }
+      else if (pid == am->pid_running)
+        {
+          name = am->running->argv[0];
+          init_action_reap_command(am);
+        }
+
+      init_log(service ? LOG_WARNING : LOG_DEBUG,
+               "%s '%s' pid %d exited %s %d",
+               service ? "Service" : "Command", name, pid, status, wstatus);
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  struct service_manager_s sm =
+    {
+      .services = LIST_INITIAL_VALUE(sm.services),
+    };
+
+  struct action_manager_s am =
+    {
+      .actions = LIST_INITIAL_VALUE(am.actions),
+      .ready_actions = LIST_INITIAL_VALUE(am.ready_actions),
+      .events = { 0 },
+      .current = NULL,
+      .running = NULL,
+      .pid_running = -1,
+      .sm = &sm,
+    };
+
+  const struct parser_s parser[] =
+    {
+      {"import", init_import_parse, NULL, NULL},
+      {"on", init_action_parse, NULL, &am},
+      {"service", init_service_parse, init_service_check, &sm},
+      {NULL},
+    };
+
+  struct init_event_s ev[] =
+    {
+    };
+
+  struct pollfd pfds[nitems(ev)];
+  size_t i;
+  int r;
+
+#ifdef CONFIG_USBDEV_TRACE
+  usbtrace_enable(TRACE_BITSET);
+#endif
+
+  for (i = 0; i < nitems(ev); i++)
+    {
+      ev[i].sm = &sm;
+      ev[i].am = &am;
+      ev[i].pfd = &pfds[i];
+      r = ev[i].init(&ev[i]);
+      if (r < 0)
+        {
+          init_err("Init event %zu", i);
+          goto out;
+        }
+    }
+
+  r = init_parse_config_file(parser, "/etc/init.d/init.rc");
+  if (r < 0)
+    {
+      goto out;
+    }
+
+  init_dump_actions(&am.actions);
+  init_dump_services(&sm.services);
+
+  init_action_add_event(&am, "boot");
+
+  boardctl(BOARDIOC_INIT, 0);
+  init_action_add_event(&am, "init");
+
+#ifdef CONFIG_NETUTILS_NETINIT
+  netinit_bringup();
+  init_action_add_event(&am, "netinit");
+#endif
+
+#ifdef CONFIG_BOARDCTL_FINALINIT
+  boardctl(BOARDIOC_FINALINIT, 0);
+  init_action_add_event(&am, "finalinit");
+#endif
+
+  for (; ; )
+    {
+      int t1 = init_service_refresh(&sm);
+      int t2 = init_action_run_command(&am);
+      struct timespec timeout;
+      int t = MIN(t1, t2);
+
+      if (t1 < 0)
+        {
+          r = t1;
+          break;
+        }
+
+      if (t2 < 0)
+        {
+          r = t2;
+          break;
+        }
+
+      r = ppoll(pfds, nitems(pfds), MS2TIMESPEC(&timeout, t), NULL);
+      if (r < 0 && errno != EINTR)
+        {
+          init_err("Wait event");
+          break;
+        }
+
+      for (i = 0; i < nitems(ev); i++)
+        {
+          if (ev[i].pfd->revents & ev[i].pfd->events)
+            {
+              ev[i].handle(&ev[i]);
+            }
+        }
+
+      reap_process(&sm, &am);
+    }
+
+out:
+  while (i--)
+    {
+      if (ev[i].deinit)
+        {
+          ev[i].deinit(&ev[i]);
+        }
+    }
+
+  return r;
+}
diff --git a/system/nxinit/init.h b/system/nxinit/init.h
new file mode 100644
index 000000000..355357a7f
--- /dev/null
+++ b/system/nxinit/init.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * apps/system/nxinit/init.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_INIT_H
+#define __APPS_SYSTEM_NXINIT_INIT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <syslog.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+#define init_debug(...) syslog(LOG_DEBUG, ##__VA_ARGS__)
+#define init_dump_args(argc, argv) \
+          { \
+            int _i; \
+            for (_i = 0; _i < (argc); _i++) \
+              { \
+                init_debug("  argv[%d] '%s'", _i, (argv)[_i]); \
+              } \
+          }
+#else
+#define init_debug(...)
+#define init_dump_args(...)
+#endif
+
+#ifdef CONFIG_SYSTEM_NXINIT_INFO
+#define init_info(...) syslog(LOG_INFO, ##__VA_ARGS__)
+#else
+#define init_info(...)
+#endif
+
+#ifdef CONFIG_SYSTEM_NXINIT_WARN
+#define init_warn(...) syslog(LOG_WARNING, ##__VA_ARGS__)
+#else
+#define init_warn(...)
+#endif
+
+#ifdef CONFIG_SYSTEM_NXINIT_ERR
+#define init_err(f, ...) syslog(LOG_ERR, "Error " f, ##__VA_ARGS__)
+#else
+#define init_err(...)
+#endif
+
+#define init_log(p, ...) \
+        do \
+          { \
+            if ((p) <= LOG_ERR) \
+              { \
+                init_err(__VA_ARGS__); \
+              } \
+            else if ((p) <= LOG_WARNING) \
+              { \
+                init_warn(__VA_ARGS__); \
+              } \
+            else if ((p) <= LOG_INFO) \
+              { \
+                init_info(__VA_ARGS__); \
+              } \
+            else \
+              { \
+                init_debug(__VA_ARGS__); \
+              } \
+          } \
+        while (0)
+
+#endif /* __APPS_SYSTEM_NXINIT_INIT_H */
diff --git a/system/nxinit/parser.c b/system/nxinit/parser.c
new file mode 100644
index 000000000..3ffe4a5a6
--- /dev/null
+++ b/system/nxinit/parser.c
@@ -0,0 +1,288 @@
+/****************************************************************************
+ * apps/system/nxinit/parser.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "init.h"
+#include "parser.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv)
+{
+  bool quote = false;
+  bool new = true;
+  int i = 0;
+
+  while (*buf != '\0')
+    {
+      while (isblank(*buf))
+        {
+          if (!quote)
+            {
+              *buf = '\0';
+              new = true;
+            }
+
+          buf++;
+        }
+
+      if (*buf == '-' && *(buf + 1) == '-')
+        {
+          argv[i++] = buf;
+          if (i >= argc || *(buf += 2) == '\0')
+            {
+              break;
+            }
+
+          while (isblank(*buf))
+            {
+              *buf++ = '\0';
+            }
+
+          argv[i++] = buf;
+          break;
+        }
+
+      if (*buf == '\"')
+        {
+          *buf = '\0';
+          if (quote)
+            {
+              quote = false;
+            }
+          else
+            {
+              quote = true;
+              new = true;
+              buf++;
+            }
+        }
+
+      if (new)
+        {
+          argv[i++] = buf;
+          if (i >= argc)
+            {
+              break;
+            }
+
+          new = false;
+        }
+
+      buf++;
+    }
+
+  if (dup && i > 0)
+    {
+      argc = i;
+      for (i = 0; i < argc; i++)
+        {
+          argv[i] = strdup(argv[i]);
+          if (!argv[i])
+            {
+              while (i-- > 0)
+                {
+                  free(argv[i]);
+                }
+
+              return -errno;
+            }
+        }
+    }
+
+  return i;
+}
+
+int init_parse_config_file(FAR const struct parser_s *parser,
+                           FAR const char *file)
+{
+  char buf[CONFIG_SYSTEM_NXINIT_RC_LINE_MAX];
+  FAR const struct parser_s *cur = NULL;
+  bool create = false;
+  FAR char *nl;
+  size_t n = 0;
+  int ret = 0;
+  int fd;
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+  int line = 0;
+#endif
+
+  init_debug("Parsing %s", file);
+
+  fd = open(file, O_RDONLY | O_CLOEXEC);
+  if (fd < 0)
+    {
+      init_err("Opening %s %d", file, errno);
+      return -errno;
+    }
+
+  for (; ; )
+    {
+      ssize_t r = read(fd, &buf[n], sizeof(buf) - n);
+      if (r < 0)
+        {
+          if (errno == EINTR)
+            {
+              continue;
+            }
+
+          ret = -errno;
+          goto out;
+        }
+      else if (r == 0)
+        {
+          if (n == 0)
+            {
+              break;
+            }
+
+          buf[n++] = '\n';
+        }
+
+      n += r;
+      while ((nl = memchr(buf, '\n', n)))
+        {
+          *(nl++) = '\0';
+          n -= nl - buf;
+          init_debug("Line %3d: '%s'", ++line, buf);
+
+          for (ret = 0; parser[ret].key; ret++)
+            {
+              if (!strncmp(parser[ret].key, buf, strlen(parser[ret].key)))
+                {
+                  create = true;
+                  cur = &parser[ret];
+                  init_debug("New section (%s)", parser[ret].key);
+                  break;
+                }
+            }
+
+          if (cur == NULL)
+            {
+              ret = -EINVAL;
+              goto out;
+            }
+
+          ret = cur->parse(cur, create, buf);
+          create = false;
+          if (ret < 0)
+            {
+              goto out;
+            }
+
+          memmove(buf, nl, n);
+        }
+
+      if (n == sizeof(buf))
+        {
+          ret = -E2BIG;
+          goto out;
+        }
+    }
+
+  for (n = 0; parser[n].key; n++)
+    {
+      if (parser[n].check)
+        {
+          ret = parser[n].check(&parser[n]);
+          if (ret < 0)
+            {
+              break;
+            }
+        }
+    }
+
+out:
+  close(fd);
+  if (ret < 0)
+    {
+      init_err("Parse %s %d", file, ret);
+    }
+
+  return ret;
+}
+
+int init_parse_configs(FAR const struct parser_s *parser,
+                       FAR const char *path)
+{
+  FAR struct dirent *entry;
+  char file[PATH_MAX];
+  struct stat sb;
+  FAR DIR *dir;
+  int ret = 0;
+  size_t i;
+
+  if (stat(path, &sb) < 0)
+    {
+      init_err("Stat %s", path);
+      return -errno;
+    }
+
+  if (S_ISDIR(sb.st_mode))
+    {
+      dir = opendir(path);
+      if (dir == NULL)
+        {
+          init_err("Opening directory %s", path);
+          return -errno;
+        }
+
+      while ((entry = readdir(dir)) != NULL)
+        {
+          if (DIRENT_ISFILE(entry->d_type))
+            {
+              i = strlen(entry->d_name);
+              if (i >= 3 && !strcmp(entry->d_name + i - 3, ".rc"))
+                {
+                  snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
+                  ret = init_parse_config_file(parser, file);
+                  if (ret < 0)
+                    {
+                      break;
+                    }
+                }
+            }
+        }
+
+      closedir(dir);
+    }
+  else if (S_ISREG(sb.st_mode))
+    {
+      ret = init_parse_config_file(parser, path);
+    }
+
+  return ret;
+}
diff --git a/system/nxinit/parser.h b/system/nxinit/parser.h
new file mode 100644
index 000000000..37ab10b3f
--- /dev/null
+++ b/system/nxinit/parser.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+ * apps/system/nxinit/parser.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_PARSER_H
+#define __APPS_SYSTEM_NXINIT_PARSER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdbool.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct parser_s
+{
+  FAR const char *key;
+
+  CODE int (*parse)(FAR const struct parser_s *, bool, FAR char *);
+  CODE int (*check)(FAR const struct parser_s *);
+
+  /* Type
+   *  a. struct action_manager_s
+   *  b. struct service_manager_s
+   */
+
+  FAR void *priv;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv);
+int init_parse_configs(FAR const struct parser_s *parser,
+                       FAR const char *path);
+int init_parse_config_file(FAR const struct parser_s *parser,
+                           FAR const char *file);
+#endif
diff --git a/system/nxinit/service.c b/system/nxinit/service.c
new file mode 100644
index 000000000..f45d893ba
--- /dev/null
+++ b/system/nxinit/service.c
@@ -0,0 +1,622 @@
+/****************************************************************************
+ * apps/system/nxinit/service.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/clock.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <spawn.h>
+#include <sys/param.h>
+
+#include "init.h"
+#include "parser.h"
+#include "service.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SYSTEM_NXINIT_SERVICE_GENTLE_KILL_TIMEOUT 200
+#define TIMESPEC2MS(t) (((t).tv_sec * 1000) + (t).tv_nsec / 1000000)
+
+#define check_flags(s, f) ((s)->flags & (f))
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+#  define dump_flags(fmt, flags) \
+          do \
+            { \
+              size_t _i; \
+              for (_i = 0; _i < nitems(g_flag_str); _i++) \
+                { \
+                  if (g_flag_str[_i].flag & (flags)) \
+                    { \
+                      init_debug(fmt, g_flag_str[_i].str); \
+                    } \
+                } \
+            } \
+          while(0)
+#else
+#  define dump_flags(...)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct cmd_map_s
+{
+  FAR const char *cmd;
+  uint8_t minargs;
+  uint8_t maxargs;
+  int (*func)(FAR struct service_manager_s *, int, FAR char **);
+};
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+struct flag_str_s
+{
+  uint32_t flag;
+  FAR const char *str;
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int option_class(FAR struct service_manager_s *sm,
+                        int argc, FAR char **argv);
+static int option_gentle_kill(FAR struct service_manager_s *sm,
+                              int argc, FAR char **argv);
+static int option_restart_period(FAR struct service_manager_s *sm,
+                                 int argc, FAR char **argv);
+static int option_override(FAR struct service_manager_s *sm,
+                           int argc, FAR char **argv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct cmd_map_s g_option[] =
+{
+  {"class", 2, 99, option_class},
+  {"gentle_kill", 1, 1, option_gentle_kill},
+  {"restart_period", 2, 2, option_restart_period},
+  {"override", 1, 1, option_override},
+};
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+static const struct flag_str_s g_flag_str[] =
+{
+  {SVC_DISABLED, "disabled"},
+  {SVC_ONESHOT, "oneshot"},
+  {SVC_RUNNING, "running"},
+  {SVC_RESTARTING, "restarting"},
+  {SVC_GENTLE_KILL, "gentle_kill"},
+  {SVC_REMOVE, "remove"},
+  {SVC_SIGKILL, "sigkill"},
+  {SVC_OVERRIDE, "override"},
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void add_flags(FAR struct service_s *service, uint32_t flags)
+{
+  init_debug("Service '%s' flag 0x%" PRIx32 " add 0x%" PRIx32 "",
+             service->argv[1], service->flags, flags);
+  dump_flags("  +flag '%s'", flags);
+
+  service->flags |= flags;
+}
+
+static void remove_flags(FAR struct service_s *service, uint32_t flags)
+{
+  init_debug("Service '%s' flag 0x%" PRIx32 " add 0x%" PRIx32 "",
+             service->argv[1], service->flags, flags);
+  dump_flags("  -flag '%s'", flags);
+
+  service->flags &= ~flags;
+}
+
+static int kill_service(FAR struct service_s *service, int signo)
+{
+  int ret;
+
+  ret = kill(service->pid, signo);
+  if (ret < 0)
+    {
+      ret = -errno;
+      if (ret == -ESRCH)
+        {
+          init_service_reap(service);
+        }
+    }
+
+  init_log(ret < 0 ? LOG_ERR : LOG_WARNING,
+           "sent signal %d to service '%s' pid %d %d",
+           signo, service->argv[1], service->pid, ret);
+
+  return ret;
+}
+
+static void remove_service(FAR struct service_s *service)
+{
+  FAR struct service_class_s *class;
+  FAR struct service_class_s *tmp;
+  int i;
+
+  init_warn("Removing service '%s' ...", service->argv[1]);
+  list_for_every_entry_safe(&service->classes, class, tmp,
+                            struct service_class_s, node)
+    {
+      list_delete(&class->node);
+      free(class);
+    }
+
+  for (i = 0; i < service->argc; i++)
+    {
+      free(service->argv[i]);
+    }
+
+  list_delete(&service->node);
+  free(service);
+}
+
+static int option_class(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);
+  size_t len = strlen(argv[1]) + 1;
+  FAR struct service_class_s *c;
+
+  list_for_every_entry(&s->classes, c, struct service_class_s, node)
+    {
+      if (!strcmp(c->name, argv[1]))
+        {
+          return 0;
+        }
+    }
+
+  c = malloc(sizeof(*c) + len);
+  if (c == NULL)
+    {
+      init_err("Alloc class");
+      return -errno;
+    }
+
+  memcpy(c->name, argv[1], len);
+  list_add_tail(&s->classes, &c->node);
+  return 0;
+}
+
+static int option_gentle_kill(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);
+
+  add_flags(s, SVC_GENTLE_KILL);
+  return 0;
+}
+
+static int option_restart_period(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->restart_period = atoi(argv[1]);
+  return 0;
+}
+
+static int option_override(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);
+
+  add_flags(s, SVC_OVERRIDE);
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: init_service_refresh
+ *
+ * Description:
+ *   Check if any services need to be restarted, force terminate(SIGKILL), or
+ *   deleted.
+ *
+ * Input Parameters:
+ *   sm - Instance of Service Manager
+ *
+ * Returned Value:
+ *   The expected time interval until the next call is returned, INT_MAX for
+ *   block indefinitely;
+ ****************************************************************************/
+
+int init_service_refresh(FAR struct service_manager_s *sm)
+{
+  FAR struct service_s *service;
+  FAR struct service_s *tmp;
+  struct timespec diff;
+  struct timespec cur;
+  int min = INT_MAX;
+  int ms;
+
+  clock_gettime(CLOCK_MONOTONIC, &cur);
+  list_for_every_entry_safe(&sm->services, service, tmp, struct service_s,
+                            node)
+    {
+      if (check_flags(service, SVC_RESTARTING))
+        {
+          clock_timespec_subtract(&cur, &service->time_started, &diff);
+          ms = TIMESPEC2MS(diff);
+          if (ms >= service->restart_period)
+            {
+              init_service_start(service);
+              continue;
+            }
+
+          min = MIN(min, service->restart_period - ms);
+        }
+      else if (check_flags(service, SVC_RUNNING) &&
+               check_flags(service, SVC_GENTLE_KILL) &&
+               check_flags(service, SVC_DISABLED))
+        {
+          if (check_flags(service, SVC_SIGKILL))
+            {
+              continue;
+            }
+
+          clock_timespec_subtract(&cur, &service->time_kill, &diff);
+          ms = TIMESPEC2MS(diff);
+          if (ms >= SYSTEM_NXINIT_SERVICE_GENTLE_KILL_TIMEOUT)
+            {
+              init_warn("Service '%s' pid %d timeout for gentle kill",
+                        service->argv[1], service->pid);
+              kill_service(service, SIGKILL);
+              add_flags(service, SVC_SIGKILL);
+              continue;
+            }
+
+          min = MIN(min, SYSTEM_NXINIT_SERVICE_GENTLE_KILL_TIMEOUT - ms);
+        }
+      else if (check_flags(service, SVC_REMOVE) &&
+               check_flags(service, SVC_DISABLED) &&
+               !check_flags(service, SVC_RUNNING))
+        {
+          remove_service(service);
+        }
+    }
+
+  return min;
+}
+
+FAR struct service_s *
+init_service_find_by_name(FAR struct service_manager_s *sm,
+                          FAR const char *name)
+{
+  FAR struct service_s *service;
+
+  list_for_every_entry(&sm->services, service, struct service_s, node)
+    {
+      if (!strcmp(name, service->argv[1]))
+        {
+          return service;
+        }
+    }
+
+  return NULL;
+}
+
+FAR struct service_s *
+init_service_find_by_pid(FAR struct service_manager_s *sm, const int pid)
+{
+  FAR struct service_s *service;
+
+  list_for_every_entry(&sm->services, service, struct service_s, node)
+    {
+      if (pid == service->pid)
+        {
+          return service;
+        }
+    }
+
+  return NULL;
+}
+
+void init_service_reap(FAR struct service_s *service)
+{
+  remove_flags(service, SVC_RUNNING);
+  if (!check_flags(service, SVC_DISABLED))
+    {
+      add_flags(service, SVC_RESTARTING);
+    }
+}
+
+int init_service_start(FAR struct service_s *service)
+{
+  int ret;
+  int pid;
+
+  init_debug("Starting service '%s' ...", service->argv[1]);
+
+  if (check_flags(service, SVC_RUNNING))
+    {
+      init_info("Service '%s' already started pid %d", service->argv[1],
+                service->pid);
+      return service->pid;
+    }
+
+  ret = posix_spawnp(&pid, service->argv[2], NULL, NULL, &service->argv[2],
+                     environ);
+  if (ret != 0)
+    {
+      init_err("Starting service '%s': %d", service->argv[1], ret);
+      return -ret;
+    }
+
+  service->pid = pid;
+  clock_gettime(CLOCK_MONOTONIC, &service->time_started);
+  add_flags(service, SVC_RUNNING);
+  remove_flags(service, SVC_RESTARTING);
+  remove_flags(service, SVC_DISABLED);
+  init_info("Started service '%s' pid %d", service->argv[1], service->pid);
+
+  return 0;
+}
+
+int init_service_stop(FAR struct service_s *service)
+{
+  init_info("Stopping service '%s' ...", service->argv[1]);
+
+  if (check_flags(service, SVC_RUNNING | SVC_RESTARTING))
+    {
+      if (check_flags(service, SVC_DISABLED))
+        {
+          init_warn("Service '%s' is exiting", service->argv[1]);
+          return -EINPROGRESS;
+        }
+    }
+  else
+    {
+      init_warn("Service '%s' is not running", service->argv[1]);
+      return -ESRCH;
+    }
+
+  add_flags(service, SVC_DISABLED);
+  if (check_flags(service, SVC_RESTARTING))
+    {
+      remove_flags(service, SVC_RESTARTING);
+    }
+
+  if (check_flags(service, SVC_GENTLE_KILL))
+    {
+      init_debug("Gentle kill");
+      remove_flags(service, SVC_SIGKILL);
+      kill_service(service, SIGTERM);
+      clock_gettime(CLOCK_MONOTONIC, &service->time_kill);
+      return 0;
+    }
+
+  return kill_service(service, SIGKILL);
+}
+
+int init_service_start_by_class(FAR struct service_manager_s *sm,
+                                FAR const char *name)
+{
+  FAR struct service_class_s *class;
+  FAR struct service_s *service;
+  int ret;
+
+  list_for_every_entry(&sm->services, service, struct service_s, node)
+    {
+      list_for_every_entry(&service->classes, class, struct service_class_s,
+                           node)
+        {
+          if (!strcmp(name, class->name))
+            {
+              ret = init_service_start(service);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              break;
+            }
+        }
+    }
+
+  return 0;
+}
+
+int init_service_stop_by_class(FAR struct service_manager_s *sm,
+                               FAR const char *name)
+{
+  FAR struct service_class_s *class;
+  FAR struct service_s *service;
+  int ret;
+
+  list_for_every_entry(&sm->services, service, struct service_s, node)
+    {
+      list_for_every_entry(&service->classes, class, struct service_class_s,
+                           node)
+        {
+          if (!strcmp(name, class->name))
+            {
+              ret = init_service_stop(service);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              break;
+            }
+        }
+    }
+
+  return 0;
+}
+
+int init_service_parse(FAR const struct parser_s *parser,
+                       bool create, FAR char *buf)
+{
+  FAR char *argv[CONFIG_SYSTEM_NXINIT_SERVICE_ARGS_MAX];
+  FAR struct service_manager_s *sm = parser->priv;
+  FAR struct service_s *s;
+  int argc;
+  size_t i;
+
+  if (create)
+    {
+      s = calloc(1, sizeof(*s));
+      if (s == NULL)
+        {
+          init_err("Alloc service");
+          return -errno;
+        }
+
+      s->argc = init_parse_arguments(buf, true, nitems(s->argv), s->argv);
+      if (s->argc < 3)
+        {
+          init_err("Get arguments %d", s->argc);
+          free(s);
+          return -EINVAL;
+        }
+
+      s->restart_period = CONFIG_SYSTEM_NXINIT_SERVICE_RESTART_PERIOD;
+      list_initialize(&s->classes);
+      list_add_tail(&sm->services, &s->node);
+    }
+  else
+    {
+      argc = init_parse_arguments(buf, false, nitems(argv), argv);
+      for (i = 0; i < nitems(g_option); i++)
+        {
+          if (!strcmp(g_option[i].cmd, argv[0]))
+            {
+              init_info("Apply option[%zu] %p for %s", i, g_option[i].func,
+                        argv[0]);
+              if (argc < g_option[i].minargs || argc > g_option[i].maxargs)
+                {
+                  break;
+                }
+
+              init_dump_args(argc, argv);
+              return g_option[i].func(sm, argc, argv);
+            }
+        }
+
+      init_err("'%s': unknown option / invalid argument", argv[0]);
+      return -EINVAL;
+    }
+
+  return 0;
+}
+
+int init_service_check(FAR const struct parser_s *parser)
+{
+  FAR struct service_manager_s *sm = parser->priv;
+  FAR struct service_s *tmp;
+  FAR struct service_s *s;
+
+  list_for_every_entry(&sm->services, s, struct service_s, node)
+    {
+      tmp = list_next_entry(s, struct service_s, node);
+      list_for_every_entry_from(&sm->services, tmp, struct service_s, node)
+        {
+          if (!strcmp(s->argv[1], tmp->argv[1]))
+            {
+              if (!check_flags(tmp, SVC_OVERRIDE))
+                {
+                  init_err("Redefined service '%s'", tmp->argv[1]);
+                  init_dump_service(s);
+                  init_dump_service(tmp);
+                  return -EEXIST;
+                }
+
+              init_info("Remove duplicate definition of service '%s'",
+                        tmp->argv[1]);
+              add_flags(s, SVC_DISABLED | SVC_REMOVE);
+            }
+        }
+    }
+
+  return 0;
+}
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+void init_dump_service(FAR struct service_s *s)
+{
+  FAR struct service_class_s *c;
+  int i;
+
+  init_debug("Service %p name '%s' path '%s'", s, s->argv[1], s->argv[2]);
+
+  init_debug("  pid: %d", s->pid);
+  init_debug("  arguments:");
+  for (i = 0; s->argv[i] && i < nitems(s->argv); i++)
+    {
+      init_debug("      [%d] '%s'", i, s->argv[i]);
+    }
+
+  init_debug("  classes:");
+  list_for_every_entry(&s->classes, c, struct service_class_s, node)
+    {
+      init_debug("    '%s'", c->name);
+    }
+
+  init_debug("  restart_period: %d", s->restart_period);
+
+  if (s->flags)
+    {
+      init_debug("  flags:");
+      dump_flags("    '%s'", s->flags);
+    }
+}
+
+void init_dump_services(FAR struct list_node *head)
+{
+  FAR struct service_s *service;
+
+  init_debug("== Dump Services ==");
+  list_for_every_entry(head, service, struct service_s, node)
+    {
+      init_dump_service(service);
+    }
+}
+#endif
diff --git a/system/nxinit/service.h b/system/nxinit/service.h
new file mode 100644
index 000000000..303a44584
--- /dev/null
+++ b/system/nxinit/service.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+ * apps/system/nxinit/service.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXINIT_SERVICE_H
+#define __APPS_SYSTEM_NXINIT_SERVICE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/list.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Ref to Android Init
+ * URL: https://android.googlesource.com/platform/system/core/+/
+ *      android16-release/init/service.h#42
+ */
+#define SVC_DISABLED    (1 << 0)  /* do not autostart with class */
+#define SVC_ONESHOT     (1 << 1)  /* do not restart on exit */
+#define SVC_RUNNING     (1 << 2)  /* currently active */
+#define SVC_RESTARTING  (1 << 3)  /* waiting to restart */
+
+/* This service should be stopped with SIGTERM instead of SIGKILL.
+ * Will still be SIGKILLed after timeout period of 200 ms.
+ */
+
+#define SVC_GENTLE_KILL (1 << 13)
+
+/* Flags below are new added.
+ */
+
+/* Override the previous definition for a service with the same name */
+
+#define SVC_OVERRIDE    (1 << 29)
+
+/* Already sent SIGKILL, and should not send again. */
+
+#define SVC_SIGKILL     (1 << 30)
+
+/* Should be removed immediately after stopped */
+
+#define SVC_REMOVE      (1 << 31)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct service_class_s
+{
+  struct list_node node;     /* Service class list node */
+  FAR char name[0];
+};
+
+struct service_s
+{
+  struct list_node node;     /* Service list node */
+  struct list_node classes;  /* Class header, struct service_class_s */
+
+  uint32_t flags;
+
+  /* The explanation of the `argv` parameter.
+   *
+   * | Index   |   Value     |      Details      |
+   * |---------|-------------|-------------------|
+   * | argv[0] | "service"   | Statement keyword |
+   * | argv[1] | name        | Service name      |
+   * | argv[2] | argv[0]     | Service pathname  |
+   * | argv[n] | argv[n - 2] | Service arguments |
+   */
+
+  FAR char *argv[CONFIG_SYSTEM_NXINIT_SERVICE_ARGS_MAX];
+  int argc;
+
+  struct timespec time_started;
+  struct timespec time_kill;
+  int restart_period;
+  pid_t pid;
+};
+
+struct service_manager_s
+{
+  struct list_node services; /* Service header, struct service_s */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int  init_service_refresh(FAR struct service_manager_s *sm);
+void init_service_reap(FAR struct service_s *service);
+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,
+                                 FAR const char *name);
+int  init_service_stop_by_class(FAR struct service_manager_s *sm,
+                                FAR const char *name);
+FAR struct service_s *
+init_service_find_by_name(FAR struct service_manager_s *sm,
+                          FAR const char *name);
+FAR struct service_s *
+init_service_find_by_pid(FAR struct service_manager_s *sm, const int pid);
+int init_service_parse(FAR const struct parser_s *parser,
+                       bool create, FAR char *buf);
+int init_service_check(FAR const struct parser_s *parser);
+
+#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
+void init_dump_service(FAR struct service_s *s);
+void init_dump_services(FAR struct list_node *head);
+#else
+#  define init_dump_service(s)
+#  define init_dump_services(h)
+#endif
+#endif /* __APPS_SYSTEM_NXINIT_SERVICE_H */

Reply via email to