unix/fiss

formatting C-like (defs on top) (b5261e475dfdc8521ef7dee6db8eaa477c56f6fa)
Repositories | LICENSE

commit b5261e475dfdc8521ef7dee6db8eaa477c56f6fa
parent 6d8e3c1c6a6955a68539f870357669ed0bb0d9c1
Author: Friedel Schön <[email protected]>
Date:   Thu, 25 May 2023 15:03:39 +0200

formatting C-like (defs on top)

Diffstat:
Minclude/config.h7+------
Minclude/util.h19++++++++-----------
Msrc/dependency.c4++--
Msrc/exec/chpst.c24+++++++++++-------------
Msrc/exec/finit.c11+++++++----
Msrc/exec/fsvc.c22++++------------------
Msrc/exec/halt.c15+++++----------
Msrc/exec/shutdown.sh6+-----
Msrc/exec/sigremap.c48+++++++++++++-----------------------------------
Msrc/exec/zzz.c11++++-------
Msrc/handle_command.c174-------------------------------------------------------------------------------
Msrc/handle_exit.c5+++--
Msrc/parse.c9+++++----
Msrc/register.c16++++++++--------
Dsrc/runit.c112-------------------------------------------------------------------------------
Msrc/service.c8++++++--
Msrc/signame.c4++--
Msrc/stage.c13++++++-------
Msrc/start.c51++++++++++++++++++++++++++++-----------------------
Asrc/status.c53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/supervise.c14++++++++------
Msrc/util.c22+++++++++++++++++++++-
Msrc/wtmp.c6+++---
23 files changed, 199 insertions(+), 455 deletions(-)

