unix/fiss

instead of absolute paths use e.g. openat/fchdir (18905fe60a0155510de380024ba6c54b37a3c3df)
Repositories | LICENSE

commit 18905fe60a0155510de380024ba6c54b37a3c3df
parent 1a096e6ac2b36aae65d7dd0e6ac3cc9f5668479e
Author: Friedel Schön <[email protected]>
Date:   Wed, 10 May 2023 15:06:13 +0200

instead of absolute paths use e.g. openat/fchdir

Diffstat:
Minclude/service.h5+++--
Msrc/command_handler.c9++++-----
Msrc/config_parser.c9++++-----
Msrc/dependency.c7++-----
Msrc/exec/fsvc.c7+------
Msrc/register.c28+++++++++++++++++++---------
Msrc/restart.c22+++++++++-------------
Msrc/service.c18++++++++++--------
Msrc/start.c21++++++++++-----------
Msrc/stop.c7++-----
Msrc/supervise.c6+++++-
11 files changed, 69 insertions(+), 70 deletions(-)

diff --git a/include/service.h b/include/service.h @@ -56,6 +56,7 @@ typedef enum service_restart { } service_restart_t; typedef struct service { + int dir; // dirfd char name[SV_NAME_MAX]; // name of service service_state_t state; pid_t pid; // pid of run @@ -83,7 +84,7 @@ extern const char* command_string[]; extern service_t services[]; extern int services_size; extern char runlevel[]; -extern const char* service_dir; +extern int service_dir; extern int null_fd; extern int control_socket; extern bool daemon_running; @@ -99,7 +100,7 @@ int service_pattern(const char* name, service_t** dest, int dest_max); int service_refresh(); int service_supervise(const char* service_dir, const char* runlevel, bool force_socket); service_t* service_get(const char* name); -service_t* service_register(const char* name, bool is_log_service); +service_t* service_register(int dir, const char* name, bool is_log_service); void service_check_state(service_t* s, bool signaled, int return_code); void service_handle_socket(int client); void service_load(service_t* s, const uint8_t* buffer); // for fsvc diff --git a/src/command_handler.c b/src/command_handler.c @@ -139,13 +139,12 @@ int service_handle_command(void* argv, sv_command_t command, unsigned char extra if (argv == NULL) return -ENOSV; - if (extra == 1) // once - snprintf(path_buffer, PATH_MAX, "%s/%s/once-%s", service_dir, s->name, runlevel); - else - snprintf(path_buffer, PATH_MAX, "%s/%s/up-%s", service_dir, s->name, runlevel); + + strcpy(path_buffer, extra == 1 ? "once-" : "up-"); + strcat(path_buffer, runlevel); if (command == S_ENABLE) { - if ((fd = open(path_buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) + if ((fd = openat(s->dir, path_buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) return 0; close(fd); } else { diff --git a/src/config_parser.c b/src/config_parser.c @@ -4,6 +4,7 @@ #include <limits.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> @@ -13,10 +14,10 @@ void parse_param_file(service_t* s, char* args[]) { int line_size = 0; char c; - snprintf(args[args_size++], SV_PARAM_FILE_LINE_MAX, "%s/%s/%s", service_dir, s->name, "run"); + strcpy(args[args_size++], "./run"); bool start = true; - if ((param_file = open("params", O_RDONLY)) != -1) { + if ((param_file = openat(s->dir, "params", O_RDONLY)) != -1) { while (read(param_file, &c, 1) > 0) { if (start && c == '%') { args_size--; @@ -65,10 +66,8 @@ void parse_env_file(char** env) { pid_t parse_pid_file(service_t* s) { - char path_buf[PATH_MAX]; - snprintf(path_buf, PATH_MAX, "%s/%s/pid", service_dir, s->name); int pid_file; - if ((pid_file = open(path_buf, O_RDONLY)) == -1) + if ((pid_file = openat(s->dir, "pid", O_RDONLY)) == -1) return 0; char buffer[20]; diff --git a/src/dependency.c b/src/dependency.c @@ -24,11 +24,8 @@ void service_update_dependency(service_t* s) { service_add_dependency(s, s->log_service); } - int depends_file; - char depends_path[PATH_MAX]; - snprintf(depends_path, PATH_MAX, "%s/%s/%s", service_dir, s->name, "depends"); - - if ((depends_file = open(depends_path, O_RDONLY)) == -1) + int depends_file; + if ((depends_file = openat(s->dir, "depends", O_RDONLY)) == -1) return; char line[512]; diff --git a/src/exec/fsvc.c b/src/exec/fsvc.c @@ -139,7 +139,6 @@ static const struct option long_options[] = { { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "runlevel", no_argument, 0, 'r' }, - { "service-dir", no_argument, 0, 's' }, { "pin", no_argument, 0, 'p' }, { "once", no_argument, 0, 'o' }, { "check", no_argument, 0, 'c' }, @@ -150,7 +149,6 @@ static const struct option long_options[] = { int main(int argc, char** argv) { strcpy(runlevel, getenv(SV_RUNLEVEL_ENV) ?: SV_RUNLEVEL); - service_dir = SV_SERVICE_DIR; char* argexec = argv[0]; @@ -162,14 +160,11 @@ int main(int argc, char** argv) { short_ = false; int c; - while ((c = getopt_long(argc, argv, ":Vvqs:r:pocf", long_options, NULL)) > 0) { + while ((c = getopt_long(argc, argv, ":Vvqr:pocf", long_options, NULL)) > 0) { switch (c) { case 'r': strcpy(runlevel, optarg); break; - case 's': - service_dir = optarg; - break; case 'q': short_ = true; break; diff --git a/src/register.c b/src/register.c @@ -1,6 +1,8 @@ #include "service.h" #include "util.h" +#include <errno.h> +#include <fcntl.h> #include <limits.h> #include <stdio.h> #include <string.h> @@ -8,7 +10,7 @@ #include <unistd.h> -service_t* service_register(const char* name, bool is_log_service) { +service_t* service_register(int dir, const char* name, bool is_log_service) { service_t* s; if ((s = service_get(name)) == NULL) { @@ -26,28 +28,36 @@ service_t* service_register(const char* name, bool is_log_service) { s->log_pipe.write = 0; s->is_log_service = is_log_service; + if ((s->dir = openat(dir, name, O_DIRECTORY)) == -1) { + print_error("error: cannot open '%s': %s\n", name); + return NULL; + } + strcpy(s->name, name); } - char path_buffer[PATH_MAX]; - - snprintf(path_buffer, PATH_MAX, "%s/%s/%s", service_dir, s->name, "log"); + struct stat st; if (s->is_log_service) { if (s->log_pipe.read == 0 || s->log_pipe.write == 0) pipe((int*) &s->log_pipe); - } else if (!s->log_service && S_ISDIR(stat_mode("%s/%s/log", service_dir, s->name))) { - snprintf(path_buffer, PATH_MAX, "%s/%s", s->name, "log"); + } else if (!s->log_service && fstatat(s->dir, "log", &st, 0) != -1 && S_ISDIR(st.st_mode)) { if (!s->log_service) - s->log_service = service_register(path_buffer, true); + s->log_service = service_register(s->dir, "log", true); } bool autostart, autostart_once; - autostart = S_ISREG(stat_mode("%s/%s/up-%s", service_dir, s->name, runlevel)); - autostart_once = S_ISREG(stat_mode("%s/%s/once-%s", service_dir, s->name, runlevel)); + char up_path[512] = "up-"; + char once_path[512] = "once-"; + + strcat(up_path, runlevel); + strcat(once_path, runlevel); + + autostart = fstatat(s->dir, up_path, &st, 0) == -1 && S_ISREG(st.st_mode); + autostart_once = fstatat(s->dir, once_path, &st, 0) == -1 && S_ISREG(st.st_mode); s->restart_file = S_DOWN; diff --git a/src/restart.c b/src/restart.c @@ -10,17 +10,9 @@ #include <unistd.h> -/*void stat_mode(const char* path_format, ...) __attribute__((format(printf, 1, 0))) { - va_list va; - va_start(va, path_format); - vsnprintf(char *, unsigned long, const char *, struct __va_list_tag *) -}*/ - static void do_finish(service_t* s) { - char path_buffer[PATH_MAX]; - snprintf(path_buffer, PATH_MAX, "%s/%s/finish", service_dir, s->name); - - if (stat_mode("%s/%s/finish", service_dir, s->name) & S_IEXEC) { + struct stat st; + if (fstatat(s->dir, "finish", &st, 0) != -1 && st.st_mode & S_IEXEC) { s->state = STATE_FINISHING; if ((s->pid = fork()) == -1) { print_error("error: cannot fork process: %s\n"); @@ -29,7 +21,9 @@ static void do_finish(service_t* s) { dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); - execl(path_buffer, path_buffer, NULL); + fchdir(s->dir); + + execl("./finish", "./finish", NULL); print_error("error: cannot execute finish process: %s\n"); _exit(1); } @@ -50,6 +44,8 @@ void service_check_state(service_t* s, bool signaled, int return_code) { if (s->restart_manual == S_ONCE) s->restart_manual = S_DOWN; + struct stat st; + switch (s->state) { case STATE_SETUP: service_run(s); @@ -92,9 +88,9 @@ void service_check_state(service_t* s, bool signaled, int return_code) { break; case STATE_STARTING: if (!signaled && return_code == 0) { - if (stat_mode("%s/%s/stop", service_dir, s->name) & S_IXUSR) { + if (fstatat(s->dir, "stop", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_ACTIVE_BACKGROUND; - } else if (stat_mode("%s/%s/stop", service_dir, s->name) & S_IRUSR) { + } else if (fstatat(s->dir, "pid", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->pid = parse_pid_file(s); s->state = STATE_ACTIVE_PID; } else { diff --git a/src/service.c b/src/service.c @@ -9,12 +9,13 @@ #include <string.h> #include <sys/stat.h> #include <sys/wait.h> +#include <unistd.h> service_t services[SV_SERVICE_MAX]; int services_size = 0; char runlevel[SV_NAME_MAX]; -const char* service_dir; +int service_dir; int control_socket; int null_fd; bool verbose = false; @@ -42,18 +43,18 @@ int service_pattern(const char* name, service_t** dest, int dest_max) { int service_refresh() { DIR* dp; struct dirent* ep; - dp = opendir(service_dir); - if (dp == NULL) { - print_error("error: cannot open directory %s: %s\n", service_dir); + if ((dp = fdopendir(service_dir)) == NULL) { + print_error("error: cannot open service directory: %s\n"); return -1; } - + struct stat st; for (int i = 0; i < services_size; i++) { service_t* s = &services[i]; - if (!S_ISDIR(stat_mode("%s/%s", service_dir, s->name))) { + if (fstat(s->dir, &st) == -1 || !S_ISDIR(st.st_mode)) { if (s->pid) kill(s->pid, SIGKILL); + close(s->dir); if (i < services_size - 1) { memmove(services + i, services + i + 1, services_size - i - 1); i--; @@ -65,10 +66,11 @@ int service_refresh() { while ((ep = readdir(dp)) != NULL) { if (ep->d_name[0] == '.') continue; - if (!S_ISDIR(stat_mode("%s/%s", service_dir, ep->d_name))) + + if (fstatat(service_dir, ep->d_name, &st, 0) == -1 || !S_ISDIR(st.st_mode)) continue; - service_register(ep->d_name, false); + service_register(service_dir, ep->d_name, false); } closedir(dp); diff --git a/src/start.c b/src/start.c @@ -81,11 +81,12 @@ static void set_user() { } void service_run(service_t* s) { - if (stat_mode("%s/%s/run", service_dir, s->name) & S_IXUSR) { + struct stat st; + if (fstatat(s->dir, "run", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_ACTIVE_FOREGROUND; - } else if (stat_mode("%s/%s/start", service_dir, s->name) & S_IXUSR) { + } else if (fstatat(s->dir, "start", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_STARTING; - } else if (stat_mode("%s/%s/depends", service_dir, s->name) & S_IREAD) { + } else if (fstatat(s->dir, "depends", &st, 0) != -1 && st.st_mode & S_IREAD) { s->state = STATE_ACTIVE_DUMMY; } else { fprintf(stderr, "warn: %s: `run`, `start` or `depends` not found\n", s->name); @@ -100,9 +101,7 @@ void service_run(service_t* s) { if (setsid() == -1) print_error("error: cannot setsid: %s\n"); - char dir_path[PATH_MAX]; - snprintf(dir_path, PATH_MAX, "%s/%s", service_dir, s->name); - if (chdir(dir_path) == -1) + if (fchdir(s->dir) == -1) print_error("error: chdir failed: %s\n"); set_pipes(s); @@ -152,10 +151,8 @@ void service_start(service_t* s, bool* changed) { service_start(depends[i].depends, NULL); } - char path_buf[PATH_MAX]; - snprintf(path_buf, PATH_MAX, "%s/%s/setup", service_dir, s->name); - - if (stat_mode("%s/%s/setup", service_dir, s->name) & S_IXUSR) { + struct stat st; + if (fstatat(s->dir, "setup", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_SETUP; if ((s->pid = fork()) == -1) { print_error("error: cannot fork process: %s\n"); @@ -164,7 +161,9 @@ void service_start(service_t* s, bool* changed) { dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); - execl(path_buf, path_buf, NULL); + fchdir(s->dir); + + execl("./setup", "./setup", NULL); print_error("error: cannot execute setup process: %s\n"); _exit(1); } diff --git a/src/stop.c b/src/stop.c @@ -9,8 +9,6 @@ void service_stop(service_t* s, bool* changed) { - char path_buffer[PATH_MAX]; - switch (s->state) { case STATE_ACTIVE_DUMMY: service_check_state(s, false, 0); @@ -25,8 +23,6 @@ void service_stop(service_t* s, bool* changed) { *changed = true; break; case STATE_ACTIVE_BACKGROUND: - snprintf(path_buffer, PATH_MAX, "%s/%s/stop", service_dir, s->name); - s->state = STATE_STOPPING; if ((s->pid = fork()) == -1) { print_error("error: cannot fork process: %s\n"); @@ -35,7 +31,8 @@ void service_stop(service_t* s, bool* changed) { dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); - execl(path_buffer, path_buffer, NULL); + fchdir(s->dir); + execl("./stop", "./stop", NULL); print_error("error: cannot execute stop process: %s\n"); _exit(1); } diff --git a/src/supervise.c b/src/supervise.c @@ -1,4 +1,5 @@ #include "service.h" +#include "util.h" #include <errno.h> #include <fcntl.h> @@ -93,7 +94,10 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc sigaction(SIGPIPE, &sigact, NULL); strcpy(runlevel, runlevel_); - service_dir = service_dir_; + if ((service_dir = open(service_dir_, O_DIRECTORY)) == -1) { + print_error("error: cannot open directory %s: %s\n", service_dir_); + return 1; + } setenv("SERVICE_RUNLEVEL", runlevel, true);