init: Handle SIGCHLD signals

This commit is contained in:
apio 2023-10-14 20:40:18 +02:00
parent 5f0830cd41
commit 81131ad3a8
Signed by: apio
GPG Key ID: B8A7D06E42258954

View File

@ -365,6 +365,40 @@ static void mount_devpts()
if (mount("/dev/pts", "devpts", "devpts") < 0) exit(255);
}
static void wait_for_child(int)
{
int status;
auto rc = os::Process::wait(os::Process::ANY_CHILD, &status);
if (rc.has_error())
{
do_log("[init] waitpid error %s", rc.error_string());
return;
}
pid_t child = rc.release_value();
for (auto& service : g_services)
{
if (service.pid.has_value() && service.pid.value() == child)
{
if (WIFEXITED(status))
{
do_log("[init] service %s exited with status %d\n", service.name.chars(), WEXITSTATUS(status));
}
else { do_log("[init] service %s was terminated by signal %d\n", service.name.chars(), WTERMSIG(status)); }
if (service.restart)
{
do_log("[init] restarting service %s\n", service.name.chars());
start_service(service);
}
break;
}
}
}
Result<int> sysinit(StringView path)
{
if (getpid() != 1)
@ -404,38 +438,7 @@ Result<int> sysinit(StringView path)
if (path.is_empty()) path = "/etc/init";
start_services(path);
while (1)
{
int status;
auto rc = os::Process::wait(os::Process::ANY_CHILD, &status);
if (rc.has_error()) continue;
pid_t child = rc.release_value();
for (auto& service : g_services)
{
if (service.pid.has_value() && service.pid.value() == child)
{
if (WIFEXITED(status))
{
do_log("[init] service %s exited with status %d\n", service.name.chars(), WEXITSTATUS(status));
}
else
{
do_log("[init] service %s was terminated by signal %d\n", service.name.chars(), WTERMSIG(status));
}
if (service.restart)
{
do_log("[init] restarting service %s\n", service.name.chars());
start_service(service);
}
break;
}
}
}
while (1) { wait_for_child(0); }
}
Result<int> user_init(StringView path)
@ -454,38 +457,7 @@ Result<int> user_init(StringView path)
TRY(os::Security::pledge("stdio rpath wpath proc exec", nullptr));
while (1)
{
int status;
auto rc = os::Process::wait(os::Process::ANY_CHILD, &status);
if (rc.has_error()) continue;
pid_t child = rc.release_value();
for (auto& service : g_services)
{
if (service.pid.has_value() && service.pid.value() == child)
{
if (WIFEXITED(status))
{
do_log("[init] service %s exited with status %d\n", service.name.chars(), WEXITSTATUS(status));
}
else
{
do_log("[init] service %s was terminated by signal %d\n", service.name.chars(), WTERMSIG(status));
}
if (service.restart)
{
do_log("[init] restarting service %s\n", service.name.chars());
start_service(service);
}
break;
}
}
}
while (1) { wait_for_child(0); }
}
Result<int> luna_main(int argc, char** argv)
@ -501,6 +473,8 @@ Result<int> luna_main(int argc, char** argv)
"change the default service path (/etc/init or /etc/user)");
parser.parse(argc, argv);
signal(SIGCHLD, wait_for_child);
if (user) return user_init(service_path);
return sysinit(service_path);
}