commit a1a8b486bdc5fc997964b3c4be5bebe62033d4db
parent 39e4016d97c4ee78180fd9d73d6fa44c9c365025
Author: Friedel Schon <[email protected]>
Date: Fri, 28 Apr 2023 01:01:45 +0200
adding setup
Diffstat:
M | include/service.h | | | 112 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | src/restart.c | | | 21 | ++++++++++++++++----- |
M | src/start.c | | | 74 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
3 files changed, 122 insertions(+), 85 deletions(-)
diff --git a/include/service.h b/include/service.h
@@ -7,30 +7,31 @@
#include <stdint.h>
#include <time.h>
-#define SV_SERIAL_LEN 17
+#define SV_SERIAL_LEN 17
#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_EXIT = 'x', // kill the fsvs instance
- S_STATUS = 'a', // get status of all services
- S_SWITCH = 'l', // change runlevel
- S_ENABLE = 'E', // of extra disable
- S_DISABLE = 'D', // of extra disable
+ 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_EXIT = 'x', // kill the fsvs instance
+ S_STATUS = 'a', // get status of all services
+ S_SWITCH = 'l', // change runlevel
+ S_ENABLE = 'E', // of extra disable
+ S_DISABLE = 'D', // of extra disable
} sv_command_t;
typedef enum service_state {
STATE_INACTIVE,
+ STATE_SETUP,
STATE_STARTING,
STATE_ACTIVE_DUMMY,
STATE_ACTIVE_FOREGROUND,
@@ -49,25 +50,25 @@ typedef enum service_exit {
typedef enum service_restart {
S_DOWN,
- S_FORCE_DOWN, // force down (manual)
+ S_FORCE_DOWN, // force down (manual)
S_ONCE,
S_RESTART,
} 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
- 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;
+ 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 {
@@ -79,32 +80,33 @@ typedef struct dependency {
extern const char* command_error[];
extern const char* command_string[];
-extern service_t services[];
-extern int services_size;
-extern char runlevel[];
-extern const char* service_dir;
-extern int null_fd;
-extern int control_socket;
-extern bool daemon_running;
-extern bool verbose;
+extern service_t services[];
+extern int services_size;
+extern char runlevel[];
+extern const char* service_dir;
+extern int null_fd;
+extern int control_socket;
+extern bool daemon_running;
+extern bool verbose;
extern dependency_t depends[];
-extern int depends_size;
+extern int depends_size;
-char service_get_command(const char* command);
-int service_command(char command, char extra, const char* service, service_t* response, int response_max);
-int service_handle_command(void* s, sv_command_t command, uint8_t extra, service_t** response);
-int service_pattern(const char* name, service_t** dest, int dest_max);
-int service_refresh();
-int service_supervise(const char* service_dir, const char* runlevel, bool force_socket);
+char service_get_command(const char* command);
+int service_command(char command, char extra, const char* service, service_t* response, int response_max);
+int service_handle_command(void* s, sv_command_t command, uint8_t extra, service_t** response);
+int service_pattern(const char* name, service_t** dest, int dest_max);
+int service_refresh();
+int service_supervise(const char* service_dir, const char* runlevel, bool force_socket);
service_t* service_get(const char* name);
service_t* service_register(const char* name, bool is_log_service);
-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
+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);
+void service_run(service_t* s);
+\ No newline at end of file
diff --git a/src/restart.c b/src/restart.c
@@ -1,14 +1,22 @@
#include "config_parser.h"
+#include "service.h"
#include <errno.h>
#include <limits.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
+/*void stat_mode(const char* path_format, ...) __attribute__((format(printf, 1, 0))) {
+ va_list va;
+ va_start(va, path_format);
+ vsnprintf(char *, unsigned long, const char *, struct __va_list_tag *)
+}*/
+
static void do_finish(service_t* s) {
- char path_buffer[PATH_MAX];
+ char path_buffer[PATH_MAX];
struct stat stat_buffer;
snprintf(path_buffer, PATH_MAX, "%s/%s/finish", service_dir, s->name);
@@ -36,16 +44,19 @@ 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)
s->restart_manual = S_DOWN;
- char path_buffer[PATH_MAX];
+ char path_buffer[PATH_MAX];
struct stat stat_buffer;
switch (s->state) {
+ case STATE_SETUP:
+ service_run(s);
+ break;
case STATE_ACTIVE_FOREGROUND:
if (signaled) {
s->last_exit = EXIT_SIGNALED;
@@ -87,7 +98,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);
@@ -97,7 +108,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/start.c b/src/start.c
@@ -1,4 +1,5 @@
#include "config_parser.h"
+#include "service.h"
#include "user_group.h"
#include <errno.h>
@@ -9,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
static void set_pipes(service_t* s) {
@@ -20,13 +22,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("log", &estat) == 0 && estat.st_mode & S_IWRITE) { // is not
+ } else if (stat("log", &estat) == 0 && estat.st_mode & S_IWRITE) { // is not
int log_fd;
if ((log_fd = open("log", O_WRONLY | O_TRUNC)) == -1)
log_fd = null_fd;
@@ -54,7 +56,7 @@ 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) {
@@ -80,28 +82,10 @@ static void set_user() {
}
}
-
-void service_start(service_t* s, bool* changed) {
- if (s->state != STATE_INACTIVE)
- return;
-
- if (changed)
- *changed = true;
-
- 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);
- }
-
- for (int i = 0; i < depends_size; i++) {
- if (depends[i].service == s)
- service_start(depends[i].depends, NULL);
- }
-
- char path_buf[PATH_MAX];
-
+void service_run(service_t* s) {
+ char path_buf[PATH_MAX];
struct stat estat;
+
if (snprintf(path_buf, PATH_MAX, "%s/%s/run", service_dir, s->name) && stat(path_buf, &estat) == 0 && estat.st_mode & S_IXUSR) {
s->state = STATE_ACTIVE_FOREGROUND;
} else if (snprintf(path_buf, PATH_MAX, "%s/%s/start", service_dir, s->name) && stat(path_buf, &estat) == 0 && estat.st_mode & S_IXUSR) {
@@ -110,13 +94,14 @@ void service_start(service_t* s, bool* changed) {
s->state = STATE_ACTIVE_DUMMY;
} else {
printf("error in %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");
exit(1);
- } else if (s->pid == 0) { // child
+ } else if (s->pid == 0) { // child
if (setsid() == -1)
print_error("cannot setsid");
@@ -151,5 +136,44 @@ void service_start(service_t* s, bool* changed) {
}
}
s->status_change = time(NULL);
+}
+
+void service_start(service_t* s, bool* changed) {
+ if (s->state != STATE_INACTIVE)
+ return;
+
+ if (changed)
+ *changed = true;
+
+ 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);
+ }
+
+ for (int i = 0; i < depends_size; i++) {
+ if (depends[i].service == s)
+ service_start(depends[i].depends, NULL);
+ }
+
+ char path_buf[PATH_MAX];
+ struct stat estat;
+
+ if (snprintf(path_buf, PATH_MAX, "%s/%s/setup", service_dir, s->name) && stat(path_buf, &estat) == 0 && estat.st_mode & S_IXUSR) {
+ s->state = STATE_FINISHING;
+ if ((s->pid = fork()) == -1) {
+ print_error("cannot fork process");
+ } 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");
+ _exit(1);
+ }
+ } else {
+ service_run(s);
+ }
printf(":: started %s \n", s->name);
}