diff --git a/system/nxinit/action.c b/system/nxinit/action.c index f1d1d2bfd35..6b2d166b73c 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 a13637ed227..48f672951f5 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 2c2bcb1663d..de6964b928a 100644 --- a/system/nxinit/init.c +++ b/system/nxinit/init.c @@ -27,7 +27,11 @@ #include #include +#include #include +#include +#include +#include #include #include @@ -91,7 +95,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); @@ -107,6 +111,77 @@ static void reap_process(FAR struct service_manager_s *sm, } } +#ifdef CONFIG_BOARDCTL_RESET_CAUSE +static int init_boot_reason(FAR struct action_manager_s *am) +{ + static FAR const char *const resetcause[] = + { + [BOARDIOC_RESETCAUSE_NONE] = "unknown", + [BOARDIOC_RESETCAUSE_SYS_CHIPPOR] = "cold", + [BOARDIOC_RESETCAUSE_SYS_RWDT] = "watchdog", + [BOARDIOC_RESETCAUSE_SYS_BOR] = "undervoltage", + [BOARDIOC_RESETCAUSE_CORE_DPSP] = "warm", + [BOARDIOC_RESETCAUSE_CORE_MWDT] = "watchdog", + [BOARDIOC_RESETCAUSE_CORE_RWDT] = "watchdog", + [BOARDIOC_RESETCAUSE_CPU_MWDT] = "watchdog", + [BOARDIOC_RESETCAUSE_CPU_RWDT] = "watchdog", + [BOARDIOC_RESETCAUSE_PIN] = "powerkey", + [BOARDIOC_RESETCAUSE_LOWPOWER] = "lowpower", + [BOARDIOC_RESETCAUSE_UNKOWN] = "unknown", + }; + + static FAR const char * const resetflag[] = + { + [BOARDIOC_SOFTRESETCAUSE_USER_REBOOT] = "reboot", + [BOARDIOC_SOFTRESETCAUSE_ASSERT] = "assert", + [BOARDIOC_SOFTRESETCAUSE_PANIC] = "kernel_panic", + [BOARDIOC_SOFTRESETCAUSE_ENTER_BOOTLOADER] = "bootloader", + [BOARDIOC_SOFTRESETCAUSE_ENTER_RECOVERY] = "recovery", + [BOARDIOC_SOFTRESETCAUSE_RESTORE_FACTORY] = "factory_reset", + [BOARDIOC_SOFTRESETCAUSE_RESTORE_FACTORY_INQUIRY] = + "factory_reset_inquiry", + [BOARDIOC_SOFTRESETCAUSE_THERMAL] = "thermal", + }; + + char buf[CONFIG_SYSTEM_NXINIT_RC_LINE_MAX]; + struct boardioc_reset_cause_s reset; + FAR const char *value; + int ret; + + memset(&reset, 0, sizeof(reset)); + ret = boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&reset); + if (ret < 0) + { + init_err("boardctl BOARDIOC_RESET_CAUSE failed: %d", ret); + return ret; + } + + if (reset.cause >= nitems(resetcause)) + { + reset.cause = nitems(resetcause) - 1; + } + + if (reset.flag >= nitems(resetflag)) + { + reset.flag = nitems(resetflag) - 1; + } + + if (resetcause[reset.cause]) + { + sprintf(buf, "%s,%" PRIu32 "", resetcause[reset.cause], reset.flag); + value = buf; + } + else + { + value = resetflag[reset.flag]; + } + + return init_property_set(am->prop, "sys.boot.reason", value); +} +#else +# define init_boot_reason(am) (0) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -185,6 +260,12 @@ int main(int argc, FAR char *argv[]) init_dump_actions(&am.actions); init_dump_services(&sm.services); + r = init_boot_reason(&am); + if (r < 0) + { + goto out; + } + init_action_add_event(&am, "boot"); for (; ; )