Refactor initial startup, run runparts and rc.local in background

The code refactored in this commit has long been an eyesore.  The
hand-over, from the sequential main() function, to the event loop
was clumsy at best and was very difficult to debug.

Instead of using a series of workers we now delegate everything to
the big state machine by introducing a new SM_BOOTSRTAP_WAIT_STATE.

Both the runparts and rc.local scripts now run in the background, no
longer blocking the event loop from responding to initctl calls.  To
ensure they run at the same point in time two things have been done:

 1. A new <int/bootstrap> condition has been added which triggers
    runparts, which now is a regular task created by conf_init()
 2. /etc/rc.local is started from SM_RUNLEVEL_WAIT_STATE when we
    transition from runlevel S to any other runlevel.

Fixes #356

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2023-07-30 10:09:34 +02:00
1 parent 28e101aaae
commit a58002588e
13 files changed
+372 -235

No files matched your search

+10 -88
View File
@@ -24,8 +24,6 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <err.h>
#include <stdarg.h>
#include <sysexits.h>
@@ -443,96 +441,20 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
return rc;
}
static void run_env(const char *env[])
pid_t run_bg(char *cmd, char *args[])
{
size_t i = 0;
pid_t pid;
if (!env)
return;
if (access(cmd, X_OK))
return 0;
while (env[i]) {
size_t j = i + 1;
print(-1, "Calling %s in the background", cmd);
pid = fork();
if (!pid)
_exit(exec_runtask(cmd, args));
print_result(pid == -1);
if (!env[j])
break;
setenv(env[i], env[j], 1);
i += 2;
}
}
int run_parts(char *dir, char *cmd, const char *env[], int progress)
{
struct dirent **e;
int i, num;
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
dbg("No files found in %s, skipping ...", dir);
return -1;
}
for (i = 0; i < num; i++) {
const char *name = e[i]->d_name;
char path[strlen(dir) + strlen(name) + 2];
struct stat st;
char *argv[4] = {
"sh",
"-c",
path,
NULL
};
pid_t pid = 0;
int status;
paste(path, sizeof(path), dir, name);
if (stat(path, &st)) {
dbg("Failed stat(%s): %s", path, strerror(errno));
continue;
}
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
if (strcmp(name, ".") && strcmp(name, ".."))
dbg("Skipping %s ...", path);
continue;
}
/* If the callee didn't supply a run_parts() argument */
if (!cmd) {
/* Check if S<NUM>service or K<NUM>service notation is used */
// dbg("Checking if %s is a sysvinit startstop script ...", name);
if (name[0] == 'S' && isdigit(name[1]))
strlcat(path, " start", sizeof(path));
else if (name[0] == 'K' && isdigit(name[1]))
strlcat(path, " stop", sizeof(path));
} else {
strlcat(path, cmd, sizeof(path));
}
if (progress)
print_desc("Calling ", path);
pid = fork();
if (!pid) {
sig_unblock();
run_env(env);
return execvp(_PATH_BSHELL, argv);
}
status = complete(path, pid);
if (WIFEXITED(status))
warnx("%s exited with status %d", path, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
warnx("%s terminated by signad %d", path, WTERMSIG(status));
if (progress)
print_result(WEXITSTATUS(status));
}
while (num--)
free(e[num]);
free(e);
return 0;
return pid;
}
/**