unix/fiss

service::restart -> s::restart_{manual,file} (7fbb4468f11aba24679eb8b6bb0759dcaccf91e5)
Repositories | LICENSE

commit 7fbb4468f11aba24679eb8b6bb0759dcaccf91e5
parent ac95deae520297b3aaafee07b14d42b6c9bf837c
Author: Friedel Schon <[email protected]>
Date:   Mon, 10 Apr 2023 11:37:14 +0200

service::restart -> s::restart_{manual,file}

Diffstat:
Minclude/service.h114++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/command.c32+++++++++++++++-----------------
Msrc/command_handler.c17+++++++----------
Msrc/exec/fsvc.c2+-
Dsrc/exec/pause.c16----------------
Msrc/register.c57++++++++++++++++++++++++++++-----------------------------
Msrc/restart.c15+++++++++------
Msrc/serialize.c42++++++++++++++++++++++--------------------
Msrc/service.c46+++++++++++++++++++++++++++++-----------------
Msrc/supervise.c55++++++++++++++++++++++++-------------------------------
10 files changed, 195 insertions(+), 201 deletions(-)

diff --git a/include/service.h b/include/service.h @@ -8,26 +8,25 @@ #include <time.h> #include <unistd.h> -#define SV_SERIAL_LEN 19 +#define SV_SERIAL_LEN 19 #define SV_HAS_LOGSERVICE ((void*) 1) -#define EBADCMD 1 // command not found -#define ENOSV 2 // service required -#define EBADSV 3 // no matching services -#define EBEXT 4 // invalid extra +#define EBADCMD 1 // command not found +#define ENOSV 2 // service required +#define EBADSV 3 // no matching services +#define EBEXT 4 // invalid extra typedef enum { - S_START = 'u', // start if not running and restart if failed - S_STOP = 'd', // stop if running and not restart if failed - S_SEND = 'k', // + signal | send signal to service - S_PAUSE = 'p', // pause service (send SIGSTOP) - S_RESUME = 'c', // unpause service (send SIGCONT) - S_REVIVE = 'v', // revive died service - S_UPDATE = 'g', // force update info // todo - S_EXIT = 'x', // kill the fsvs instance - S_REFRESH = 'y', // if service is given refresh command dir otherwise look for new services ?? - S_STATUS = 'a', // get status of all services - S_CHLEVEL = 'l', // change runlevel + S_START = 'u', // start if not running and restart if failed + S_STOP = 'd', // stop if running and not restart if failed + S_SEND = 'k', // + signal | send signal to service + S_PAUSE = 'p', // pause service (send SIGSTOP) + S_RESUME = 'c', // unpause service (send SIGCONT) + S_REVIVE = 'v', // revive died service + S_UPDATE = 'g', // force update info // todo + S_EXIT = 'x', // kill the fsvs instance + S_STATUS = 'a', // get status of all services + S_CHLEVEL = 'l', // change runlevel } sv_command_t; typedef enum service_state { @@ -48,20 +47,26 @@ typedef enum service_exit { EXIT_SIGNALED, } service_exit_t; +typedef enum service_restart { + S_NONE, + S_RESTART, + S_ONCE, +} service_restart_t; + typedef struct service { - char name[SV_NAME_MAX]; // name of service - service_state_t state; - pid_t pid; // pid of run - time_t status_change; // last status change - pipe_t log_pipe; // pipe for logging - bool restart; // should restart on exit - bool restart_once; // if once-{} is present - service_exit_t last_exit; // stopped signaled or exited - int return_code; // return code or signal - uint8_t fail_count; // current fail cound - bool is_log_service; // is a log service - bool paused; - struct service* log_service; + char name[SV_NAME_MAX]; // name of service + service_state_t state; + pid_t pid; // pid of run + time_t status_change; // last status change + pipe_t log_pipe; // pipe for logging + service_restart_t restart_manual; // should restart on exit + service_restart_t restart_file; // should restart on exit + service_exit_t last_exit; // stopped signaled or exited + int return_code; // return code or signal + uint8_t fail_count; // current fail cound + bool is_log_service; // is a log service + bool paused; + struct service* log_service; } service_t; typedef struct dependency { @@ -73,31 +78,32 @@ typedef struct dependency { extern string command_error[]; extern string command_string[]; -extern service_t services[]; -extern int services_size; -extern string runlevel; -extern int null_fd; -extern int control_socket; -extern bool daemon_running; -extern bool verbose; -extern string service_dir; +extern service_t services[]; +extern int services_size; +extern string runlevel; +extern int null_fd; +extern int control_socket; +extern bool daemon_running; +extern bool verbose; +extern string service_dir; extern dependency_t depends[]; -extern int depends_size; +extern int depends_size; -char service_get_command(string command); -int service_command(char command, char extra, string service, service_t* response, int response_max); -int service_handle_command(service_t* s, sv_command_t command, uint8_t extra, service_t** response); -int service_pattern(string name, service_t** dest, int dest_max); -int service_refresh(service_t** added); -int service_supervise(string service_dir, string runlevel, bool force_socket); +char service_get_command(string command); +int service_command(char command, char extra, string service, service_t* response, int response_max); +int service_handle_command(service_t* s, sv_command_t command, uint8_t extra, service_t** response); +int service_pattern(string name, service_t** dest, int dest_max); +int service_refresh(); +int service_supervise(string service_dir, string runlevel, bool force_socket); service_t* service_get(string name); -service_t* service_register(string name, bool log_service, bool* changed); -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 -void service_send(service_t* s, int signal); -void service_start(service_t* s, bool* changed); -void service_stop(service_t* s, bool* changed); -void service_store(service_t* s, uint8_t* buffer); // for fsvs -void service_update_dependency(service_t* s); -\ No newline at end of file +service_t* service_register(string 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 +void service_send(service_t* s, int signal); +void service_start(service_t* s, bool* changed); +void service_stop(service_t* s, bool* changed); +void service_store(service_t* s, uint8_t* buffer); // for fsvs +void service_update_dependency(service_t* s); +bool service_need_restart(service_t* s); +\ No newline at end of file diff --git a/src/command.c b/src/command.c @@ -9,28 +9,26 @@ string command_error[] = { - [0] = "success", + [0] = "success", [EBADCMD] = "command not found", - [ENOSV] = "service required", + [ENOSV] = "service required", [EBADSV] = "no matching services", - [EBEXT] = "invalid extra" + [EBEXT] = "invalid extra" }; string command_string[] = { - (void*) S_START, "start", // start if not running and restart if failed - (void*) S_START, "up", // start if not running and restart if failed - (void*) S_STOP, "stop", // stop if running and not restart if failed - (void*) S_STOP, "down", // stop if running and not restart if failed - (void*) S_SEND, "send", // + signal | send signal to service - (void*) S_SEND, "kill", // + signal | send signal to service - (void*) S_PAUSE, "pause", // pause service (send SIGSTOP) - (void*) S_RESUME, "resume", // unpause service (send SIGCONT) - (void*) S_REVIVE, "revive", // revive died service - (void*) S_UPDATE, "update", // force update info // todo - (void*) S_REFRESH, "refresh", // if service is given refresh command dir otherwise look for new services - (void*) S_REFRESH, "reload", // if service is given refresh command dir otherwise look for new services - (void*) S_STATUS, "status", // get status of all services - (void*) S_EXIT, "exit", // exit + (void*) S_START, "start", // start if not running and restart if failed + (void*) S_START, "up", // start if not running and restart if failed + (void*) S_STOP, "stop", // stop if running and not restart if failed + (void*) S_STOP, "down", // stop if running and not restart if failed + (void*) S_SEND, "send", // + signal | send signal to service + (void*) S_SEND, "kill", // + signal | send signal to service + (void*) S_PAUSE, "pause", // pause service (send SIGSTOP) + (void*) S_RESUME, "resume", // unpause service (send SIGCONT) + (void*) S_REVIVE, "revive", // revive died service + (void*) S_UPDATE, "update", // force update info // todo + (void*) S_STATUS, "status", // get status of all services + (void*) S_EXIT, "exit", // exit (void*) S_CHLEVEL, "chlevel", 0, 0 }; diff --git a/src/command_handler.c b/src/command_handler.c @@ -23,11 +23,11 @@ int service_handle_command(service_t* s, sv_command_t command, unsigned char ext if (extra > 2) { return -EBEXT; } - if (extra == 1 || extra == 2) { // pin - changed = !s->restart; - s->restart = true; + if (extra == 1 || extra == 2) { // pin + changed = !s->restart_manual; + s->restart_manual = S_RESTART; } else { - s->restart_once = true; + s->restart_manual = S_ONCE; } if (extra == 0 || extra == 1) service_start(s, &changed); @@ -43,9 +43,9 @@ int service_handle_command(service_t* s, sv_command_t command, unsigned char ext if (extra > 2) { return -EBEXT; } - if (extra == 1 || extra == 2) { // pin - changed = s->restart; - s->restart = false; + if (extra == 1 || extra == 2) { // pin + changed = s->restart_manual; + s->restart_manual = S_NONE; } if (extra == 0 || extra == 1) service_stop(s, &changed); @@ -97,9 +97,6 @@ int service_handle_command(service_t* s, sv_command_t command, unsigned char ext daemon_running = false; return 0; - case S_REFRESH: - return service_refresh(response); - default: fprintf(stderr, "warning: handling command: unknown command 0x%2x%2x\n", command, extra); return -EBADSV; diff --git a/src/exec/fsvc.c b/src/exec/fsvc.c @@ -81,7 +81,7 @@ void print_service(service_t* s, service_t* log) { printf("- %s (", s->name); print_status(s); printf(")\n"); - printf(" [ %c ] restart on exit\n", s->restart ? 'x' : ' '); + printf(" [ %c ] restart on exit\n", s->restart_file || s->restart_manual ? 'x' : ' '); printf(" [%3d] last return code (%s)\n", s->return_code, s->last_exit == EXIT_SIGNALED ? "signaled" : "exited"); if (s->log_service) { printf(" logging: "); diff --git a/src/exec/pause.c b/src/exec/pause.c @@ -1,16 +0,0 @@ -#include <signal.h> -#include <unistd.h> - -static void signal_nop(int signum) { - (void) signum; -} - -int main() { - signal(SIGTERM, signal_nop); - signal(SIGINT, signal_nop); - signal(SIGHUP, SIG_IGN); - - pause(); - - return 0; -} diff --git a/src/register.c b/src/register.c @@ -9,43 +9,41 @@ #include <sys/stat.h> #include <unistd.h> -service_t* service_register(string name, bool log_service, bool* changed_ptr) { +service_t* service_register(string name, bool is_log_service) { service_t* s; - if ((s = service_get(name)) != NULL) - return s; - - s = &services[services_size++]; - s->state = STATE_INACTIVE; - s->status_change = time(NULL); - s->restart = false; - s->restart_once = false; - s->last_exit = EXIT_NONE; - s->return_code = 0; - s->fail_count = 0; - s->log_service = NULL; - s->paused = false; - s->log_pipe.read = 0; - s->log_pipe.write = 0; - - strcpy(s->name, name); - - s->is_log_service = log_service; + if ((s = service_get(name)) == NULL) { + s = &services[services_size++]; + s->state = STATE_INACTIVE; + s->status_change = time(NULL); + s->restart_manual = S_NONE; + s->restart_file = S_NONE; + s->last_exit = EXIT_NONE; + s->return_code = 0; + s->fail_count = 0; + s->log_service = NULL; + s->paused = false; + s->log_pipe.read = 0; + s->log_pipe.write = 0; + s->is_log_service = is_log_service; + + strcpy(s->name, name); + } struct stat stat_buf; + char path_buffer[PATH_MAX]; - char path_buffer[PATH_MAX]; snprintf(path_buffer, PATH_MAX, "%s/%s/%s", service_dir, s->name, "log"); if (s->is_log_service) { if (s->log_pipe.read == 0 || s->log_pipe.write == 0) pipe((int*) &s->log_pipe); - } else if (stat(path_buffer, &stat_buf) > -1 && S_ISDIR(stat_buf.st_mode)) { + } else if (!s->log_service && stat(path_buffer, &stat_buf) > -1 && S_ISDIR(stat_buf.st_mode)) { snprintf(path_buffer, PATH_MAX, "%s/%s", s->name, "log"); if (!s->log_service) - s->log_service = service_register(path_buffer, true, NULL); + s->log_service = service_register(path_buffer, true); } bool autostart, autostart_once; @@ -56,17 +54,18 @@ service_t* service_register(string name, bool log_service, bool* changed_ptr) { snprintf(path_buffer, PATH_MAX, "%s/%s/once-%s", service_dir, s->name, runlevel); autostart_once = stat(path_buffer, &stat_buf) != -1 && S_ISREG(stat_buf.st_mode); + s->restart_file = S_NONE; + if (autostart && autostart_once) { fprintf(stderr, "error: %s is marked for up AND once!\n", s->name); - } else { - s->restart = autostart; - s->restart_once = autostart_once; + } else if (autostart) { + s->restart_file = S_RESTART; + } else if (autostart_once) { + if (s->restart_file == S_NONE) + s->restart_file = S_ONCE; } s->status_change = time(NULL); - if (changed_ptr != NULL) - *changed_ptr = true; - return s; } diff --git a/src/restart.c b/src/restart.c @@ -13,7 +13,7 @@ static void do_finish(service_t* s) { - char path_buffer[PATH_MAX]; + char path_buffer[PATH_MAX]; struct stat stat_buffer; snprintf(path_buffer, PATH_MAX, "%s/%s/finish", service_dir, s->name); @@ -41,10 +41,13 @@ 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->restart_once = false; + s->pid = 0; + if (s->restart_file == S_ONCE) + s->restart_file = S_NONE; + if (s->restart_manual == S_ONCE) + s->restart_manual = S_NONE; - char path_buffer[PATH_MAX]; + char path_buffer[PATH_MAX]; struct stat stat_buffer; switch (s->state) { @@ -89,7 +92,7 @@ void service_check_state(service_t* s, bool signaled, int return_code) { if (snprintf(path_buffer, PATH_MAX, "%s/%s/stop", service_dir, s->name) && stat(path_buffer, &stat_buffer) == 0 && stat_buffer.st_mode & S_IXUSR) { s->state = STATE_ACTIVE_BACKGROUND; } else if (snprintf(path_buffer, PATH_MAX, "%s/%s/pid", service_dir, s->name) && stat(path_buffer, &stat_buffer) == 0 && stat_buffer.st_mode & S_IRUSR) { - s->pid = parse_pid_file(s); + s->pid = parse_pid_file(s); s->state = STATE_ACTIVE_PID; } else { do_finish(s); @@ -99,7 +102,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/serialize.c b/src/serialize.c @@ -26,9 +26,10 @@ void service_store(service_t* s, uint8_t* buffer) { buffer[13] = (s->fail_count); buffer[14] = (s->return_code); buffer[15] = (s->last_exit << 0) | - (s->restart << 2) | - (s->is_log_service << 4) | - ((s->log_service != NULL) << 5); + (s->restart_file << 2) | + (s->restart_manual << 4) | + (s->is_log_service << 6) | + ((s->log_service != NULL) << 7); // +--+--+--+--+--+--+--+--+ // |FS|ZO|LS|AU|PS|DE|SG|RS| @@ -56,22 +57,23 @@ void service_store(service_t* s, uint8_t* buffer) { void service_load(service_t* s, const uint8_t* buffer) { s->state = buffer[0]; - s->pid = ((uint32_t) buffer[1] << 0) | - ((uint32_t) buffer[2] << 8) | - ((uint32_t) buffer[3] << 16) | - ((uint32_t) buffer[4] << 24); + s->pid = ((uint32_t) buffer[1] << 0) | + ((uint32_t) buffer[2] << 8) | + ((uint32_t) buffer[3] << 16) | + ((uint32_t) buffer[4] << 24); s->status_change = ((uint64_t) buffer[5] << 0) | - ((uint64_t) buffer[6] << 8) | - ((uint64_t) buffer[7] << 16) | - ((uint64_t) buffer[8] << 24) | - ((uint64_t) buffer[9] << 32) | - ((uint64_t) buffer[10] << 40) | - ((uint64_t) buffer[11] << 48) | - ((uint64_t) buffer[12] << 56); - s->fail_count = buffer[13]; - s->return_code = buffer[14]; - s->last_exit = buffer[15] & 0x03; - s->restart = (buffer[15] >> 2) & 0x01; - s->is_log_service = (buffer[15] >> 4) & 0x01; - s->log_service = (buffer[15] >> 5) ? (void*) 1 : NULL; + ((uint64_t) buffer[6] << 8) | + ((uint64_t) buffer[7] << 16) | + ((uint64_t) buffer[8] << 24) | + ((uint64_t) buffer[9] << 32) | + ((uint64_t) buffer[10] << 40) | + ((uint64_t) buffer[11] << 48) | + ((uint64_t) buffer[12] << 56); + s->fail_count = buffer[13]; + s->return_code = buffer[14]; + s->last_exit = buffer[15] & 0x03; + s->restart_file = (buffer[15] >> 2) & 0x03; + s->restart_manual = (buffer[15] >> 4) & 0x03; + s->is_log_service = (buffer[15] >> 6) & 0x01; + s->log_service = (buffer[15] >> 7) ? (void*) 1 : NULL; } \ No newline at end of file diff --git a/src/service.c b/src/service.c @@ -19,15 +19,15 @@ #include <sys/wait.h> #include <unistd.h> -service_t services[SV_SERVICE_MAX]; -int services_size = 0; -string runlevel; -string service_dir; -int control_socket; -int null_fd; -bool verbose = false; +service_t services[SV_SERVICE_MAX]; +int services_size = 0; +string runlevel; +string service_dir; +int control_socket; +int null_fd; +bool verbose = false; dependency_t depends[SV_DEPENDENCY_MAX]; -int depends_size; +int depends_size; service_t* service_get(string name) { @@ -47,8 +47,8 @@ int service_pattern(string name, service_t** dest, int dest_max) { return size; } -int service_refresh(service_t** added) { - DIR* dp; +int service_refresh() { + DIR* dp; struct dirent* ep; dp = opendir(service_dir); if (dp == NULL) { @@ -57,8 +57,7 @@ int service_refresh(service_t** added) { } struct stat stat_str; - char path_buffer[PATH_MAX]; - int added_len = 0; + char path_buffer[PATH_MAX]; for (int i = 0; i < services_size; i++) { service_t* s = &services[i]; @@ -81,10 +80,7 @@ int service_refresh(service_t** added) { if (stat(path_buffer, &stat_str) == -1 || !S_ISDIR(stat_str.st_mode)) continue; - bool changed; - service_t* s = service_register(ep->d_name, false, &changed); - if (changed && added != NULL) - added[added_len++] = s; + service_register(ep->d_name, false); } closedir(dp); @@ -93,5 +89,20 @@ int service_refresh(service_t** added) { for (int i = 0; i < services_size; i++) service_update_dependency(&services[i]); - return added_len; + return 0; } + + +static bool is_dependency(service_t* d) { + service_t* s; + for (int i = 0; i < depends_size; i++) { + s = depends[i].service; + if (depends[i].depends == d && (s->state != STATE_INACTIVE || service_need_restart(s))) + return true; + } + return false; +} + +bool service_need_restart(service_t* s) { + return s->restart_file || s->restart_manual || is_dependency(s); +} +\ No newline at end of file diff --git a/src/supervise.c b/src/supervise.c @@ -27,8 +27,8 @@ 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) { @@ -51,16 +51,6 @@ static void signal_child(int unused) { service_check_state(s, WIFSIGNALED(status), WIFSIGNALED(status) ? WTERMSIG(status) : WEXITSTATUS(status)); } -static bool is_dependency(service_t* d) { - service_t* s; - for (int i = 0; i < depends_size; i++) { - s = depends[i].service; - if (depends[i].depends == d && (s->state != STATE_INACTIVE || s->restart || s->restart_once || is_dependency(s))) - return true; - } - return false; -} - static void check_deaths() { service_t* s; for (int i = 0; i < services_size; i++) { @@ -78,7 +68,7 @@ static void check_services() { s = &services[i]; if (s->state == STATE_DEAD) continue; - if (s->restart || s->restart_once || is_dependency(s)) { + if (service_need_restart(s)) { if (s->state == STATE_INACTIVE) { service_start(s, NULL); } @@ -90,14 +80,27 @@ static void check_services() { } } +static void accept_socket() { + int client_fd; + if ((client_fd = accept(control_socket, NULL, NULL)) == -1) { + if (errno == EWOULDBLOCK) { + sleep(SV_ACCEPT_INTERVAL); + } else { + print_error("cannot accept client from control-socket"); + } + } else { + service_handle_socket(client_fd); + } +} + int service_supervise(string service_dir_, string 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); - runlevel = runlevel_; + runlevel = runlevel_; service_dir = service_dir_; setenv("SERVICE_RUNLEVEL", runlevel, true); @@ -112,7 +115,7 @@ int service_supervise(string service_dir_, string runlevel_, bool force_socket) printf(":: starting services on '%s'\n", runlevel); - if (service_refresh(NULL) < 0) + if (service_refresh() < 0) return 1; printf(":: started services\n"); @@ -134,7 +137,7 @@ int service_supervise(string service_dir_, string runlevel_, bool force_socket) // 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); @@ -156,21 +159,11 @@ int service_supervise(string service_dir_, string runlevel_, bool force_socket) } // accept connections and handle requests - int client_fd; while (daemon_running) { check_deaths(); + service_refresh(); check_services(); - - if ((client_fd = accept(control_socket, NULL, NULL)) == -1) { - if (errno == EWOULDBLOCK) { - sleep(SV_ACCEPT_INTERVAL); - } else { - print_error("cannot accept client from control-socket"); - return 1; - } - } else { - service_handle_socket(client_fd); - } + accept_socket(); } close(control_socket); @@ -188,9 +181,9 @@ int service_supervise(string service_dir_, string runlevel_, bool force_socket) } 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)