mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
For some specialized forms of runparts, e.g., start-stop scripts in SysV init replacements, there is a need to append an argument. Typically this is 'start' or 'stop'. This functionality has been broken for quite some time, meaning we should consider it being unused by current users of Finit. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
223 lines
4.2 KiB
C
223 lines
4.2 KiB
C
#include <ctype.h> /* isdigit() */
|
|
#include <dirent.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <paths.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
|
|
#ifdef _LIBITE_LITE
|
|
# include <libite/conio.h>
|
|
# include <libite/lite.h>
|
|
#else
|
|
# include <lite/conio.h>
|
|
# include <lite/lite.h>
|
|
#endif
|
|
|
|
#include "log.h"
|
|
#include "sig.h"
|
|
#include "util.h"
|
|
|
|
#ifdef __FINIT__
|
|
#include "helpers.h"
|
|
#else
|
|
#include <sys/prctl.h>
|
|
|
|
int debug;
|
|
|
|
static void print_desc(const char *prefix, const char *msg)
|
|
{
|
|
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
|
}
|
|
static void print_result(int rc)
|
|
{
|
|
if (rc)
|
|
fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
|
else
|
|
fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
|
}
|
|
|
|
void sig_unblock(void)
|
|
{
|
|
struct sigaction sa;
|
|
sigset_t nmask;
|
|
int i;
|
|
|
|
sigemptyset(&nmask);
|
|
sigaddset(&nmask, SIGHUP);
|
|
sigaddset(&nmask, SIGCHLD);
|
|
sigaddset(&nmask, SIGINT);
|
|
sigaddset(&nmask, SIGPWR);
|
|
sigaddset(&nmask, SIGSTOP);
|
|
sigaddset(&nmask, SIGTSTP);
|
|
sigaddset(&nmask, SIGCONT);
|
|
sigaddset(&nmask, SIGTERM);
|
|
sigaddset(&nmask, SIGUSR1);
|
|
sigaddset(&nmask, SIGUSR2);
|
|
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
|
|
|
/* Reset signal handlers that were set by the parent process */
|
|
for (i = 1; i < NSIG; i++)
|
|
DFLSIG(sa, i, 0);
|
|
}
|
|
#endif /* __FINIT__ */
|
|
|
|
static void run_env(const char *env[])
|
|
{
|
|
size_t i = 0;
|
|
|
|
if (!env)
|
|
return;
|
|
|
|
while (env[i]) {
|
|
size_t j = i + 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)
|
|
{
|
|
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
|
|
struct dirent **d;
|
|
int i, num;
|
|
int rc = 0;
|
|
|
|
num = scandir(dir, &d, NULL, alphasort);
|
|
if (num < 0) {
|
|
dbg("No files found in %s, skipping ...", dir);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < num; i++) {
|
|
char path[strlen(dir) + strlen(d[i]->d_name) + 3 + cmdlen];
|
|
const char *name = d[i]->d_name;
|
|
char *argv[4] = {
|
|
"sh",
|
|
"-c",
|
|
path,
|
|
NULL
|
|
};
|
|
struct stat st;
|
|
int result = 0;
|
|
pid_t pid = 0;
|
|
int status;
|
|
|
|
/* skip backup files */
|
|
if (name[strlen(name) - 1] == '~')
|
|
continue;
|
|
|
|
/* cannot rely on d_type, not supported on all filesystems */
|
|
paste(path, sizeof(path), dir, name);
|
|
if (stat(path, &st)) {
|
|
warn("failed stat(%s)", path);
|
|
continue;
|
|
}
|
|
|
|
/* skip non-executable files and directories */
|
|
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
|
dbg("skipping %s not an executable or is a directory", 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 */
|
|
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, " ", sizeof(path));
|
|
strlcat(path, cmd, sizeof(path));
|
|
}
|
|
|
|
if (progress)
|
|
print_desc("Calling", path);
|
|
|
|
pid = fork();
|
|
if (!pid) {
|
|
sig_unblock();
|
|
run_env(env);
|
|
|
|
_exit(execvp(_PATH_BSHELL, argv));
|
|
}
|
|
|
|
if (waitpid(pid, &status, 0) == -1) {
|
|
warnx("failed starting %s, error %d: %s", path, errno, strerror(errno));
|
|
result = 1;
|
|
} else {
|
|
if (WIFEXITED(status)) {
|
|
result = WEXITSTATUS(status);
|
|
dbg("%s exited with status %d", path, result);
|
|
} else if (WIFSIGNALED(status)) {
|
|
warnx("%s terminated by signal %d", path, WTERMSIG(status));
|
|
result = 1;
|
|
} else
|
|
result = 1;
|
|
}
|
|
|
|
if (progress)
|
|
print_result(result);
|
|
rc += result;
|
|
}
|
|
|
|
while (num--)
|
|
free(d[num]);
|
|
free(d);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifndef __FINIT__
|
|
static int usage(int rc)
|
|
{
|
|
warnx("usage: runparts [-dh?] DIRECTORY");
|
|
return rc;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rc, c, progress = 0;
|
|
char *dir;
|
|
|
|
while ((c = getopt(argc, argv, "dh?p")) != EOF) {
|
|
switch(c) {
|
|
case 'd':
|
|
debug = 1;
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
return usage(0);
|
|
case 'p':
|
|
progress = 1;
|
|
break;
|
|
default:
|
|
return usage(1);
|
|
}
|
|
}
|
|
|
|
if (optind >= argc)
|
|
return usage(1);
|
|
|
|
dir = argv[optind];
|
|
if (!fisdir(dir))
|
|
return usage(1);
|
|
|
|
prctl(PR_SET_CHILD_SUBREAPER, 1);
|
|
|
|
rc = run_parts(dir, NULL, NULL, progress);
|
|
if (rc == -1)
|
|
err(1, "failed run-parts %s", dir);
|
|
|
|
return rc;
|
|
}
|
|
#endif /* __FINIT__ */
|