fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

commit d3507d1843999cbff35d2d0b9aae61dca14dcff2
parent c83032aecece458b8cfa69107e0a19c0396dcca3
Author: Friedel Schön <derfriedmundschoen@gmail.com>
Date:   Mon,  8 May 2023 13:43:08 +0200

consistent prints

Diffstat:
Ainclude/message.h | 22++++++++++++++++++++++
Minclude/util.h | 8+++-----
Msrc/command.c | 4++--
Msrc/exec/finit.c | 16++++++++--------
Msrc/exec/fsvs.c | 41+++++++----------------------------------
Msrc/exec/sigremap.c | 129++++++++++++++++++++++++++++---------------------------------------------------
Msrc/exec/vlogger.c | 8++++----
Msrc/exec/zzz.c | 16++++++++--------
Asrc/message.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/restart.c | 24++++++++++++------------
Msrc/service.c | 2+-
Msrc/socket_handler.c | 7++++---
Msrc/stage.c | 31++++++++++++++-----------------
Msrc/start.c | 31++++++++++++++++---------------
Msrc/stop.c | 4++--
Msrc/supervise.c | 35+++++++++++++++++------------------
16 files changed, 217 insertions(+), 212 deletions(-)

diff --git a/include/message.h b/include/message.h @@ -0,0 +1,21 @@ +#pragma once + +#define FISS_VERSION "0.1.1" + +#define FISS_VERSION_STRING "fiss version v" FISS_VERSION "" + +typedef enum prog { + PROG_FINIT, + PROG_FSVC, + PROG_FSVS, + PROG_HALT, + PROG_POWEROFF, + PROG_REBOOT, + PROG_SEEDRNG, + PROG_SIGREMAP, + PROG_VLOGGER, + PROG_ZZZ +} prog_t; + +void print_usage_exit(prog_t prog, int status) __attribute__((noreturn)); +void print_version_exit() __attribute__((noreturn)); +\ No newline at end of file diff --git a/include/util.h b/include/util.h @@ -2,13 +2,11 @@ #include <stdio.h> -#define streq(a, b) (!strcmp((a), (b))) -#define stringify(s) #s +#define streq(a, b) (!strcmp((a), (b))) +#define stringify(s) #s #define static_stringify(s) stringify(s) -#define print_error(msg, ...) (fprintf(stderr, "error: " msg ": %s\n", ##__VA_ARGS__, strerror(errno))) -#define print_warning(msg, ...) (fprintf(stderr, "warning: " msg ": %s\n", ##__VA_ARGS__, strerror(errno))) - +#define print_error(msg, ...) (fprintf(stderr, msg, ##__VA_ARGS__, strerror(errno))) typedef struct { int read; diff --git a/src/command.c b/src/command.c @@ -23,7 +23,7 @@ int service_command(char command, char extra, const char* service, service_t* re int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd == -1) { - print_error("cannot connect to socket"); + print_error("error: cannot connect to socket: %s\n"); exit(1); } @@ -34,7 +34,7 @@ int service_command(char command, char extra, const char* service, service_t* re int ret = connect(sockfd, (struct sockaddr*) &addr, sizeof(addr)); if (ret == -1) { - print_error("cannot connect to %s", addr.sun_path); + print_error("error: cannot connect to %s: %s\n", addr.sun_path); exit(EXIT_FAILURE); } diff --git a/src/exec/finit.c b/src/exec/finit.c @@ -1,4 +1,5 @@ #include "config.h" +#include "message.h" #include "service.h" #include "util.h" @@ -16,16 +17,15 @@ void sigblock_all(bool unblock); int handle_initctl(int argc, const char** argv) { if (argc != 2 || argv[1][1] != '\0' || (argv[1][0] != '0' && argv[1][0] != '6')) { - printf("Usage: %s <0|6>\n", argv[0]); - return 1; + print_usage_exit(PROG_FINIT, 1); } if (getuid() != 0) { - printf("can only be run as root...\n"); + fprintf(stderr, "error: can only be run as root...\n"); return 1; } int sig = argv[1][0] == '0' ? SIGTERM : SIGINT; if (kill(1, sig) == -1) { - print_error("unable to kill init"); + print_error("error: unable to kill init: %s\n"); return 1; } return 0; @@ -39,12 +39,12 @@ static bool do_reboot; static void signal_interrupt(int signum) { daemon_running = false; - do_reboot = signum == SIGINT; + do_reboot = signum == SIGINT; } int main(int argc, const char** argv) { - int ttyfd; + int ttyfd; sigset_t ss; if (getpid() != 1) { @@ -69,11 +69,11 @@ int main(int argc, const char** argv) { handle_stage1(); - if (daemon_running) { // stage1 succeed + if (daemon_running) { // stage1 succeed sigblock_all(true); struct sigaction sigact = { 0 }; - sigact.sa_handler = signal_interrupt; + sigact.sa_handler = signal_interrupt; sigaction(SIGTERM, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); diff --git a/src/exec/fsvs.c b/src/exec/fsvs.c @@ -1,6 +1,7 @@ // daemon manager #include "config.h" +#include "message.h" #include "service.h" #include "util.h" @@ -14,30 +15,7 @@ #define SV_STOP_TIMEOUT_STR static_stringify(SV_STOP_TIMEOUT) -static const char HELP_MESSAGE[] = - "Usage:\n" - " %s [options] <runlevel>\n" - "\n" - "Options:\n" - " -h, --help ........ prints this and exits\n" - " -v, --verbose ..... print more info\n" - " -V, --version ..... prints current version and exits\n" - " -f, --force ....... forces socket\n" - "\n"; - -static const char VERSION_MESSAGE[] = - "FISS v" SV_VERSION "\n" - "\n" - "Features:\n" - " service directory: " SV_SERVICE_DIR "\n" - " service control socket: " SV_CONTROL_SOCKET "\n" - " max. services: " MAX_SERVICE_STR "\n" - " max. dependencies: " SV_DEPENDS_MAX_STR "\n" - " stop timeout: " SV_STOP_TIMEOUT_STR "sec\n" - "\n"; - static const struct option long_options[] = { - { "help", no_argument, 0, 'h' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "force", no_argument, 0, 'f' }, @@ -54,18 +32,13 @@ int main(int argc, char** argv) { bool force_socket = false; int c; - while ((c = getopt_long(argc, argv, ":hvVf", long_options, NULL)) > 0) { + while ((c = getopt_long(argc, argv, ":vVf", long_options, NULL)) > 0) { switch (c) { - case 'h': - printf(VERSION_MESSAGE, "<runlevel>"); - printf(HELP_MESSAGE, argv[0]); - return 0; case 'v': verbose = true; break; case 'V': - printf(VERSION_MESSAGE, "<runlevel>"); - return 0; + print_version_exit(); case 'f': force_socket = true; break; @@ -74,7 +47,7 @@ int main(int argc, char** argv) { fprintf(stderr, "error: invalid option -%c\n", optopt); else fprintf(stderr, "error: invalid option %s\n", argv[optind - 1]); - return 1; + print_usage_exit(PROG_FSVC, 1); } } @@ -82,13 +55,13 @@ int main(int argc, char** argv) { argc -= optind; if (argc == 0) { fprintf(stderr, "error: missing <service-dir>\n"); - return 1; + print_usage_exit(PROG_FSVC, 1); } else if (argc == 1) { fprintf(stderr, "error: missing <runlevel>\n"); - return 1; + print_usage_exit(PROG_FSVC, 1); } else if (argc > 2) { fprintf(stderr, "error: too many arguments\n"); - return 1; + print_usage_exit(PROG_FSVC, 1); } signal(SIGINT, signal_interrupt); diff --git a/src/exec/sigremap.c b/src/exec/sigremap.c @@ -1,24 +1,24 @@ /* Copyright (c) 2015 Yelp, Inc. - With modification 2023 Friedel Schon - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ + With modification 2023 Friedel Schon + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ /* * sigremap is a simple wrapper program designed to run as PID 1 and pass @@ -30,7 +30,9 @@ * To get debug output on stderr, run with '-v'. */ +#include "message.h" #include "signame.h" +#include "util.h" #include <assert.h> #include <errno.h> @@ -43,13 +45,10 @@ #include <sys/wait.h> #include <unistd.h> -#define PRINTERR(...) \ - fprintf(stderr, "[sigremap] " __VA_ARGS__) - -#define DEBUG(...) \ - do { \ - if (debug) \ - PRINTERR(__VA_ARGS__); \ +#define DEBUG(...) \ + do { \ + if (debug) \ + fprintf(stderr, __VA_ARGS__); \ } while (0) #define set_signal_undefined(old, new) \ @@ -68,8 +67,8 @@ int signal_remap[MAXSIG + 1] = { [0 ... MAXSIG] = -1 }; // One-time ignores due to TTY quirks. 0 = no skip, 1 = skip the next-received signal. bool signal_temporary_ignores[MAXSIG + 1] = { [0 ... MAXSIG] = false }; -pid_t child_pid = -1; -bool debug = false; +pid_t child_pid = -1; +bool debug = false; bool use_setsid = true; void forward_signal(int signum) { @@ -114,7 +113,7 @@ void handle_signal(int signum) { DEBUG("Ignoring tty hand-off signal %d.\n", signum); signal_temporary_ignores[signum] = 0; } else if (signum == SIGCHLD) { - int status, exit_status; + int status, exit_status; pid_t killed_pid; while ((killed_pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status)) { @@ -127,7 +126,7 @@ void handle_signal(int signum) { } if (killed_pid == child_pid) { - kill(use_setsid ? -child_pid : child_pid, SIGTERM); // send SIGTERM to any remaining children + kill(use_setsid ? -child_pid : child_pid, SIGTERM); // send SIGTERM to any remaining children DEBUG("Child exited with status %d. Goodbye.\n", exit_status); exit(exit_status); } @@ -148,54 +147,26 @@ void handle_signal(int signum) { } } -void print_help(char* argv[]) { - fprintf(stderr, - "Usage: %s [option] [old-signal=new-signal] command [[arg] ...]\n" - "\n" - "sigremap is a simple process supervisor that forwards signals to children.\n" - "It is designed to run as PID1 in minimal container environments.\n" - "\n" - "Optional arguments:\n" - " -s, --single Run in single-child mode.\n" - " In this mode, signals are only proxied to the\n" - " direct child and not any of its descendants.\n" - " -r, --remap s:r remap received signal s to new signal r before proxying.\n" - " To ignore (not proxy) a signal, remap it to 0.\n" - " This option can be specified multiple times.\n" - " -v, --verbose Print debugging information to stderr.\n" - " -h, --help Print this help message and exit.\n" - " -V, --version Print the current version and exit.\n" - "\n" - "Full help is available online at https://github.com/Yelp/dumb-init\n", - argv[0]); -} - - char** parse_command(int argc, char* argv[]) { - int opt; + int opt; struct option long_options[] = { - { "help", no_argument, NULL, 'h' }, { "single", no_argument, NULL, 's' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; - while ((opt = getopt_long(argc, argv, "+hvVs", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "+:hvVs", long_options, NULL)) != -1) { switch (opt) { - case 'h': - print_help(argv); - exit(0); case 'v': debug = true; break; case 'V': - // fprintf(stderr, "sigremap v%.*s", VERSION_len, VERSION); - exit(0); + print_version_exit(); case 'c': use_setsid = false; break; default: - exit(1); + print_usage_exit(PROG_SIGREMAP, 1); } } @@ -206,7 +177,7 @@ char** parse_command(int argc, char* argv[]) { if ((new = strchr(argv[0], '=')) == NULL) break; - old = argv[0]; + old = argv[0]; *new = '\0'; new ++; @@ -226,12 +197,7 @@ char** parse_command(int argc, char* argv[]) { } if (argc < 1) { - fprintf( - stderr, - "Usage: %s [option] program [args]\n" - "Try %s --help for full usage.\n", - argv[0], argv[0]); - exit(1); + print_usage_exit(PROG_SIGREMAP, 1); } if (use_setsid) { @@ -252,7 +218,7 @@ void dummy(int signum) { } int main(int argc, char* argv[]) { - char** cmd = parse_command(argc, argv); + char** cmd = parse_command(argc, argv); sigset_t all_signals; sigfillset(&all_signals); sigprocmask(SIG_BLOCK, &all_signals, NULL); @@ -271,9 +237,9 @@ int main(int argc, char* argv[]) { if (use_setsid) { if (ioctl(STDIN_FILENO, TIOCNOTTY) == -1) { DEBUG( - "Unable to detach from controlling tty (errno=%d %s).\n", - errno, - strerror(errno)); + "Unable to detach from controlling tty (errno=%d %s).\n", + errno, + strerror(errno)); } else { /* * When the session leader detaches from its controlling tty via @@ -294,32 +260,29 @@ int main(int argc, char* argv[]) { child_pid = fork(); if (child_pid < 0) { - PRINTERR("Unable to fork. Exiting.\n"); + print_error("error: unable to fork: %s\n"); return 1; } else if (child_pid == 0) { /* child */ sigprocmask(SIG_UNBLOCK, &all_signals, NULL); if (use_setsid) { if (setsid() == -1) { - PRINTERR( - "Unable to setsid (errno=%d %s). Exiting.\n", - errno, - strerror(errno)); + print_error("error: unable to setsid: %s\n"); exit(1); } if (ioctl(STDIN_FILENO, TIOCSCTTY, 0) == -1) { DEBUG( - "Unable to attach to controlling tty (errno=%d %s).\n", - errno, - strerror(errno)); + "Unable to attach to controlling tty (errno=%d %s).\n", + errno, + strerror(errno)); } DEBUG("setsid complete.\n"); } execvp(cmd[0], cmd); // if this point is reached, exec failed, so we should exit nonzero - PRINTERR("%s: %s\n", cmd[0], strerror(errno)); + print_error("error: unable to execute %s: %s\n", cmd[0]); _exit(2); } diff --git a/src/exec/vlogger.c b/src/exec/vlogger.c @@ -1,3 +1,4 @@ +#include "message.h" #include "util.h" #include <errno.h> @@ -110,7 +111,7 @@ int main(int argc, char* argv[]) { switch (c) { case 'f': if (freopen(optarg, "r", stdin) == NULL) { - fprintf(stderr, "vlogger: %s: %s\n", optarg, strerror(errno)); + print_error("error: unable to reopen %s: %s\n", optarg); return 1; } break; @@ -130,8 +131,7 @@ int main(int argc, char* argv[]) { tag = optarg; break; default: - fprintf(stderr, "usage: vlogger [-isS] [-f file] [-p pri] [-t tag] [message ...]\n"); - exit(1); + print_usage_exit(PROG_VLOGGER, 1); } argc -= optind; argv += optind; @@ -151,7 +151,7 @@ int main(int argc, char* argv[]) { sfacility = ident->name; } execl("/etc/vlogger", argv0, tag ?: "", slevel, sfacility, NULL); - fprintf(stderr, "vlogger: exec: %s\n", strerror(errno)); + print_error("error: unable to exec /etc/vlogger: %s\n"); exit(1); } diff --git a/src/exec/zzz.c b/src/exec/zzz.c @@ -67,11 +67,11 @@ int main(int argc, char** argv) { if (stat(SV_SUSPEND_EXEC, &st) == 0 && st.st_mode & S_IXUSR) { pid_t pid; if ((pid = fork()) == -1) { - fprintf(stderr, "failed to fork for " SV_SUSPEND_EXEC ": %s\n", strerror(errno)); + print_error("failed to fork for " SV_SUSPEND_EXEC ": %s\n"); return 1; } else if (pid == 0) { // child execl(SV_SUSPEND_EXEC, SV_SUSPEND_EXEC, NULL); - fprintf(stderr, "failed to execute " SV_SUSPEND_EXEC ": %s\n", strerror(errno)); + print_error("failed to execute " SV_SUSPEND_EXEC ": %s\n"); _exit(1); } @@ -80,22 +80,22 @@ int main(int argc, char** argv) { if (new_disk) { if ((sys_disk = open("/sys/power/disk", O_WRONLY | O_TRUNC)) == -1) { - fprintf(stderr, "cannot open /sys/power/disk: %s\n", strerror(errno)); + print_error("cannot open /sys/power/disk: %s\n"); return 1; } if (write(sys_disk, new_disk, strlen(new_disk)) == -1) - fprintf(stderr, "error writing to /sys/power/disk: %s\n", strerror(errno)); + print_error("error writing to /sys/power/disk: %s\n"); close(sys_disk); } if (new_state) { if ((sys_state = open("/sys/power/state", O_WRONLY | O_TRUNC)) == -1) { - fprintf(stderr, "cannot open /sys/power/state: %s\n", strerror(errno)); + print_error("cannot open /sys/power/state: %s\n"); return 1; } if (write(sys_state, new_state, strlen(new_state)) == -1) - fprintf(stderr, "error writing to /sys/power/state: %s\n", strerror(errno)); + print_error("error writing to /sys/power/state: %s\n"); close(sys_state); } else { @@ -105,11 +105,11 @@ int main(int argc, char** argv) { if (stat(SV_RESUME_EXEC, &st) == 0 && st.st_mode & S_IXUSR) { pid_t pid; if ((pid = fork()) == -1) { - fprintf(stderr, "failed to fork for " SV_RESUME_EXEC ": %s\n", strerror(errno)); + print_error("failed to fork for " SV_RESUME_EXEC ": %s\n"); return 1; } else if (pid == 0) { // child execl(SV_RESUME_EXEC, SV_RESUME_EXEC, NULL); - fprintf(stderr, "failed to execute " SV_RESUME_EXEC ": %s\n", strerror(errno)); + print_error("failed to execute " SV_RESUME_EXEC ": %s\n"); _exit(1); } diff --git a/src/message.c b/src/message.c @@ -0,0 +1,50 @@ +#include "message.h" + +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> + +static const char* prog_usage[] = { + [PROG_FINIT] = "init <0|6>", + [PROG_FSVC] = "fsvc <command> [-v --verbose] [-V --version] [-r --runlevel <level>] [-s --service-dir <path>]\n" + " fsvc start [-p --pin] <service>\n" + " fsvc stop [-p --pin] <service>\n" + " fsvc enable [-o --once] <service>\n" + " fsvc disable [-o --once] <service>\n" + " fsvc kill <service> <signal|signum>\n" + " fsvc status [-c --check] <service>\n" + " fsvc pause <service>\n" + " fsvc resume <service>\n" + " fsvc switch [-f --reset] <runlevel>", + [PROG_FSVS] = "fsvs [-V --version] [-v --verbose] [-f --force] <service-dir> <runlevel>", + [PROG_HALT] = "halt [-n] [-f] [-d] [-w] [-B]", + [PROG_POWEROFF] = "poweroff [-n] [-f] [-d] [-w] [-B]", + [PROG_REBOOT] = "reboot [-n] [-f] [-d] [-w] [-B]", + [PROG_SEEDRNG] = "seedrng", + [PROG_SIGREMAP] = "sigremap [-s --single] [-v --verbose] [-V --version] <old-signal=new-signal...> <command> [args...]", + [PROG_VLOGGER] = "vlogger [-isS] [-f file] [-p pri] [-t tag] [message ...]", + [PROG_ZZZ] = "zzz [-n --noop] [-S --freeze] [-z --suspend] [-Z --hibernate] [-R --reboot] [-H --hybrid]" +}; + +static const char* prog_manual[] = { + [PROG_FINIT] = "finit 8", + [PROG_FSVC] = "fsvc 8", + [PROG_FSVS] = "fsvs 8", + [PROG_HALT] = "halt 8", + [PROG_POWEROFF] = "poweroff 8", + [PROG_REBOOT] = "reboot 8", + [PROG_SEEDRNG] = "seedrng 8", + [PROG_SIGREMAP] = "sigremap 1", + [PROG_VLOGGER] = "vlogger 8", + [PROG_ZZZ] = "zzz 8" +}; + +void print_usage_exit(prog_t prog, int status) { + fprintf(status ? stderr : stdout, "Usage: %s\n\nCheck manual '%s' for more information.\n", prog_usage[prog], prog_manual[prog]); + exit(status); +} + +void print_version_exit() { + printf(FISS_VERSION_STRING); + exit(0); +} +\ No newline at end of file diff --git a/src/restart.c b/src/restart.c @@ -11,9 +11,9 @@ /*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 *) + 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) { @@ -23,19 +23,19 @@ static void do_finish(service_t* s) { if (stat_mode("%s/%s/finish", service_dir, s->name) & S_IEXEC) { s->state = STATE_FINISHING; if ((s->pid = fork()) == -1) { - print_error("cannot fork process"); + print_error("error: cannot fork process: %s\n"); } else if (s->pid == 0) { dup2(null_fd, STDIN_FILENO); dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); execl(path_buffer, path_buffer, NULL); - print_error("cannot execute finish process"); + print_error("error: cannot execute finish process: %s\n"); _exit(1); } } else if (s->fail_count == SV_FAIL_MAX) { s->state = STATE_DEAD; - printf(":: %s died\n", s->name); + printf("%s died\n", s->name); } else { s->state = STATE_INACTIVE; } @@ -44,7 +44,7 @@ static void do_finish(service_t* s) { void service_check_state(service_t* s, bool signaled, int return_code) { s->status_change = time(NULL); - s->pid = 0; + s->pid = 0; if (s->restart_file == S_ONCE) s->restart_file = S_DOWN; if (s->restart_manual == S_ONCE) @@ -60,7 +60,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { s->return_code = return_code; s->fail_count++; - printf(":: %s killed thought signal %d\n", s->name, s->return_code); + printf("%s killed thought signal %d\n", s->name, s->return_code); } else { s->last_exit = EXIT_NORMAL; s->return_code = return_code; @@ -69,7 +69,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { else s->fail_count = 0; - printf(":: %s exited with code %d\n", s->name, s->return_code); + printf("%s exited with code %d\n", s->name, s->return_code); } do_finish(s); @@ -85,7 +85,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { case STATE_FINISHING: if (s->fail_count == SV_FAIL_MAX) { s->state = STATE_DEAD; - printf(":: %s died\n", s->name); + printf("%s died\n", s->name); } else { s->state = STATE_INACTIVE; } @@ -95,7 +95,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { if (stat_mode("%s/%s/stop", service_dir, s->name) & S_IXUSR) { s->state = STATE_ACTIVE_BACKGROUND; } else if (stat_mode("%s/%s/stop", service_dir, s->name) & S_IRUSR) { - s->pid = parse_pid_file(s); + s->pid = parse_pid_file(s); s->state = STATE_ACTIVE_PID; } else { do_finish(s); @@ -105,7 +105,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { s->return_code = return_code; do_finish(s); - } else { // signaled + } else { // signaled s->last_exit = EXIT_SIGNALED; s->return_code = return_code; diff --git a/src/service.c b/src/service.c @@ -44,7 +44,7 @@ int service_refresh() { struct dirent* ep; dp = opendir(service_dir); if (dp == NULL) { - print_error("cannot open directory %s", service_dir); + print_error("error: cannot open directory %s: %s\n", service_dir); return -1; } diff --git a/src/socket_handler.c b/src/socket_handler.c @@ -10,11 +10,12 @@ void service_handle_socket(int client) { read(client, command, sizeof(command)); - printf("command: %c\n", command[0]); - ssize_t service_len = readstr(client, service_name); - printf("command: %c-%02x with service '%s'\n", command[0], command[1], service_name); + if (service_len) + printf("command issued by user: %c-%02x with service '%s'\n", command[0], command[1], service_name); + else + printf("command issued by user: %c-%02x without service\n", command[0], command[1]); int res = 0; int res_off = 0; diff --git a/src/stage.c b/src/stage.c @@ -26,7 +26,7 @@ void handle_stage1() { int pid, ttyfd, exitstat; sigset_t ss; while ((pid = fork()) == -1) { - print_error("unable to fork for stage1"); + print_error("error: unable to fork for stage1: %s\n"); sleep(5); } if (pid == 0) { @@ -34,7 +34,7 @@ void handle_stage1() { /* stage 1 gets full control of console */ if ((ttyfd = open("/dev/console", O_RDWR)) == -1) { - print_error("unable to open /dev/console"); + print_error("error: unable to open /dev/console: %s\n"); } else { ioctl(ttyfd, TIOCSCTTY, NULL); // make the controlling process dup2(ttyfd, 0); @@ -52,9 +52,8 @@ void handle_stage1() { sigact.sa_handler = SIG_IGN; sigaction(SIGCONT, &sigact, NULL); - printf("enter stage1\n"); execl(SV_START_EXEC, SV_START_EXEC, NULL); - print_error("unable to exec stage1"); + print_error("error: unable to exec stage1: %s\n"); _exit(1); } bool dont_wait = false; @@ -77,7 +76,7 @@ void handle_stage1() { } while (child > 0 && child != pid); if (child == -1) { - print_error("waitpid failed, pausing"); + print_error("warn: waitpid failed: %s"); sleep(5); } @@ -91,16 +90,14 @@ void handle_stage1() { if (child == pid) { if (!WIFEXITED(exitstat) || WEXITSTATUS(exitstat) != 0) { - printf("child failed\n"); if (WIFSIGNALED(exitstat)) { /* this is stage 1 */ - printf("leave stage 1\n"); - printf("skipping stage 2\n"); + fprintf(stderr, "stage 1 failed: skip stage 2\n"); daemon_running = false; break; } } - printf("leave stage1\n"); + printf("leave stage 1\n"); break; } if (child != 0) { @@ -115,7 +112,7 @@ void handle_stage1() { continue; } - printf("signals only work in stage 2\n"); + fprintf(stderr, "warn: signals only work in stage 2, ignoring...\n"); } } @@ -124,7 +121,7 @@ void handle_stage3() { int pid, ttyfd, exitstat; sigset_t ss; while ((pid = fork()) == -1) { - print_error("unable to fork for state3"); + print_error("warn: unable to fork for state3: %s"); sleep(5); } if (pid == 0) { @@ -145,7 +142,7 @@ void handle_stage3() { printf("enter stage3\n"); execl(SV_STOP_EXEC, SV_STOP_EXEC, NULL); - print_error("unable to exec stage3"); + print_error("error: unable to exec stage3: %s\n"); _exit(1); } bool dont_wait = false; @@ -168,7 +165,7 @@ void handle_stage3() { } while (child > 0 && child != pid); if (child == -1) { - print_error("waitpid failed, pausing"); + print_error("error: waitpid failed, pausing: %s\n"); sleep(5); } @@ -181,9 +178,9 @@ void handle_stage3() { } if (child == pid) { - if (!WIFEXITED(exitstat) || WEXITSTATUS(exitstat) != 0) { - printf("child failed\n"); - } + // if (!WIFEXITED(exitstat) || WEXITSTATUS(exitstat) != 0) { + // printf("child failed\n"); + // } printf("leave stage: stage3\n"); break; } @@ -197,6 +194,6 @@ void handle_stage3() { if (sig != SIGCONT && sig != SIGINT) { continue; } - printf("signals only work in stage 2\n"); + fprintf(stderr, "warn: signals only work in stage 2\n"); } } diff --git a/src/start.c b/src/start.c @@ -20,13 +20,13 @@ static void set_pipes(service_t* s) { close(s->log_pipe.read); dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); - } else if (s->log_service) { // aka has_log_service + } else if (s->log_service) { // aka has_log_service close(s->log_service->log_pipe.read); dup2(s->log_service->log_pipe.write, STDOUT_FILENO); dup2(s->log_service->log_pipe.write, STDERR_FILENO); close(s->log_service->log_pipe.write); dup2(null_fd, STDIN_FILENO); - } else if (stat_mode("log") & S_IWRITE) { // is not + } else if (stat_mode("log") & S_IWRITE) { // is not int log_fd; if ((log_fd = open("log", O_WRONLY | O_TRUNC)) == -1) log_fd = null_fd; @@ -54,11 +54,11 @@ static void set_pipes(service_t* s) { static void set_user() { char buffer[1024]; - int user_file; + int user_file; if ((user_file = open("user", O_RDONLY)) != -1) { ssize_t n; if ((n = read(user_file, buffer, sizeof(buffer))) == -1) { - printf("failed reading user\n"); + print_error("error: failed reading ./user: %s\n"); close(user_file); return; } @@ -67,7 +67,7 @@ static void set_user() { uid_t uid; gid_t gids[60]; if ((n = parse_ugid(buffer, &uid, gids)) <= 0) { - printf("error parsing user\n"); + fprintf(stderr, "warn: malformatted user file\n"); close(user_file); return; } @@ -88,22 +88,22 @@ void service_run(service_t* s) { } else if (stat_mode("%s/%s/depends", service_dir, s->name) & S_IREAD) { s->state = STATE_ACTIVE_DUMMY; } else { - printf("error in %s: `run`, `start` or `depends` not found\n", s->name); + fprintf(stderr, "warn: %s: `run`, `start` or `depends` not found\n", s->name); s->state = STATE_INACTIVE; } if (s->state != STATE_ACTIVE_DUMMY) { if ((s->pid = fork()) == -1) { - print_error("cannot fork process"); + print_error("error: cannot fork process: %s\n"); exit(1); - } else if (s->pid == 0) { // child + } else if (s->pid == 0) { // child if (setsid() == -1) - print_error("cannot setsid"); + 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) - print_error("chdir failed"); + print_error("error: chdir failed: %s\n"); set_pipes(s); @@ -111,6 +111,7 @@ void service_run(service_t* s) { char* argv[SV_ARGUMENTS_MAX]; for (int i = 0; i < SV_ARGUMENTS_MAX; i++) argv[i] = args[i]; + char envs[SV_ENV_MAX][SV_ENV_FILE_LINE_MAX]; char* envv[SV_ENV_MAX]; for (int i = 0; i < SV_ENV_MAX; i++) @@ -126,7 +127,7 @@ void service_run(service_t* s) { } else { execve("./run", argv, envv); } - print_error("cannot execute service"); + print_error("error: cannot execute service: %s\n"); _exit(1); } } @@ -140,7 +141,7 @@ void service_start(service_t* s, bool* changed) { if (changed) *changed = true; - printf(":: starting %s \n", s->name); + printf("starting %s\n", s->name); for (int i = 0; i < depends_size; i++) { if (depends[i].service == s) service_start(depends[i].depends, NULL); @@ -157,18 +158,18 @@ void service_start(service_t* s, bool* changed) { if (stat_mode("%s/%s/setup", service_dir, s->name) & S_IXUSR) { s->state = STATE_SETUP; if ((s->pid = fork()) == -1) { - print_error("cannot fork process"); + print_error("error: cannot fork process: %s\n"); } else if (s->pid == 0) { dup2(null_fd, STDIN_FILENO); dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); execl(path_buf, path_buf, NULL); - print_error("cannot execute finish process"); + print_error("error: cannot execute setup process: %s\n"); _exit(1); } } else { service_run(s); } - printf(":: started %s \n", s->name); + printf("started %s \n", s->name); } diff --git a/src/stop.c b/src/stop.c @@ -29,14 +29,14 @@ void service_stop(service_t* s, bool* changed) { s->state = STATE_STOPPING; if ((s->pid = fork()) == -1) { - print_error("cannot fork process"); + print_error("error: cannot fork process: %s\n"); } else if (s->pid == 0) { dup2(null_fd, STDIN_FILENO); dup2(null_fd, STDOUT_FILENO); dup2(null_fd, STDERR_FILENO); execl(path_buffer, path_buffer, NULL); - print_error("cannot execute stop process"); + print_error("error: cannot execute stop process: %s\n"); _exit(1); } if (changed) diff --git a/src/supervise.c b/src/supervise.c @@ -19,12 +19,12 @@ bool daemon_running = true; static void signal_child(int unused) { (void) unused; - int status; - pid_t died_pid; + int status; + pid_t died_pid; service_t* s = NULL; if ((died_pid = wait(&status)) == -1) { - print_error("cannot wait for process"); + print_error("error: cannot wait for process: %s\n"); return; } @@ -78,7 +78,7 @@ static void accept_socket() { if (errno == EWOULDBLOCK) { sleep(SV_ACCEPT_INTERVAL); } else { - print_error("cannot accept client from control-socket"); + print_error("error: cannot accept client from control-socket: %s\n"); } } else { service_handle_socket(client_fd); @@ -87,7 +87,7 @@ static void accept_socket() { int service_supervise(const char* service_dir_, const char* runlevel_, bool force_socket) { struct sigaction sigact = { 0 }; - sigact.sa_handler = signal_child; + sigact.sa_handler = signal_child; sigaction(SIGCHLD, &sigact, NULL); sigact.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigact, NULL); @@ -101,7 +101,7 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc snprintf(socket_path, PATH_MAX, SV_CONTROL_SOCKET, runlevel); if ((null_fd = open("/dev/null", O_RDWR)) == -1) { - print_error("cannot open /dev/null"); + print_error("error: cannot open /dev/null: %s\n"); null_fd = 1; } @@ -115,7 +115,7 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc struct stat socket_stat; if (force_socket) { if (unlink(socket_path) == -1 && errno != ENOENT) { - print_error("cannot unlink socket"); + print_error("error: cannot unlink socket: %s\n"); } } else if (stat(socket_path, &socket_stat) != -1 && S_ISREG(socket_stat.st_mode)) { printf("error: %s exist and is locking supervision,\nrun this program with '-f' flag if you are sure no other superviser is running.", socket_path); @@ -123,31 +123,30 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc } // create socket if ((control_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - print_error("cannot create socket"); + print_error("error: cannot create socket: %s\n"); return 1; } // bind socket to address struct sockaddr_un addr = { 0 }; - addr.sun_family = AF_UNIX; + addr.sun_family = AF_UNIX; strcpy(addr.sun_path, socket_path); if (bind(control_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) { - print_error("cannot bind %s to socket", socket_path); + print_error("error: cannot bind %s to socket: %s\n", socket_path); return 1; } // listen for connections if (listen(control_socket, 5) == -1) { - print_error("cannot listen to control socket"); + print_error("error: cannot listen to control socket: %s\n"); return 1; } int sockflags = fcntl(control_socket, F_GETFL, 0); if (sockflags == -1) { - print_warning("fcntl-getflags on control-socket failed"); - } else { - if (fcntl(control_socket, F_SETFL, sockflags | O_NONBLOCK) == -1) - print_warning("fcntl-setflags on control-socket failed"); + print_error("warn: fcntl-getflags on control-socket failed: %s\n"); + } else if (fcntl(control_socket, F_SETFL, sockflags | O_NONBLOCK) == -1) { + print_error("warn: fcntl-setflags on control-socket failed: %s\n"); } // accept connections and handle requests @@ -161,7 +160,7 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc close(control_socket); if (unlink(socket_path) == -1 && errno != ENOENT) { - print_error("cannot unlink socket"); + print_error("error: cannot unlink socket: %s\n"); } printf(":: terminating\n"); @@ -173,9 +172,9 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc } time_t start = time(NULL); - int running; + int running; do { - sleep(1); // sleep for one second + sleep(1); // sleep for one second running = 0; for (int i = 0; i < services_size; i++) { if (services[i].state != STATE_INACTIVE)