Files
finit/src/runparts.c
T
Joachim Wiberg 308f75b209 Silence false positive from Coverity Scan
51static int is_dir_empty(const char *path)
    52{
	 1. var_decl: Declaring variable namelist without initializer.
    53        struct dirent **namelist;
    54        int num;
    55

   CID 898746: (#1 of 1): Uninitialized pointer read (UNINIT)
   2. uninit_use_in_call: Using uninitialized value namelist when calling scandir.
    56        num = scandir(path, &namelist, NULL, NULL);
    57        if (num < 0)
    58                return 0;

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-12-15 22:37:07 +01:00

243 lines
4.7 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>
const char *active_msg = NULL;
int interactive = 1;
int debug;
static void print_desc(const char *prefix, const char *msg)
{
if (interactive)
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
else
fprintf(stderr, "%s %s ...\n", prefix, msg);
active_msg = msg;
}
static void print_result(int rc)
{
if (interactive) {
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);
} else
fprintf(stderr, "[%s] %s\n", rc ? "FAIL" : " OK ", active_msg ?: "");
}
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, int sysv)
{
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
struct dirent **d = NULL;
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 (sysv && name[0] != 'S' && name[0] != 'K') {
dbg("S-only flag set, skipping non-SysV script: %s", name);
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 [-bdhps?] DIRECTORY");
return rc;
}
int main(int argc, char *argv[])
{
int rc, c, progress = 0, sysv = 0;
char *dir;
while ((c = getopt(argc, argv, "bdh?ps")) != EOF) {
switch(c) {
case 'b': /* batch mode */
interactive = 0;
break;
case 'd':
debug = 1;
break;
case 'h':
case '?':
return usage(0);
case 'p':
progress = 1;
break;
case 's':
sysv = 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, sysv);
if (rc == -1)
err(1, "failed run-parts %s", dir);
return rc;
}
#endif /* __FINIT__ */