* apps/system/init/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 <stdio.h>
#include <string.h>
#include <sys/boardctl.h>
#include <sys/param.h>
#include <sys/wait.h>
#include "action.h"
#include "builtin.h"
#include "init.h"
#include "import.h"
#include "property.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 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 ret;
int pid;
for (; ; )
{
pid = waitpid(-1, &wstatus, WNOHANG);
if (pid <= 0)
{
break;
}
else if (WIFEXITED(wstatus))
{
status = "status";
ret = WEXITSTATUS(wstatus);
}
else if (WIFSIGNALED(wstatus))
{
status = "signal";
ret = WTERMSIG(wstatus);
}
else
{
continue;
}
if (pid == am->pid_running)
{
name = am->running->argv[0];
init_action_reap_command(am, ret);
}
service = init_service_find_by_pid(sm, pid);
if (service)
{
name = service->argv[1];
init_service_reap(service, ret);
}
init_log(service ? LOG_WARNING : LOG_DEBUG,
"%s '%s' pid %d exited %s %d",
service ? "service" : "command", name, pid, status, ret);
}
}
#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] = "unkown",
[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] = "unkown",
};
static FAR const char * const resetflag[] =
{
[BOARDIOC_SOFTRESETCAUSE_USER_REBOOT] = "reboot",
[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",
[BOARDIOC_SOFTRESETCAUSE_POWEROFF] = "shutdown",
};
char buf[CONFIG_SYSTEM_INIT_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
****************************************************************************/
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),
.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_poller_s poller[] =
{
{
.init = init_property_init,
.handle = init_property_handler,
.deinit = init_property_deinit,
},
};
struct pollfd pfds[nitems(poller)];
size_t i;
int r;
#ifdef CONFIG_USBDEV_TRACE
usbtrace_enable(TRACE_BITSET);
#endif
for (i = 0; i < nitems(poller); i++)
{
poller[i].sm = &sm;
poller[i].am = &am;
poller[i].pfd = &pfds[i];
r = poller[i].init(&poller[i]);
if (r < 0)
{
init_err("init event %zu", i);
goto out;
}
}
r = init_parse_configs(parser);
if (r < 0)
{
goto out;
}
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 (; ; )
{
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(poller); i++)
{
if (poller[i].pfd->revents & poller[i].pfd->events)
{
poller[i].handle(&poller[i]);
}
}
reap_process(&sm, &am);
}
out:
while (i--)
{
if (poller[i].deinit)
{
poller[i].deinit(&poller[i]);
}
}
return r;
}