diff --git a/include/config.h b/include/config.h @@ -1,10 +1,5 @@ #pragma once -// environment variable where the current runlevel is stored -#ifndef SV_RUNLEVEL_DEFAULT_ENV -# define SV_RUNLEVEL_DEFAULT_ENV "SERVICE_RUNLEVEL" -#endif - // seconds to wait for a service before it gets killed #ifndef SV_STOP_TIMEOUT # define SV_STOP_TIMEOUT 5 @@ -12,7 +7,7 @@ // maximal characters a service-dir can have #ifndef SV_NAME_MAX -# define SV_NAME_MAX 512 +# define SV_NAME_MAX 128 #endif // maximal dependencies a service can have diff --git a/include/util.h b/include/util.h @@ -13,15 +13,12 @@ typedef struct { int write; } pipe_t; -ssize_t dgetline(int fd, char* line, size_t line_buffer); -ssize_t readstr(int fd, char* str); -ssize_t writestr(int fd, const char* str); - +ssize_t dgetline(int fd, char* line, size_t line_buffer); +ssize_t readstr(int fd, char* str); +ssize_t writestr(int fd, const char* str); unsigned int stat_mode(const char* format, ...); - -int fork_dup_cd_exec(int dir, const char* path, int fd0, int fd1, int fd2); - -int reclaim_console(void); -void sigblock_all(int unblock); - -long parse_long(const char* str, const char* name); +int fork_dup_cd_exec(int dir, const char* path, int fd0, int fd1, int fd2); +int reclaim_console(void); +void sigblock_all(int unblock); +long parse_long(const char* str, const char* name); +char* progname(char* path); diff --git a/src/dependency.c b/src/dependency.c @@ -20,16 +20,16 @@ void service_add_dependency(service_t* s, service_t* d) { void service_update_dependency(service_t* s) { service_t* dep; + int depends_file; + char line[SV_NAME_MAX]; if (s->log_service) { // aka keep first entry (the log service) if a log service is used service_add_dependency(s, s->log_service); } - int depends_file; if ((depends_file = openat(s->dir, "depends", O_RDONLY)) == -1) return; - char line[SV_NAME_MAX]; while (dgetline(depends_file, line, sizeof(line)) > 0) { if (streq(s->name, line)) { fprintf(stderr, "warning: %s depends on itself\n", s->name); diff --git a/src/exec/chpst.c b/src/exec/chpst.c @@ -27,19 +27,6 @@ int main(int argc, char** argv) { case 'b': arg0 = optarg; break; - case 'e': // ignored - fprintf(stderr, "`envdir` is ignored\n"); - break; - case 'd': - case 'o': - case 'p': - case 'f': - case 'c': - case 'r': - case 't': - case 'm': // ignored - fprintf(stderr, "limits are ignored\n"); - break; case '/': root = optarg; break; @@ -67,6 +54,17 @@ int main(int argc, char** argv) { case '2': closestd[opt - '0'] = true; break; + case 'e': + case 'd': + case 'o': + case 'p': + case 'f': + case 'c': + case 'r': + case 't': + case 'm': // ignored + fprintf(stderr, "warning: '-%c' are ignored\n", optopt); + break; case '?': fprintf(stderr, "usage\n"); return 1; diff --git a/src/exec/finit.c b/src/exec/finit.c @@ -14,6 +14,8 @@ int handle_initctl(int argc, const char** argv) { + int sig; + if (argc != 2 || argv[1][1] != '\0' || (argv[1][0] != '0' && argv[1][0] != '6')) { print_usage_exit(PROG_FINIT, 1); } @@ -21,7 +23,7 @@ int handle_initctl(int argc, const char** argv) { fprintf(stderr, "error: can only be run as root...\n"); return 1; } - int sig = argv[1][0] == '0' ? SIGTERM : SIGINT; + sig = argv[1][0] == '0' ? SIGTERM : SIGINT; if (kill(1, sig) == -1) { print_error("error: unable to kill init: %s\n"); return 1; @@ -40,6 +42,7 @@ static void signal_interrupt(int signum) { int main(int argc, const char** argv) { sigset_t ss; + pid_t pid; if (getpid() != 1) { return handle_initctl(argc, argv); @@ -61,10 +64,11 @@ int main(int argc, const char** argv) { // stage 2 if (daemon_running) { // stage1 succeed + struct sigaction sigact = { 0 }; + 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); @@ -79,7 +83,6 @@ int main(int argc, const char** argv) { /* fallthrough stage 3 */ printf("sending KILL signal to all processes...\n"); kill(-1, SIGKILL); - pid_t pid; if ((pid = fork()) <= 0) { if (do_reboot) { diff --git a/src/exec/fsvc.c b/src/exec/fsvc.c @@ -49,22 +49,9 @@ static const struct option long_options[] = { { 0 } }; -static char* progname(char* path) { - char* match; - for (;;) { - if ((match = strrchr(path, '/')) == NULL) - return path; - - if (match[1] != '\0') - return match + 1; - - *match = '\0'; - } - return path; -} - static int check_service(int dir) { int fd; + if ((fd = openat(dir, "supervise/ok", O_WRONLY | O_NONBLOCK)) == -1) return -1; close(fd); @@ -114,8 +101,9 @@ int status(int dir) { } int main(int argc, char** argv) { - int opt; - int timeout = SV_STATUS_WAIT; + int opt, dir, + timeout = SV_STATUS_WAIT; + time_t mod, start; const char* command = NULL; @@ -168,8 +156,6 @@ int main(int argc, char** argv) { command++; } - int dir; - time_t mod, start; for (int i = 0; i < argc; i++) { if ((dir = open(argv[i], O_DIRECTORY)) == -1) { fprintf(stderr, "warning: '%s' is not a valid directory\n", argv[0]); diff --git a/src/exec/halt.c b/src/exec/halt.c @@ -14,27 +14,22 @@ int main(int argc, char* argv[]) { do_wtmp = true, noop = false; int opt; - char* progname; int rebootnum; const char* initarg; - if ((progname = strrchr(argv[0], '/')) != NULL) { - progname++; // to hide '/' - } else { - progname = argv[0]; - } + char* prog = progname(argv[0]); - if (streq(progname, "halt")) { + if (streq(prog, "halt")) { rebootnum = RB_HALT_SYSTEM; initarg = "0"; - } else if (streq(progname, "poweroff")) { + } else if (streq(prog, "poweroff")) { rebootnum = RB_POWER_OFF; initarg = "0"; - } else if (streq(progname, "reboot")) { + } else if (streq(prog, "reboot")) { rebootnum = RB_AUTOBOOT; initarg = "6"; } else { - fprintf(stderr, "invalid mode: %s\n", progname); + fprintf(stderr, "invalid mode: %s\n", prog); return 1; } diff --git a/src/exec/shutdown.sh b/src/exec/shutdown.sh @@ -1,10 +1,6 @@ #!/bin/sh # shutdown - shutdown(8) lookalike for fiss -single() { - fsvc chlevel single -} - abort() { printf '%s\n' "$1" >&2 exit 1 @@ -14,7 +10,7 @@ usage() { abort "Usage: ${0##*/} [-fF] [-kchPr] time [warning message]" } -action=single +action=: while getopts akrhPHfFnct: opt; do case "$opt" in diff --git a/src/exec/sigremap.c b/src/exec/sigremap.c @@ -20,15 +20,6 @@ THE SOFTWARE. */ -/* - * sigremap is a simple wrapper program designed to run as PID 1 and pass - * signals to its children. - * - * Usage: - * ./sigremap python -c 'while True: pass' - * - * To get debug output on stderr, run with '-v'. - */ #include "message.h" #include "signame.h" @@ -63,28 +54,14 @@ // Indices are one-indexed (signal 1 is at index 1). Index zero is unused. // User-specified signal rewriting. -int signal_remap[MAXSIG + 1]; +static int signal_remap[MAXSIG + 1]; // One-time ignores due to TTY quirks. 0 = no skip, 1 = skip the next-received signal. -bool signal_temporary_ignores[MAXSIG + 1]; - -int child_pid = -1; -bool debug = false; -bool use_setsid = true; - -void forward_signal(int signum) { - if (signum >= 0 && signum <= MAXSIG && signal_remap[signum] != -1) { - DEBUG("Translating signal %d to %d.\n", signum, signal_remap[signum]); - signum = signal_remap[signum]; - } +static bool signal_temporary_ignores[MAXSIG + 1]; - if (signum == 0) { - DEBUG("Not forwarding signal %d to children (ignored).\n", signum); - return; - } +static int child_pid = -1; +static bool debug = false; +static bool use_setsid = true; - kill(use_setsid ? -child_pid : child_pid, signum); - DEBUG("Forwarded signal %d to children.\n", signum); -} /* * The sigremap signal handler. @@ -106,7 +83,7 @@ void forward_signal(int signum) { * https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html * */ -void handle_signal(int signum) { +static void handle_signal(int signum) { DEBUG("Received signal %d.\n", signum); if (signal_temporary_ignores[signum] == 1) { @@ -147,7 +124,7 @@ void handle_signal(int signum) { } } -char** parse_command(int argc, char* argv[]) { +static char** parse_command(int argc, char* argv[]) { int opt; struct option long_options[] = { { "single", no_argument, NULL, 's' }, @@ -155,6 +132,9 @@ char** parse_command(int argc, char* argv[]) { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; + char *old, *new; + int oldsig, newsig; + while ((opt = getopt_long(argc, argv, "+:hvVs", long_options, NULL)) != -1) { switch (opt) { case 'v': @@ -173,7 +153,6 @@ char** parse_command(int argc, char* argv[]) { argc -= optind, argv += optind; while (argc > 0) { - char *old, *new; if ((new = strchr(argv[0], '=')) == NULL) break; @@ -181,8 +160,6 @@ char** parse_command(int argc, char* argv[]) { *new = '\0'; new ++; - int oldsig, newsig; - if ((oldsig = signame(old)) == -1) { fprintf(stderr, "error: invalid old signal '%s'\n", old); exit(1); @@ -213,13 +190,15 @@ char** parse_command(int argc, char* argv[]) { // On the FreeBSD kernel, ignored signals cannot be waited on by `sigwait` (but // they can be on Linux). We must provide a dummy handler. // https://lists.freebsd.org/pipermail/freebsd-ports/2009-October/057340.html -void dummy(int signum) { +static void dummy(int signum) { (void) signum; } int main(int argc, char* argv[]) { char** cmd = parse_command(argc, argv); sigset_t all_signals; + int signum; + sigfillset(&all_signals); sigprocmask(SIG_BLOCK, &all_signals, NULL); @@ -292,7 +271,6 @@ int main(int argc, char* argv[]) { /* parent */ DEBUG("Child spawned with PID %d.\n", child_pid); for (;;) { - int signum; sigwait(&all_signals, &signum); handle_signal(signum); } diff --git a/src/exec/zzz.c b/src/exec/zzz.c @@ -4,8 +4,6 @@ #include <errno.h> #include <fcntl.h> #include <getopt.h> -#include <stdbool.h> -#include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/wait.h> @@ -21,6 +19,7 @@ static int open_write(const char* path, const char* string) { } if (write(fd, string, strlen(string)) == -1) { print_error("error writing to %s: %s\n", path); + close(fd); return -1; } return close(fd); @@ -28,8 +27,9 @@ static int open_write(const char* path, const char* string) { int main(int argc, char** argv) { - int opt; - + int opt; + pid_t pid; + struct stat st; const char *new_state = "mem", *new_disk = NULL; @@ -81,10 +81,8 @@ int main(int argc, char** argv) { argc -= optind, argv += optind; - struct stat st; if (stat(SV_SUSPEND_EXEC, &st) == 0 && st.st_mode & S_IXUSR) { - pid_t pid; if ((pid = fork()) == -1) { print_error("failed to fork for " SV_SUSPEND_EXEC ": %s\n"); return 1; @@ -108,7 +106,6 @@ 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) { print_error("failed to fork for " SV_RESUME_EXEC ": %s\n"); return 1; diff --git a/src/handle_command.c b/src/handle_command.c @@ -8,180 +8,6 @@ #include <unistd.h> -#if 0 -int service_handle_command(service_t* s, service_command_t command) { - bool changed = false; - char path_buffer[PATH_MAX]; - int fd; - - switch (command) { - case S_STATUS: - if (s != NULL) { - response[0] = s; - return 1; - } - for (int i = 0; i < services_size; i++) { - response[i] = &services[i]; - } - return services_size; - - case S_START: - if (s == NULL) - return -ENOSV; - if (extra > 1) { - return -EBEXT; - } - if (s->state != STATE_INACTIVE) - return 0; - - if (extra == 1) { // pin - changed = s->restart_manual != S_RESTART; - s->restart_manual = S_RESTART; - } else { - changed = s->restart_manual != S_ONCE; - s->restart_manual = S_ONCE; - } - if (extra == 0 || extra == 1) - service_start(s, &changed); - - if (!changed) - return 0; - - s->status_change = time(NULL); - service_update_status(s); - - response[0] = s; - return 1; - - case S_STOP: - if (s == NULL) - return -ENOSV; - if (extra > 1) { - return -EBEXT; - } - if (s->state == STATE_INACTIVE) - return 0; - if (extra == 1) { // pin - changed = s->restart_manual != S_FORCE_DOWN; - s->restart_manual = S_FORCE_DOWN; - } else { - changed = s->restart_manual != S_DOWN; - s->restart_manual = S_DOWN; - } - if (extra == 0 || extra == 1) - service_stop(s, &changed); - - if (!changed) - return 0; - - s->status_change = time(NULL); - service_update_status(s); - - response[0] = s; - return 1; - - case S_SEND: - if (s == NULL) - return -ENOSV; - - service_kill(s, extra); - response[0] = s; - return 1; - - case S_PAUSE: - if (s == NULL) - return -ENOSV; - - if (s->state == STATE_INACTIVE || s->paused) - return 0; - - s->paused = true; - service_kill(s, SIGSTOP); - - s->status_change = time(NULL); - service_update_status(s); - - response[0] = s; - return 1; - - case S_RESUME: - if (s == NULL) - return -ENOSV; - - if (s->state == STATE_INACTIVE || s->state == STATE_DEAD || s->pid == 0 || !s->paused) - return 0; - - s->paused = false; - service_kill(s, SIGCONT); - - s->status_change = time(NULL); - service_update_status(s); - - response[0] = s; - return 1; - - case S_RESET: - if (s == NULL) - return -ENOSV; - - if (s->paused) { - s->paused = false; - service_kill(s, SIGCONT); - } - - s->fail_count = 0; - if (s->state == STATE_DEAD) - s->state = STATE_INACTIVE; - - s->status_change = time(NULL); - service_update_status(s); - - response[0] = s; - return 1; - - case S_EXIT: - daemon_running = false; - return 0; - - case S_SWITCH: - if (argv == NULL) - return -ENOSV; - - strncpy(runlevel, argv, SV_NAME_MAX); - - if (extra == 1) { - for (int i = 0; i < services_size; i++) { - services[i].restart_manual = S_DOWN; - } - } - - return 0; - - case S_ENABLE: - case S_DISABLE: - if (argv == NULL) - return -ENOSV; - - strcpy(path_buffer, extra == 1 ? "once-" : "up-"); - strcat(path_buffer, runlevel); - - if (command == S_ENABLE) { - if ((fd = openat(s->dir, path_buffer, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) - return 0; - close(fd); - } else { - if (remove(path_buffer) == -1) - return 0; - } - - response[0] = s; - return 1; - } - fprintf(stderr, "warning: handling command: unknown command 0x%2x%2x\n", command, extra); - return -EBADSV; -} -#endif - static int runit_signals[] = { [X_ALARM] = SIGALRM, [X_HUP] = SIGHUP, diff --git a/src/handle_exit.c b/src/handle_exit.c @@ -12,6 +12,7 @@ static void do_finish(service_t* s) { struct stat st; + if (fstatat(s->dir, "finish", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_FINISHING; if ((s->pid = fork_dup_cd_exec(s->dir, "./finish", null_fd, null_fd, null_fd)) == -1) { @@ -31,14 +32,14 @@ static void do_finish(service_t* s) { void service_handle_exit(service_t* s, bool signaled, int return_code) { + struct stat st; + s->pid = 0; if (s->restart_file == S_ONCE) s->restart_file = S_DOWN; if (s->restart_manual == S_ONCE) s->restart_manual = S_DOWN; - struct stat st; - switch (s->state) { case STATE_SETUP: service_run(s); diff --git a/src/parse.c b/src/parse.c @@ -15,10 +15,10 @@ void parse_param_file(service_t* s, char* args[]) { int args_size = 0; int line_size = 0; char c; + bool start = true; strcpy(args[args_size++], "./run"); - bool start = true; if ((param_file = openat(s->dir, "params", O_RDONLY)) != -1) { while (read(param_file, &c, 1) > 0) { if (start && c == '%') { @@ -68,9 +68,9 @@ void parse_env_file(char** env) { /* uid:gid[:gid[:gid]...] */ static int parse_ugid_num(char* str, uid_t* uid, gid_t* gids) { - int i; - + int i; char* end; + *uid = strtoul(str, &end, 10); if (*end != ':') @@ -98,6 +98,7 @@ int parse_ugid(char* str, uid_t* uid, gid_t* gids) { char* end; char* groupstr = NULL; int gid_size = 0; + char* next; if (str[0] == ':') return parse_ugid_num(str + 1, uid, gids); @@ -117,7 +118,7 @@ int parse_ugid(char* str, uid_t* uid, gid_t* gids) { return 1; } - char* next = groupstr; + next = groupstr; while (next && gid_size < 60) { groupstr = next; diff --git a/src/register.c b/src/register.c @@ -13,6 +13,7 @@ static int fd_set_flag(int fd, int flags) { int rc; + if ((rc = fcntl(fd, F_GETFL)) == -1) return -1; @@ -55,7 +56,13 @@ static void init_supervise(service_t* s) { } service_t* service_register(int dir, const char* name, bool is_log_service) { - service_t* s; + service_t* s; + struct stat st; + bool autostart, autostart_once; + + char up_path[SV_NAME_MAX] = "up-", + once_path[SV_NAME_MAX] = "once-"; + if ((s = service_get(name)) == NULL) { s = &services[services_size++]; @@ -84,8 +91,6 @@ service_t* service_register(int dir, const char* name, bool is_log_service) { service_update_status(s); } - struct stat st; - if (s->is_log_service) { if (s->log_pipe.read == 0 || s->log_pipe.write == 0) pipe((int*) &s->log_pipe); @@ -96,11 +101,6 @@ service_t* service_register(int dir, const char* name, bool is_log_service) { s->log_service = service_register(s->dir, "log", true); } - bool autostart, autostart_once; - - char up_path[SV_NAME_MAX] = "up-"; - char once_path[SV_NAME_MAX] = "once-"; - strcat(up_path, runlevel); strcat(once_path, runlevel); diff --git a/src/runit.c b/src/runit.c @@ -1,112 +0,0 @@ -#include "service.h" -#include "util.h" - -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <string.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <unistd.h> - - -static int runit_signals[] = { - [X_ALARM] = SIGALRM, - [X_HUP] = SIGHUP, - [X_INT] = SIGINT, - [X_QUIT] = SIGQUIT, - [X_USR1] = SIGUSR1, - [X_USR2] = SIGUSR2, -}; - -void service_update_status(service_t* s) { - int fd; - if ((fd = openat(s->dir, "supervise/status", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { - print_error("cannot open supervise/status: %s\n"); - return; - } - - service_serial_t stat_runit; - service_encode(s, &stat_runit); - - if (write(fd, &stat_runit, sizeof(stat_runit)) == -1) { - print_error("cannot write to supervise/status: %s\n"); - return; - } - - close(fd); - - if ((fd = openat(s->dir, "supervise/stat", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { - print_error("cannot create supervise/stat: %s\n"); - return; - } - - const char* stat_human = service_status_name(s); - if (write(fd, stat_human, strlen(stat_human)) == -1) { - print_error("cannot write to supervise/stat: %s\n"); - return; - } - - close(fd); - - if ((fd = openat(s->dir, "supervise/pid", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { - print_error("cannot create supervise/stat: %s\n"); - return; - } - - dprintf(fd, "%d", s->pid); - - close(fd); -} - -#if 0 -void service_handle_command_runit(service_t* s, sv_command_runit_t command) { -# if SV_RUNIT_COMPAT != 0 - switch (command) { - case R_DOWN: - case R_TERM: - s->restart_manual = S_FORCE_DOWN; - service_stop(s, NULL); - break; - case R_UP: - s->restart_manual = S_RESTART; - service_start(s, NULL); - break; - case R_ONCE: - s->restart_manual = S_ONCE; - service_start(s, NULL); - break; - case R_KILL: - s->restart_manual = S_FORCE_DOWN; - service_kill(s, SIGKILL); - break; - case R_PAUSE: - if (!s->paused) { - s->paused = true; - service_kill(s, SIGSTOP); - } - break; - case R_CONT: - if (s->paused) { - s->paused = false; - service_kill(s, SIGCONT); - } - break; - case R_ALARM: - case R_HUP: - case R_INT: - case R_QUIT: - case R_USR1: - case R_USR2: - service_kill(s, runit_signals[command]); - break; - case R_EXIT: - // ignored - return; - } - - s->status_change = time(NULL); - service_update_status(s); -# endif -} -#endif diff --git a/src/service.c b/src/service.c @@ -33,6 +33,7 @@ service_t* service_get(const char* name) { int service_pattern(const char* name, service_t** dest, int dest_max) { int size = 0; + for (int i = 0; i < services_size && size < dest_max; i++) { if (pattern_test(name, services[i].name)) dest[size++] = &services[i]; @@ -43,15 +44,16 @@ int service_pattern(const char* name, service_t** dest, int dest_max) { int service_refresh_directory(void) { DIR* dp; struct dirent* ep; + struct stat st; + service_t* s; if ((dp = opendir(service_dir_path)) == 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]; + s = &services[i]; if (fstat(s->dir, &st) == -1 || !S_ISDIR(st.st_mode)) { if (s->pid) kill(s->pid, SIGKILL); @@ -87,6 +89,7 @@ int service_refresh_directory(void) { static bool is_dependency(service_t* d) { service_t* s; + for (int i = 0; i < depends_size; i++) { s = depends[i][0]; if (depends[i][1] == d && (s->state != STATE_INACTIVE || service_need_restart(s))) @@ -98,6 +101,7 @@ static bool is_dependency(service_t* d) { bool service_need_restart(service_t* s) { if (s->restart_manual == S_FORCE_DOWN) return is_dependency(s); + return s->restart_file == S_ONCE || s->restart_file == S_RESTART || s->restart_manual == S_ONCE || diff --git a/src/signame.c b/src/signame.c @@ -176,9 +176,9 @@ static signal_name_t signal_names[] = { int signame(char const* name) { char* endptr; int signum; - if ((signum = strtol(name, &endptr, 10)) && endptr == strchr(name, '\0')) { + + if ((signum = strtol(name, &endptr, 10)) && endptr == strchr(name, '\0')) return signum; - } // startswith SIG, remove that so -SIGKILL == -KILL if (strncmp(name, "SIG", 3) == 0) { diff --git a/src/stage.c b/src/stage.c @@ -17,12 +17,14 @@ static const char* stage_exec[] = { void service_stage(int stage) { + int pid, ttyfd, exitstat, sig = 0; + sigset_t ss; + struct sigaction sigact = { 0 }; + + // stage = 0 | 2 if (stage != 0 && stage != 2) return; - // stage = 0 | 2 - int pid, ttyfd, exitstat; - sigset_t ss; while ((pid = fork()) == -1) { print_error("error: unable to fork for stage1: %s\n"); sleep(5); @@ -44,8 +46,7 @@ void service_stage(int stage) { sigblock_all(true); - struct sigaction sigact = { 0 }; - sigact.sa_handler = SIG_DFL; + sigact.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); @@ -58,8 +59,6 @@ void service_stage(int stage) { _exit(1); } - int sig = 0; - sigemptyset(&ss); sigaddset(&ss, SIGCHLD); sigaddset(&ss, SIGCONT); diff --git a/src/start.c b/src/start.c @@ -39,9 +39,10 @@ static void set_pipes(service_t* s) { dup2(null_fd, STDERR_FILENO); } else { char service_log[PATH_MAX]; + int log_fd; + snprintf(service_log, PATH_MAX, "%s/%s-%s.log", SV_LOG_DIR, s->name, runlevel); - int log_fd; if ((log_fd = open(service_log, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) log_fd = null_fd; @@ -52,35 +53,38 @@ static void set_pipes(service_t* s) { } static void set_user(void) { - char buffer[SV_USER_BUFFER]; - int user_file; - if ((user_file = open("user", O_RDONLY)) != -1) { - ssize_t n; - if ((n = read(user_file, buffer, sizeof(buffer))) == -1) { - print_error("error: failed reading ./user: %s\n"); - close(user_file); - return; - } - buffer[n] = '\0'; - - uid_t uid; - gid_t gids[SV_USER_GROUP_MAX]; - if ((n = parse_ugid(buffer, &uid, gids)) <= 0) { - fprintf(stderr, "warn: malformatted user file\n"); - close(user_file); - return; - } + char buffer[SV_USER_BUFFER]; + int user_file; + ssize_t n; + uid_t uid; + gid_t gids[SV_USER_GROUP_MAX]; - setgroups(n, gids); - setgid(gids[0]); - setuid(uid); + if ((user_file = open("user", O_RDONLY)) == -1) + return; + + if ((n = read(user_file, buffer, sizeof(buffer))) == -1) { + print_error("error: failed reading ./user: %s\n"); + close(user_file); + return; + } + buffer[n] = '\0'; + if ((n = parse_ugid(buffer, &uid, gids)) <= 0) { + fprintf(stderr, "warn: malformatted user file\n"); close(user_file); + return; } + + setgroups(n, gids); + setgid(gids[0]); + setuid(uid); + + close(user_file); } void service_run(service_t* s) { struct stat st; + if (fstatat(s->dir, "run", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_ACTIVE_FOREGROUND; } else if (fstatat(s->dir, "start", &st, 0) != -1 && st.st_mode & S_IXUSR) { @@ -132,6 +136,8 @@ void service_run(service_t* s) { } void service_start(service_t* s) { + struct stat st; + if (s->state != STATE_INACTIVE) return; @@ -141,7 +147,6 @@ void service_start(service_t* s) { service_start(depends[i][1]); } - struct stat st; if (fstatat(s->dir, "setup", &st, 0) != -1 && st.st_mode & S_IXUSR) { s->state = STATE_SETUP; if ((s->pid = fork_dup_cd_exec(s->dir, "./setup", null_fd, null_fd, null_fd)) == -1) { diff --git a/src/status.c b/src/status.c @@ -0,0 +1,53 @@ +#include "service.h" +#include "util.h" + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <unistd.h> + + +void service_update_status(service_t* s) { + int fd; + const char* stat_human; + service_serial_t stat_runit; + + if ((fd = openat(s->dir, "supervise/status", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { + print_error("cannot open supervise/status: %s\n"); + return; + } + + service_encode(s, &stat_runit); + + if (write(fd, &stat_runit, sizeof(stat_runit)) == -1) { + print_error("cannot write to supervise/status: %s\n"); + return; + } + + close(fd); + + if ((fd = openat(s->dir, "supervise/stat", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { + print_error("cannot create supervise/stat: %s\n"); + return; + } + + stat_human = service_status_name(s); + if (write(fd, stat_human, strlen(stat_human)) == -1) { + print_error("cannot write to supervise/stat: %s\n"); + return; + } + + close(fd); + + if ((fd = openat(s->dir, "supervise/pid", O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { + print_error("cannot create supervise/stat: %s\n"); + return; + } + + dprintf(fd, "%d", s->pid); + + close(fd); +} diff --git a/src/supervise.c b/src/supervise.c @@ -46,6 +46,7 @@ static void signal_child(int unused) { static void check_services(void) { service_t* s; + for (int i = 0; i < services_size; i++) { s = &services[i]; if (s->state == STATE_DEAD) @@ -71,6 +72,7 @@ static void control_sockets(void) { service_t* s; char cmd, chr; bool read_signo = false; + for (int i = 0; i < services_size; i++) { s = &services[i]; while (read(s->control, &chr, 1) == 1) { @@ -90,7 +92,11 @@ static void control_sockets(void) { int service_supervise(const char* service_dir_, const char* runlevel_) { struct sigaction sigact = { 0 }; - sigact.sa_handler = signal_child; + service_t* s; + time_t start; + int running; + + sigact.sa_handler = signal_child; sigaction(SIGCHLD, &sigact, NULL); sigact.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigact, NULL); @@ -102,8 +108,6 @@ int service_supervise(const char* service_dir_, const char* runlevel_) { return 1; } - // setenv("SERVICE_RUNLEVEL", runlevel, true); - if ((null_fd = open("/dev/null", O_RDWR)) == -1) { print_error("error: cannot open /dev/null: %s\n"); null_fd = 1; @@ -122,14 +126,12 @@ int service_supervise(const char* service_dir_, const char* runlevel_) { printf(":: terminating\n"); - service_t* s; for (int i = 0; i < services_size; i++) { s = &services[i]; service_stop(s); } - time_t start = time(NULL); - int running; + start = time(NULL); do { sleep(1); // sleep for one second running = 0; diff --git a/src/util.c b/src/util.c @@ -15,6 +15,7 @@ ssize_t dgetline(int fd, char* line, size_t line_buffer) { ssize_t line_size = 0; ssize_t rc; char c; + while (line_size < (ssize_t) line_buffer - 1 && (rc = read(fd, &c, 1)) == 1) { if (c == '\r') continue; @@ -48,8 +49,8 @@ ssize_t writestr(int fd, const char* str) { unsigned int stat_mode(const char* format, ...) { char path[PATH_MAX]; struct stat st; + va_list args; - va_list args; va_start(args, format); vsnprintf(path, PATH_MAX, format, args); va_end(args); @@ -62,6 +63,7 @@ unsigned int stat_mode(const char* format, ...) { int fork_dup_cd_exec(int dir, const char* path, int fd0, int fd1, int fd2) { pid_t pid; + if ((pid = fork()) == -1) { print_error("error: cannot fork process: %s\n"); return -1; @@ -81,6 +83,7 @@ int fork_dup_cd_exec(int dir, const char* path, int fd0, int fd1, int fd2) { int reclaim_console(void) { int ttyfd; + if ((ttyfd = open("/dev/console", O_RDWR)) == -1) return -1; @@ -95,6 +98,7 @@ int reclaim_console(void) { void sigblock_all(int unblock) { sigset_t ss; + sigemptyset(&ss); sigfillset(&ss); /* sigaddset(&ss, SIGALRM); @@ -111,9 +115,25 @@ void sigblock_all(int unblock) { long parse_long(const char* str, const char* name) { char* end; long l = strtol(str, &end, 10); + if (*end != '\0') { fprintf(stderr, "error: invalid %s '%s'\n", name, optarg); exit(1); } return l; } + +char* progname(char* path) { + char* match; + + for (;;) { + if ((match = strrchr(path, '/')) == NULL) + return path; + + if (match[1] != '\0') + return match + 1; + + *match = '\0'; + } + return path; +} diff --git a/src/wtmp.c b/src/wtmp.c @@ -10,13 +10,13 @@ void write_wtmp(int boot) { int fd; - if ((fd = open(OUR_WTMP, O_WRONLY | O_APPEND)) < 0) - return; - struct utmp utmp = { 0 }; struct utsname uname_buf; struct timeval tv; + if ((fd = open(OUR_WTMP, O_WRONLY | O_APPEND)) < 0) + return; + gettimeofday(&tv, 0); utmp.ut_tv.tv_sec = tv.tv_sec; utmp.ut_tv.tv_usec = tv.tv_usec;