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:
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)