commit c0010b9fb6af43268e8386a54a63accf8345d12c
parent e9e41609626596f6135cc00a225a0b32d50e1186
Author: Friedel Schön <[email protected]>
Date: Thu, 25 May 2023 14:17:11 +0200
removing socket, full runit compilant
Diffstat:
23 files changed, 556 insertions(+), 848 deletions(-)
diff --git a/docs/internal/command.txt b/docs/internal/command.txt
@@ -1,37 +1,23 @@
FISS COMMANDS
=============
-start (u) [0] <service>: start if not running
-start (u) [1] <service>: start if not running and pin as up
-start (u) [2] <service>: only pin as restart
-stop (d) [0] <service>: stop if running
-stop (d) [1] <service>: stop if running and pin as down
-stop (d) [2] <service>: only pin as down
-send (k) [s] <service>: send signal $s to service
-pause (p) [-] <service>: pause service (send SIGSTOP)
-resume (c) [-] <service>: unpause service (send SIGCONT)
-revive (v) [-] <service>: revive died service
-update (g) [-] <service>: force update info // todo
-exit (x) [-]: stop all services and kill the fsvs instance
-refresh (y) [-]: refresh the service directory
-status (a) [-] <service>: get status of the service
-status (a) [-]: get status of all services
+ + new in fiss, - same as in runit, ! different behaviour
-
-RUNIT COMMANDS
-==============
-
-down (d): stopts the service and pin as stopped
-up (u): starts the services and pin as started
-exit (x): does nothing (actually exits the runsv instance)
-once (o): starts the service but don't pin as started
-term (t): same as down
-kill (k): sends kill
-pause (p): pauses the service
-cont (c): resumes the service
-alarm (a): sends alarm
-hup (h): sends hup
-int (i): sends interrupt
-quit (q): sends quit
-usr1 (1): sends usr1
-usr2 (2): sends usr2
-\ No newline at end of file
+- up (u): starts the services, pin as started
+- down (d): stops the service, pin as stopped
+- once (o): starts the service, pin as started once
++ xup (U): stops the service, don't pin as stopped
++ xdown (D): stops the service, don't pin as stopped
+- term (t): same as down
+- kill (k): sends kill, pin as stopped
+- pause (p): pauses the service
+- cont (c): resumes the service
++ reset (r): resets the service (fail-count)
++ send (s): sends custom signal, followed by signal-byte
+- alarm (a): sends alarm
+- hup (h): sends hup
+- int (i): sends interrupt
+- quit (q): sends quit
+- usr1 (1): sends usr1
+- usr2 (2): sends usr2
+! exit (x): does nothing (actually exits the runsv instance)
+\ No newline at end of file
diff --git a/docs/internal/serialize.txt b/docs/internal/serialize.txt
@@ -1,59 +1,47 @@
FISS CONTROL RESPONSE
=====================
-+--+-/ /-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-| NAME0 | PID | STATUS CHANGE |FC|RC|FLAGS|
-+--+-/ /-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-NAME0 = name of services | null-terminated
-PID = pid of the current instance (dependening on state) | big endian
-STATUS CHANGE = unix timestamp of last update (why tai tho?) | big endian
-FC = fail count
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+FISS: | STATUS CHANGE |ST|RC|FC|FL| PID |PS|RS|FD|SR|
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+RUNIT: | STATUS CHANGE | TAIA NANO | PID |PS|WU|TR|SR|
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+STATUS CHANGE = unix seconds + 4611686018427387914ULL (tai, lower endian)
+ST = state (see below)
RC = last return code (0 if not exitted yet)
+FC = fail count
+FL = flags (see below)
+PID = current pid (big endian)
+PS = is paused (int boolean)
+RS = restart ('u' if want up, 'd' if want down)
+FD = forced down (int boolean, unused by fiss)
+SR = state runit (0 is down, 1 is running, 2 is finishing, not available in daemontools, unused by fiss)
+
+TAIA NANO = unix nanoseconds (written, never read)
+WU = wants up ('u' if want up, 'd' if want down)
+TR = was terminated (int boolean)
FLAGS
-----
-+--+--+--+--+--+--+--+--*--+--+--+--+--+--+--+--+
-| STATE |RSFIL|RSMAN|LSTEX|RD|PS|LS|HL| --- |
-+--+--+--+--+--+--+--+--*--+--+--+--+--+--+--+--+
-STATE = state of the service
-RSFIL = restart file (up-<runlevel>; 0 = down, 2 = once, 3 = restart)
++--+--+--+--+--+--+--+--+
+| --- |RSFIL|RSMAN|LSTEX|
++--+--+--+--+--+--+--+--+
+RSFIL = restart file (0 = down, 2 = once, 3 = restart)
RSMAN = restart manual override (0 = down, 1 = force down, 2 = once, 3 = restart)
-RD = absolute restart needed, combining above + dependencies
LSTEX = last exit (0 = never exitted, 1 = normally, 2 = signaled)
-PS = paused
-LS = is log service
-HS = has log service (in struct is pointer but stored as (void*) 1 or (void*) 0)
-- = nothing yet
STATE
-----
0 = inactive - is not enabled and does nothing
-1 = setup - ./setup is running atm
-2 = starting - ./start is running atm
-3 = active_dummy - service is considered as started but does nothing
-4 = active_foreground - ./run is running
-5 = active_background - ./start is done and ./stop is not called yet
-6 = active_pid - ./start is done and ./pid is not killed yet
+1 = setup - ./setup is running
+2 = starting - ./start is running
+3 = active_foreground - ./run is running
+4 = active_background - ./start is done and ./stop is not called yet
+5 = active_dummy - service is considered as started but does nothing
+6 = stopping - ./stop is running
7 = finishing - ./finish is running
-8 = stopping - ./stop is running
-9 = dead - was enabled but failed too much or another error appeared
-
-
-
-RUNIT CONTROL RESPONSE
-======================
-
-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-| TAI SECONDS | TAIA NANO | PID |PS|WU|TR|ST|
-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-TAI SECONDS = unix seconds + 4611686018427387914ULL | lower endian!
-TAIA NANO = unix nanoseconds (nulled-out as fiss don't store them)
-PID = current pid | big endian
-PS = is paused (int boolean)
-WU = wants up ('u' if want up, 'd' if want down)
-TR = was terminated (int boolean)
-ST = state (0 is down, 1 is running, 2 is finishing)
-
-yuup, there are no flags, boolean-flags still use the whole byte (and WU even uses 'u'/'d')
-\ No newline at end of file
+8 = dead - was enabled but failed too much or another error
+\ No newline at end of file
diff --git a/include/config.h b/include/config.h
@@ -138,3 +138,7 @@
#ifndef SV_RUNIT_COMPAT
# define SV_RUNIT_COMPAT 1
#endif
+
+#ifndef SV_STATUS_WAIT
+# define SV_STATUS_WAIT 5
+#endif
diff --git a/include/service.h b/include/service.h
@@ -7,86 +7,64 @@
#include <stdint.h>
#include <time.h>
-#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_RESET = '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 sv_command_runit {
- R_DOWN = 'd',
- R_UP = 'u',
- R_EXIT = 'x',
- R_TERM = 't',
- R_KILL = 'k',
- R_PAUSE = 'p',
- R_CONT = 'c',
- R_ONCE = 'o',
- R_ALARM = 'a',
- R_HUP = 'h',
- R_INT = 'i',
- R_QUIT = 'q',
- R_USR1 = '1',
- R_USR2 = '2',
-} sv_command_runit_t;
+typedef enum service_command {
+ X_UP = 'u', // starts the services, pin as started
+ X_DOWN = 'd', // stops the service, pin as stopped
+ X_XUP = 'U', // starts the service, set restart (d = down, f = force_down, o = once, u = up)
+ X_XDOWN = 'D', // stops the service, set restart (d = down, f = force_down, o = once, u = up)
+ X_ONCE = 'o', // starts the service, pin as once
+ X_TERM = 't', // same as down
+ X_KILL = 'k', // sends kill, pin as stopped
+ X_PAUSE = 'p', // pauses the service
+ X_CONT = 'c', // resumes the service
+ X_RESET = 'r', // resets the service
+ X_ALARM = 'a', // sends alarm
+ X_HUP = 'h', // sends hup
+ X_INT = 'i', // sends interrupt
+ X_QUIT = 'q', // sends quit
+ X_USR1 = '1', // sends usr1
+ X_USR2 = '2', // sends usr2
+ X_EXIT = 'x', // does nothing
+} service_command_t;
typedef enum service_state {
- STATE_INACTIVE,
- STATE_SETUP,
- STATE_STARTING,
- STATE_ACTIVE_DUMMY,
- STATE_ACTIVE_FOREGROUND,
- STATE_ACTIVE_BACKGROUND,
- STATE_ACTIVE_PID,
- STATE_FINISHING,
- STATE_STOPPING,
- STATE_DEAD,
+ STATE_INACTIVE = 0,
+ STATE_SETUP = 1,
+ STATE_STARTING = 2,
+ STATE_ACTIVE_FOREGROUND = 3,
+ STATE_ACTIVE_BACKGROUND = 4,
+ STATE_ACTIVE_DUMMY = 5,
+ STATE_STOPPING = 6,
+ STATE_FINISHING = 7,
+ STATE_DEAD = 8,
} service_state_t;
typedef enum service_exit {
- EXIT_NONE,
- EXIT_NORMAL,
- EXIT_SIGNALED,
+ EXIT_NONE = 0,
+ EXIT_NORMAL = 1,
+ EXIT_SIGNALED = 2,
} service_exit_t;
typedef enum service_restart {
- S_DOWN,
- S_FORCE_DOWN, // force down (manual)
- S_ONCE,
- S_RESTART,
+ S_DOWN = 0,
+ S_FORCE_DOWN = 1, // force down (manual)
+ S_ONCE = 2,
+ S_RESTART = 3,
} service_restart_t;
typedef struct service_serial {
- uint8_t pid[4];
- uint8_t status_change[8];
- uint8_t failcount[1];
- uint8_t return_code[1];
- uint8_t flags[2];
-} service_serial_t;
-
-typedef struct service_serial_runit {
uint8_t status_change[8];
- uint8_t status_change_nsec[4];
+ uint8_t state;
+ uint8_t return_code;
+ uint8_t fail_count;
+ uint8_t flags;
uint8_t pid[4];
- uint8_t paused[1];
- uint8_t wants_up[1];
- uint8_t terminated[1];
- uint8_t state[1];
-} service_serial_runit_t;
+ uint8_t paused;
+ uint8_t restart;
+ uint8_t force_down;
+ uint8_t state_runit;
+} service_serial_t;
typedef struct service {
char name[SV_NAME_MAX]; // name of service
@@ -107,38 +85,23 @@ typedef struct service {
struct service* log_service;
} service_t;
-typedef struct dependency {
- service_t* service;
- service_t* depends;
-} dependency_t;
-
-
-extern const char* command_error[];
-extern const char* command_string[];
+extern service_t services[];
+extern int services_size;
+extern char runlevel[];
+extern int service_dir;
+extern int null_fd;
+extern bool daemon_running;
+extern service_t* depends[][2];
+extern int depends_size;
+extern const char* service_dir_path;
-extern service_t services[];
-extern int services_size;
-extern char runlevel[];
-extern int 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 const char* service_dir_path;
-
-const char* service_status_name(service_t* s);
void service_decode(service_t* s, const service_serial_t* buffer); // for fsvc
void service_encode(service_t* s, service_serial_t* buffer); // for fsvs
-void service_encode_runit(service_t* s, service_serial_runit_t* buffer);
service_t* service_get(const char* name);
void service_handle_client(int client);
-int service_handle_command(void* argv, sv_command_t command, uint8_t extra, service_t** response);
-void service_handle_command_runit(service_t* s, sv_command_runit_t command);
+void service_handle_command(service_t* s, service_command_t command, char data);
void service_handle_exit(service_t* s, bool signaled, int return_code);
-void service_init_runit(service_t* s);
void service_kill(service_t* s, int signal);
bool service_need_restart(service_t* s);
int service_pattern(const char* name, service_t** dest, int dest_max);
@@ -147,8 +110,9 @@ service_t* service_register(int dir, const char* name, bool is_log_service);
void service_run(service_t* s);
int service_send_command(char command, char extra, const char* service, service_t* response, int response_max);
void service_stage(int stage);
-void service_start(service_t* s, bool* changed);
-void service_stop(service_t* s, bool* changed);
+void service_start(service_t* s);
+const char* service_status_name(service_t* s);
+void service_stop(service_t* s);
int service_supervise(const char* service_dir, const char* runlevel, bool force_socket);
void service_update_dependency(service_t* s);
void service_update_status(service_t* s);
diff --git a/include/util.h b/include/util.h
@@ -21,5 +21,7 @@ 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);
+int reclaim_console(void);
void sigblock_all(int unblock);
+
+long parse_long(const char* str, const char* name);
diff --git a/src/dependency.c b/src/dependency.c
@@ -13,8 +13,8 @@ void service_add_dependency(service_t* s, service_t* d) {
if (s == d)
return;
- depends[depends_size].service = s;
- depends[depends_size].depends = d;
+ depends[depends_size][0] = s;
+ depends[depends_size][1] = d;
depends_size++;
}
diff --git a/src/exec/chpst.c b/src/exec/chpst.c
@@ -9,16 +9,6 @@
#include <sys/file.h>
-static long parse_long(const char* str) {
- char* end;
- long l = strtol(str, &end, 10);
- if (*end != '\0') {
- fprintf(stderr, "error: invalid limit '%s'\n", optarg);
- exit(1);
- }
- return l;
-}
-
int main(int argc, char** argv) {
int opt, lockfd, lockflags, gid_len = 0;
char *arg0 = NULL, *root = NULL, *cd = NULL, *lock = NULL, *exec = NULL;
@@ -57,7 +47,7 @@ int main(int argc, char** argv) {
cd = optarg;
break;
case 'n':
- nicelevel = parse_long(optarg);
+ nicelevel = parse_long(optarg, "nice-level");
break;
case 'l':
lock = optarg;
diff --git a/src/exec/fsvc.c b/src/exec/fsvc.c
@@ -1,314 +1,207 @@
#include "config.h"
+#include "message.h"
#include "service.h"
-#include "signame.h"
+#include "util.h"
-#include <ctype.h>
+#include <fcntl.h>
#include <getopt.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+struct ident {
+ const char* name;
+ const char* command;
+};
-static const char HELP_MESSAGE[] =
- "Usage:\n"
- " %s <command> [-cfopqvV] [-r ..] [-s ..] [service]\n"
- " /etc/init.d/<service> [-cfopqvV] [-r ..] [-s ..] <command>\n"
- "\n"
- "Check the manual (fsvc 8) for more information.\n";
+static struct ident command_names[] = {
+ { "up", "u" }, // starts the services, pin as started
+ { "down", "d" }, // stops the service, pin as stopped
+ { "xup", "U" }, // stops the service, don't pin as stopped
+ { "xdown", "D" }, // stops the service, don't pin as stopped
+ { "once", "o" }, // same as xup
+ { "term", "t" }, // same as down
+ { "kill", "k" }, // sends kill, pin as stopped
+ { "pause", "p" }, // pauses the service
+ { "cont", "c" }, // resumes the service
+ { "reset", "r" }, // resets the service
+ { "alarm", "a" }, // sends alarm
+ { "hup", "h" }, // sends hup
+ { "int", "i" }, // sends interrupt
+ { "quit", "q" }, // sends quit
+ { "1", "1" }, // sends usr1
+ { "2", "2" }, // sends usr2
+ { "exit", "x" }, // does nothing
+ { "+up", "U0" }, // starts the service, don't modify pin
+ { "+down", "D0" }, // stops the service, don't modify pin
+ { "restart", "!D0U0" }, // restarts the service, don't modify pin
+ { "start", "!u" }, // start the service, pin as started, print status
+ { "stop", "!d" }, // stop the service, pin as stopped, print status
+ { "status", "!" }, // print status
+ { 0, 0 }
+};
-static const char VERSION_MESSAGE[] =
- "FISS v" SV_VERSION "\n";
+static const struct option long_options[] = {
+ { "version", no_argument, NULL, 'V' },
+ { "wait", no_argument, NULL, 'w' },
+ { 0 }
+};
+static char* progname(char* path) {
+ char* match;
+ for (;;) {
+ if ((match = strrchr(path, '/')) == NULL)
+ return path;
-void print_status(service_t* s, char* state, size_t size) {
- switch (s->state) {
- case STATE_SETUP:
- strncpy(state, "setup", size);
- break;
- case STATE_INACTIVE:
- strncpy(state, "inactive", size);
- break;
- case STATE_STARTING:
- strncpy(state, "starting", size);
- break;
- case STATE_ACTIVE_PID:
- snprintf(state, size, "active (pid) as %d", s->pid);
- break;
- case STATE_ACTIVE_BACKGROUND:
- strncpy(state, "active (background)", size);
- break;
- case STATE_ACTIVE_DUMMY:
- strncpy(state, "active (dummy)", size);
- break;
- case STATE_ACTIVE_FOREGROUND:
- snprintf(state, size, "active as %d", s->pid);
- break;
- case STATE_FINISHING:
- strncpy(state, "finishing", size);
- break;
- case STATE_STOPPING:
- strncpy(state, "stopping", size);
- break;
- case STATE_DEAD:
- strncpy(state, "dead", size);
- break;
- }
- time_t diff = time(NULL) - s->status_change;
- const char* diff_unit = "sec";
- if (diff >= 60) {
- diff /= 60;
- diff_unit = "min";
- }
- if (diff >= 60) {
- diff /= 60;
- diff_unit = "hours";
- }
- if (diff >= 24) {
- diff /= 24;
- diff_unit = "days";
+ if (match[1] != '\0')
+ return match + 1;
+
+ *match = '\0';
}
- int len = strlen(state);
- snprintf(state + len, size - len, " since %lu%s", diff, diff_unit);
+ return path;
}
-void print_service(service_t* s) {
- char state[100];
- print_status(s, state, sizeof(state));
-
- printf("- %s (%s)\n", s->name, state);
- printf(" [ %c ] restart on exit\n", s->restart_final ? 'x' : ' ');
- if (s->return_code > 0)
- printf(" [%3d] last return code (%s)\n", s->return_code, s->last_exit == EXIT_SIGNALED ? "signaled" : "exited");
- printf(" [%3d] fail count\n", s->fail_count);
- printf(" [ %c ] has log service\n", s->is_log_service ? '-'
- : s->log_service ? 'x'
- : ' ');
- printf(" [ %c ] is paused\n", s->paused ? 'x' : ' ');
- printf("\n");
+static int check_service(int dir) {
+ int fd;
+ if ((fd = openat(dir, "supervise/ok", O_WRONLY | O_NONBLOCK)) == -1)
+ return -1;
+ close(fd);
+ return 0;
}
-static char* to_upper(char* str) {
- for (char* c = str; *c; c++) {
- if (islower(*c))
- *c += 'A' - 'a';
- }
- return str;
+static time_t get_mtime(int dir) {
+ struct stat st;
+ if (fstatat(dir, "supervise/status", &st, 0) == -1)
+ return -1;
+ return st.st_mtim.tv_sec;
}
-void print_service_short(service_t* s) {
- bool active = s->state == STATE_ACTIVE_BACKGROUND ||
- s->state == STATE_ACTIVE_DUMMY ||
- s->state == STATE_ACTIVE_FOREGROUND ||
- s->state == STATE_ACTIVE_PID;
-
- bool wants_other = active != s->restart_final;
-
- if (s->state == STATE_SETUP || s->state == STATE_STARTING)
- printf("[ {+}]");
- else if (s->state == STATE_FINISHING || s->state == STATE_STOPPING)
- printf("[{-} ]");
- else if (active)
- printf("[ %s + ]", wants_other ? "<-" : " ");
- else
- printf("[ - %s ]", wants_other ? "->" : " ");
-
- printf(" %s", s->name);
-
- if (s->pid) {
- if (s->state == STATE_ACTIVE_PID || s->state == STATE_ACTIVE_FOREGROUND) {
- printf(" (pid: %d)", s->pid);
- } else if (s->last_exit == EXIT_SIGNALED) {
- printf(" (last exit: SIG%s)", sigabbr(s->return_code));
- } else if (s->last_exit == EXIT_NORMAL) {
- printf(" (last exit: %d)", s->return_code);
- }
- }
- printf("\n");
+static int send_command(int dir, const char* command) {
+ int fd;
+ if ((fd = openat(dir, "supervise/control", O_WRONLY | O_NONBLOCK)) == -1)
+ return -1;
+
+ if (write(fd, command, strlen(command)) == -1)
+ return -1;
+
+ close(fd);
+
+ return 0;
}
-static const struct option long_options[] = {
- { "verbose", no_argument, 0, 'v' },
- { "version", no_argument, 0, 'V' },
- { "runlevel", no_argument, 0, 'r' },
- { "pin", no_argument, 0, 'p' },
- { "once", no_argument, 0, 'o' },
- { "check", no_argument, 0, 'c' },
- { "reset", no_argument, 0, 'f' },
- { "short", no_argument, 0, 'q' },
- { 0 }
-};
+int status(int dir) {
+ int fd;
+ if ((fd = openat(dir, "supervise/status", O_RDONLY | O_NONBLOCK)) == -1)
+ return -1;
-int main(int argc, char** argv) {
- strncpy(runlevel, getenv(SV_RUNLEVEL_DEFAULT_ENV) ? getenv(SV_RUNLEVEL_DEFAULT_ENV) : SV_RUNLEVEL_DEFAULT, SV_NAME_MAX);
+ service_serial_t buffer;
+ service_t s;
- char* argexec = argv[0];
+ if (read(fd, &buffer, sizeof(buffer)) == -1) {
+ close(fd);
+ return -1;
+ }
- bool check = false,
- pin = false,
- once = false,
- reset = false,
+ close(fd);
- short_ = false;
+ service_decode(&s, &buffer);
- int c;
- while ((c = getopt_long(argc, argv, ":Vvqr:pocf", long_options, NULL)) > 0) {
- switch (c) {
- case 'r':
- strncpy(runlevel, optarg, SV_NAME_MAX);
- break;
- case 'q':
- short_ = true;
- break;
- case 'v':
- verbose = true;
- break;
+ printf("%d\n", s.pid);
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ int opt;
+ int timeout = SV_STATUS_WAIT;
+
+ const char* command = NULL;
+
+ while ((opt = getopt_long(argc, argv, ":Vw:", long_options, NULL)) != -1) {
+ switch (opt) {
case 'V':
- printf(VERSION_MESSAGE);
- return 0;
- case 'p':
- pin = true;
- break;
- case 'o':
- once = true;
+ // version
break;
- case 'c':
- check = true;
- break;
- case 'f':
- reset = true;
+ case 'w':
+ timeout = parse_long(optarg, "seconds");
break;
+ default:
case '?':
if (optopt)
fprintf(stderr, "error: invalid option -%c\n", optopt);
else
fprintf(stderr, "error: invalid option %s\n", argv[optind - 1]);
- fprintf(stderr, "%s", HELP_MESSAGE);
- return 1;
+ print_usage_exit(PROG_FSVC, 1);
}
}
- argc -= optind;
- argv += optind;
-
- if (argc < 1) {
- printf("fsvc [options] <command> [service]\n");
- return 1;
- }
-
- const char* command_str = argv[0];
- argv++, argc--;
- const char* service;
- char command, extra = 0;
+ argc -= optind, argv += optind;
- if (streq(service = basename(argexec), "fsvc")) {
- if (argc > 0) {
- service = argv[0];
- argv++, argc--;
- } else {
- service = NULL;
+ if (argc == 0) {
+ fprintf(stderr, "error: command omitted\n");
+ print_usage_exit(PROG_FSVC, 1);
+ }
+ for (struct ident* ident = command_names; ident->name != NULL; ident++) {
+ if (streq(ident->name, argv[0])) {
+ command = ident->command;
+ break;
}
}
+ if (command == NULL) {
+ fprintf(stderr, "error: unknown command '%s'\n", argv[0]);
+ print_usage_exit(PROG_FSVC, 1);
+ }
- if (streq(command_str, "up") || streq(command_str, "start") || streq(command_str, "down") || streq(command_str, "stop")) {
- if (!service) {
- printf("service omitted\n");
- return 1;
- }
+ argc--, argv++;
- command = streq(command_str, "down") || streq(command_str, "stop") ? S_STOP : S_START;
- extra = pin;
- pin = false;
- } else if (streq(command_str, "send") || streq(command_str, "kill")) {
- if (!service) {
- printf("service omitted\n");
- return 1;
- }
- if (argc == 1) {
- printf("signal omitted\n");
- return 1;
- }
- if ((extra = signame(argv[1])) == -1) {
- printf("unknown signalname\n");
- return 1;
- }
+ if (argc == 0) {
+ fprintf(stderr, "error: at least one service must be specified\n");
+ print_usage_exit(PROG_FSVC, 1);
+ }
- command = S_SEND;
- } else if (streq(command_str, "enable") || streq(command_str, "disable")) {
- if (!service) {
- printf("service omitted\n");
- return 1;
- }
+ chdir(SV_SERVICE_DIR);
- command = streq(command_str, "enable") ? S_ENABLE : S_DISABLE;
- extra = once;
- once = false;
- } else if (streq(command_str, "status")) {
- command = S_STATUS;
- extra = check;
- check = false;
- } else if (streq(command_str, "pause") || streq(command_str, "resume")) {
- if (!service) {
- printf("service omitted\n");
- return 1;
- }
+ bool print_status;
+ if ((print_status = command[0] == '!')) {
+ command++;
+ }
- command = streq(command_str, "pause") ? S_PAUSE : S_RESUME;
- } else if (streq(command_str, "reset")) {
- if (!service) {
- printf("service omitted\n");
- return 1;
+ 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]);
+ continue;
}
- command = S_RESET;
- extra = 0;
- } else if (streq(command_str, "switch")) {
- if (!service) {
- printf("runlevel omitted\n");
- return 1;
+ if (check_service(dir) == -1) {
+ fprintf(stderr, "warning: '%s' is not a valid service\n", argv[0]);
+ continue;
}
- command = S_SWITCH;
- extra = reset;
- reset = false;
- } else {
- printf("unknown command '%s'\n", command_str);
- return 1;
- }
-
- if (check)
- printf("warn: --check specified but not used\n");
- if (pin)
- printf("warn: --pin specified but not used\n");
- if (once)
- printf("warn: --once specified but not used\n");
- if (reset)
- printf("warn: --reset specified but not used\n");
-
-
- service_t response[SV_SOCKET_SERVICE_MAX];
- int rc;
-
- if (check) {
- service_t s;
- if ((rc = service_send_command(command, extra, service, &s, 1)) != 1) {
- printf("error: %s (errno: %d)\n", command_error[-rc], -rc);
- return 1;
+ if ((mod = get_mtime(dir)) == -1) {
+ fprintf(stderr, "warning: cannot get modify-time of '%s'\n", argv[0]);
+ continue;
}
- return s.state == STATE_ACTIVE_PID || s.state == STATE_ACTIVE_DUMMY || s.state == STATE_ACTIVE_FOREGROUND || s.state == STATE_ACTIVE_BACKGROUND;
- } else {
- rc = service_send_command(command, extra, service, response, SV_SOCKET_SERVICE_MAX);
- if (rc < 0) {
- printf("error: %s (errno: %d)\n", command_error[-rc], -rc);
- return 1;
+ if (command[0] != '\0') {
+ if (send_command(dir, command) == -1) {
+ fprintf(stderr, "warning: unable to send command to '%s'\n", argv[0]);
+ continue;
+ }
+ } else {
+ mod++; // avoid modtime timeout
}
- for (int i = 0; i < rc; i++) {
- if (short_)
- print_service_short(&response[i]);
- else
- print_service(&response[i]);
+ start = time(NULL);
+ if (print_status) {
+ while (get_mtime(dir) == mod && time(NULL) - start < timeout)
+ usleep(500); // sleep half a secound
+
+ printf(get_mtime(dir) == mod ? "timeout: %s: " : "ok: %s: ", progname(argv[i]));
+ if (status(dir) == -1)
+ printf("unable to access supervise/status\n");
}
}
}
diff --git a/src/exec/fsvs.c b/src/exec/fsvs.c
@@ -10,13 +10,8 @@
#include <sys/wait.h>
#include <unistd.h>
-#define SV_DEPENDS_MAX_STR static_stringify(SV_DEPENDS_MAX)
-#define MAX_SERVICE_STR static_stringify(SV_SERVICE_MAX)
-#define SV_STOP_TIMEOUT_STR static_stringify(SV_STOP_TIMEOUT)
-
static const struct option long_options[] = {
- { "verbose", no_argument, 0, 'v' },
{ "version", no_argument, 0, 'V' },
{ "force", no_argument, 0, 'f' },
{ 0 }
@@ -32,16 +27,14 @@ int main(int argc, char** argv) {
bool force_socket = false;
int c;
- while ((c = getopt_long(argc, argv, ":vVf", long_options, NULL)) > 0) {
+ while ((c = getopt_long(argc, argv, ":Vf", long_options, NULL)) > 0) {
switch (c) {
- case 'v':
- verbose = true;
- break;
case 'V':
print_version_exit();
case 'f':
force_socket = true;
break;
+ default:
case '?':
if (optopt)
fprintf(stderr, "error: invalid option -%c\n", optopt);
diff --git a/src/exec/init.lnk b/src/exec/init.lnk
@@ -0,0 +1 @@
+finit
+\ No newline at end of file
diff --git a/src/handle_client.c b/src/handle_client.c
@@ -1,67 +0,0 @@
-#include "service.h"
-
-#include <stdio.h>
-#include <unistd.h>
-
-
-void service_handle_client(int client) {
- char command[2] = { 0, 0 };
- char service_name[SV_NAME_MAX];
-
- read(client, command, sizeof(command));
-
- ssize_t service_len = readstr(client, 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;
- service_t* response[SV_SOCKET_SERVICE_MAX];
- service_t* request[SV_SOCKET_SERVICE_MAX];
-
- if (service_len > 0) {
- if (command[0] == S_SWITCH) {
- res = service_handle_command(service_name, command[0], command[1], response + res_off);
- } else {
- int req_size = service_pattern(service_name, request, 128);
- if (req_size == 0) {
- res = -EBADSV;
- goto cleanup;
- }
- for (int i = 0; i < req_size; i++) {
- res = service_handle_command(request[i], command[0], command[1], response + res_off);
- if (res < 0)
- goto cleanup;
- res_off += res;
- }
- }
- } else {
- res = service_handle_command(NULL, command[0], command[1], response);
- if (res < 0)
- goto cleanup;
-
- res_off = res;
- }
-
-
-cleanup:
- if (res < 0) {
- res *= -1;
- write(client, &res, 1);
- goto cleanup;
- } else {
- write(client, "", 1);
- service_serial_t service_buffer;
-
- for (int i = 0; i < res_off; i++) {
- service_encode(response[i], &service_buffer);
- writestr(client, response[i]->name);
- write(client, &service_buffer, sizeof(service_buffer));
- }
- write(client, "", 1);
- }
- close(client);
-}
diff --git a/src/handle_command.c b/src/handle_command.c
@@ -8,11 +8,11 @@
#include <unistd.h>
-int service_handle_command(void* argv, sv_command_t command, unsigned char extra, service_t** response) {
- service_t* s = argv;
- bool changed = false;
- char path_buffer[PATH_MAX];
- int fd;
+#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:
@@ -180,3 +180,108 @@ int service_handle_command(void* argv, sv_command_t command, unsigned char extra
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,
+ [X_INT] = SIGINT,
+ [X_QUIT] = SIGQUIT,
+ [X_USR1] = SIGUSR1,
+ [X_USR2] = SIGUSR2,
+};
+
+void service_handle_command(service_t* s, service_command_t command, char data) {
+ switch (command) {
+ case X_UP:
+ s->restart_manual = S_RESTART;
+ service_start(s);
+ break;
+ case X_ONCE:
+ s->restart_manual = S_ONCE;
+ service_start(s);
+ break;
+ case X_DOWN:
+ case X_TERM:
+ s->restart_manual = S_FORCE_DOWN;
+ service_stop(s);
+ break;
+ case X_XUP:
+ switch (data) {
+ case 'd':
+ s->restart_manual = S_DOWN;
+ break;
+ case 'f':
+ s->restart_manual = S_FORCE_DOWN;
+ break;
+ case 'o':
+ s->restart_manual = S_ONCE;
+ break;
+ case 'u':
+ s->restart_manual = S_RESTART;
+ break;
+ }
+ service_start(s);
+ break;
+ case X_XDOWN:
+ switch (data) {
+ case 'd':
+ s->restart_manual = S_DOWN;
+ break;
+ case 'f':
+ s->restart_manual = S_FORCE_DOWN;
+ break;
+ case 'o':
+ s->restart_manual = S_ONCE;
+ break;
+ case 'u':
+ s->restart_manual = S_RESTART;
+ break;
+ }
+ service_stop(s);
+ break;
+ case X_KILL:
+ s->restart_manual = S_FORCE_DOWN;
+ service_kill(s, SIGKILL);
+ break;
+ case X_PAUSE:
+ if (!s->paused) {
+ s->paused = true;
+ service_kill(s, SIGSTOP);
+ }
+ break;
+ case X_CONT:
+ if (s->paused) {
+ s->paused = false;
+ service_kill(s, SIGCONT);
+ }
+ break;
+ case X_ALARM:
+ case X_HUP:
+ case X_INT:
+ case X_QUIT:
+ case X_USR1:
+ case X_USR2:
+ service_kill(s, runit_signals[command]);
+ break;
+ case X_RESET:
+ 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);
+ break;
+ case X_EXIT:
+ // ignored
+ return;
+ }
+
+ s->status_change = time(NULL);
+ service_update_status(s);
+}
diff --git a/src/handle_exit.c b/src/handle_exit.c
@@ -65,7 +65,6 @@ void service_handle_exit(service_t* s, bool signaled, int return_code) {
break;
case STATE_ACTIVE_DUMMY:
- case STATE_ACTIVE_PID:
case STATE_ACTIVE_BACKGROUND:
case STATE_STOPPING:
do_finish(s);
@@ -83,9 +82,6 @@ void service_handle_exit(service_t* s, bool signaled, int return_code) {
if (!signaled && return_code == 0) {
if (fstatat(s->dir, "stop", &st, 0) != -1 && st.st_mode & S_IXUSR) {
s->state = STATE_ACTIVE_BACKGROUND;
- } else if (fstatat(s->dir, "pid", &st, 0) != -1 && st.st_mode & S_IXUSR) {
- s->pid = parse_pid_file(s);
- s->state = STATE_ACTIVE_PID;
} else {
do_finish(s);
}
diff --git a/src/register.c b/src/register.c
@@ -11,6 +11,49 @@
#include <unistd.h>
+static int fd_set_flag(int fd, int flags) {
+ int rc;
+ if ((rc = fcntl(fd, F_GETFL)) == -1)
+ return -1;
+
+ if (fcntl(fd, F_SETFL, rc | flags) == -1)
+ return -1;
+
+ return 0;
+}
+
+static void init_supervise(service_t* s) {
+ int lockfd;
+ struct stat st;
+
+ if (fstatat(s->dir, "supervise", &st, 0) == -1)
+ mkdirat(s->dir, "supervise", 0744);
+
+ if (fstatat(s->dir, "supervise/ok", &st, 0) == -1)
+ mkfifoat(s->dir, "supervise/ok", 0644);
+
+ if (fstatat(s->dir, "supervise/control", &st, 0) == -1)
+ mkfifoat(s->dir, "supervise/control", 0644);
+
+ if (openat(s->dir, "supervise/ok", O_RDONLY | O_NONBLOCK) == -1) {
+ print_error("cannot open supervise/ok: %s\n");
+ return;
+ }
+
+ if ((s->control = openat(s->dir, "supervise/control", O_RDONLY | O_NONBLOCK)) == -1) {
+ print_error("cannot open supervise/ok: %s\n");
+ return;
+ }
+
+ fd_set_flag(s->control, O_NONBLOCK);
+
+ if ((lockfd = openat(s->dir, "supervise/lock", O_CREAT | O_WRONLY, 0644)) == -1) {
+ print_error("cannot create supervise/lock: %s\n");
+ return;
+ }
+ close(lockfd);
+}
+
service_t* service_register(int dir, const char* name, bool is_log_service) {
service_t* s;
@@ -35,7 +78,7 @@ service_t* service_register(int dir, const char* name, bool is_log_service) {
strncpy(s->name, name, sizeof(s->name));
- service_init_runit(s);
+ init_supervise(s);
s->status_change = time(NULL);
service_update_status(s);
diff --git a/src/runit.c b/src/runit.c
@@ -11,56 +11,23 @@
static int runit_signals[] = {
- [R_ALARM] = SIGALRM,
- [R_HUP] = SIGHUP,
- [R_INT] = SIGINT,
- [R_QUIT] = SIGQUIT,
- [R_USR1] = SIGUSR1,
- [R_USR2] = SIGUSR2,
+ [X_ALARM] = SIGALRM,
+ [X_HUP] = SIGHUP,
+ [X_INT] = SIGINT,
+ [X_QUIT] = SIGQUIT,
+ [X_USR1] = SIGUSR1,
+ [X_USR2] = SIGUSR2,
};
-void service_init_runit(service_t* s) {
-#if SV_RUNIT_COMPAT != 0
- int lockfd;
- struct stat st;
-
- if (fstatat(s->dir, "supervise", &st, 0) == -1)
- mkdirat(s->dir, "supervise", 0744);
-
- if (fstatat(s->dir, "supervise/ok", &st, 0) == -1)
- mkfifoat(s->dir, "supervise/ok", 0644);
-
- if (fstatat(s->dir, "supervise/control", &st, 0) == -1)
- mkfifoat(s->dir, "supervise/control", 0644);
-
- if (openat(s->dir, "supervise/ok", O_RDONLY | O_NONBLOCK) == -1) {
- print_error("cannot open supervise/ok: %s\n");
- return;
- }
-
- if ((s->control = openat(s->dir, "supervise/control", O_RDONLY | O_NONBLOCK)) == -1) {
- print_error("cannot open supervise/ok: %s\n");
- return;
- }
-
- if ((lockfd = openat(s->dir, "supervise/lock", O_CREAT | O_WRONLY, 0644)) == -1) {
- print_error("cannot create supervise/lock: %s\n");
- return;
- }
- close(lockfd);
-#endif
-}
-
void service_update_status(service_t* s) {
-#if SV_RUNIT_COMPAT != 0
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_runit_t stat_runit;
- service_encode_runit(s, &stat_runit);
+ 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");
@@ -90,11 +57,11 @@ void service_update_status(service_t* s) {
dprintf(fd, "%d", s->pid);
close(fd);
-#endif
}
+#if 0
void service_handle_command_runit(service_t* s, sv_command_runit_t command) {
-#if SV_RUNIT_COMPAT != 0
+# if SV_RUNIT_COMPAT != 0
switch (command) {
case R_DOWN:
case R_TERM:
@@ -140,5 +107,6 @@ void service_handle_command_runit(service_t* s, sv_command_runit_t command) {
s->status_change = time(NULL);
service_update_status(s);
-#endif
+# endif
}
+#endif
diff --git a/src/send_command.c b/src/send_command.c
@@ -1,63 +0,0 @@
-#include "service.h"
-#include "util.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-
-const char* command_error[] = {
- [0] = "success",
- [EBADCMD] = "command not found",
- [ENOSV] = "service required",
- [EBADSV] = "no matching services",
- [EBEXT] = "invalid extra"
-};
-
-int service_send_command(char command, char extra, const char* service, service_t* response, int response_max) {
- char request[2] = { command, extra };
-
- int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sockfd == -1) {
- print_error("error: cannot connect to socket: %s\n");
- exit(1);
- }
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), SV_CONTROL_SOCKET, runlevel);
-
- int ret;
- if ((ret = connect(sockfd, (struct sockaddr*) &addr, sizeof(addr))) == -1) {
- print_error("error: cannot connect to %s: %s\n", addr.sun_path);
- exit(EXIT_FAILURE);
- }
-
- write(sockfd, request, sizeof(request));
- writestr(sockfd, service);
-
- int res;
- read(sockfd, &res, 1);
-
- service_serial_t service_buffer;
-
- if (res == 0) {
- if (response) {
- while (res < response_max && readstr(sockfd, response[res].name) > 1) {
- read(sockfd, &service_buffer, sizeof(service_buffer));
- service_decode(&response[res], &service_buffer);
- res++;
- }
- }
- } else {
- res *= -1;
- }
-
- close(sockfd);
- return res;
-}
diff --git a/src/serialize.c b/src/serialize.c
@@ -7,15 +7,16 @@ const char* service_status_name(service_t* s) {
return "setup";
case STATE_STARTING:
return "starting";
- case STATE_ACTIVE_DUMMY:
case STATE_ACTIVE_FOREGROUND:
- case STATE_ACTIVE_BACKGROUND:
- case STATE_ACTIVE_PID:
return "run";
- case STATE_STOPPING:
- return "stopping";
+ case STATE_ACTIVE_BACKGROUND:
+ return "run (background)";
+ case STATE_ACTIVE_DUMMY:
+ return "run (dummy)";
case STATE_FINISHING:
return "finishing";
+ case STATE_STOPPING:
+ return "stopping";
case STATE_INACTIVE:
return "down";
case STATE_DEAD:
@@ -24,102 +25,80 @@ const char* service_status_name(service_t* s) {
}
void service_encode(service_t* s, service_serial_t* buffer) {
- buffer->pid[0] = (s->pid >> 0) & 0xff;
- buffer->pid[1] = (s->pid >> 8) & 0xff;
- buffer->pid[2] = (s->pid >> 16) & 0xff;
- buffer->pid[3] = (s->pid >> 24) & 0xff;
-
- buffer->status_change[0] = (s->status_change >> 0) & 0xff;
- buffer->status_change[1] = (s->status_change >> 8) & 0xff;
- buffer->status_change[2] = (s->status_change >> 16) & 0xff;
- buffer->status_change[3] = (s->status_change >> 24) & 0xff;
- buffer->status_change[4] = (s->status_change >> 32) & 0xff;
- buffer->status_change[5] = (s->status_change >> 40) & 0xff;
- buffer->status_change[6] = (s->status_change >> 48) & 0xff;
- buffer->status_change[7] = (s->status_change >> 56) & 0xff;
-
- buffer->failcount[0] = (s->fail_count);
- buffer->return_code[0] = (s->return_code);
-
- buffer->flags[0] = (s->state << 4) |
- (s->restart_file << 2) |
- (s->restart_manual << 0);
- buffer->flags[1] = (s->last_exit << 6) |
- (service_need_restart(s) << 5) |
- (s->paused << 4) |
- (s->is_log_service << 3) |
- ((s->log_service != NULL) << 2);
-}
-
-void service_encode_runit(service_t* s, service_serial_runit_t* buffer) {
uint64_t tai = (uint64_t) s->status_change + 4611686018427387914ULL;
- int runit_state;
+ int state_runit;
+
switch (s->state) {
case STATE_INACTIVE:
case STATE_DEAD:
- runit_state = 0;
+ state_runit = 0;
break;
case STATE_SETUP:
case STATE_STARTING:
case STATE_ACTIVE_DUMMY:
case STATE_ACTIVE_FOREGROUND:
case STATE_ACTIVE_BACKGROUND:
- case STATE_ACTIVE_PID:
- runit_state = 1;
+ case STATE_STOPPING:
+ state_runit = 1;
break;
case STATE_FINISHING:
- case STATE_STOPPING:
- runit_state = 2;
+ state_runit = 2;
break;
}
- buffer->status_change[0] = (tai >> 56) & 0xff;
- buffer->status_change[1] = (tai >> 48) & 0xff;
- buffer->status_change[2] = (tai >> 40) & 0xff;
- buffer->status_change[3] = (tai >> 32) & 0xff;
- buffer->status_change[4] = (tai >> 24) & 0xff;
- buffer->status_change[5] = (tai >> 16) & 0xff;
- buffer->status_change[6] = (tai >> 8) & 0xff;
- buffer->status_change[7] = (tai >> 0) & 0xff;
- buffer->status_change_nsec[0] = 0; // not implemented
- buffer->status_change_nsec[1] = 0; // not implemented
- buffer->status_change_nsec[2] = 0; // not implemented
- buffer->status_change_nsec[3] = 0; // not implemented
- buffer->pid[0] = (s->pid >> 0) & 0xff;
- buffer->pid[1] = (s->pid >> 8) & 0xff;
- buffer->pid[2] = (s->pid >> 16) & 0xff;
- buffer->pid[3] = (s->pid >> 24) & 0xff;
- buffer->paused[0] = (s->paused);
- buffer->wants_up[0] = service_need_restart(s) ? 'u' : 'd';
- buffer->terminated[0] = 0; // not implemented
- buffer->state[0] = runit_state;
+ buffer->status_change[0] = (tai >> 56) & 0xff;
+ buffer->status_change[1] = (tai >> 48) & 0xff;
+ buffer->status_change[2] = (tai >> 40) & 0xff;
+ buffer->status_change[3] = (tai >> 32) & 0xff;
+ buffer->status_change[4] = (tai >> 24) & 0xff;
+ buffer->status_change[5] = (tai >> 16) & 0xff;
+ buffer->status_change[6] = (tai >> 8) & 0xff;
+ buffer->status_change[7] = (tai >> 0) & 0xff;
+
+ buffer->state = s->state;
+ buffer->return_code = s->return_code;
+ buffer->fail_count = s->fail_count;
+
+ buffer->flags = (s->restart_file << 4) |
+ (s->restart_manual << 2) |
+ (s->last_exit << 0);
+
+ buffer->pid[0] = (s->pid >> 0) & 0xff;
+ buffer->pid[1] = (s->pid >> 8) & 0xff;
+ buffer->pid[2] = (s->pid >> 16) & 0xff;
+ buffer->pid[3] = (s->pid >> 24) & 0xff;
+
+ buffer->paused = s->paused;
+ buffer->restart = service_need_restart(s);
+ buffer->force_down = s->restart_manual == S_FORCE_DOWN;
+ buffer->state_runit = state_runit;
}
+
void service_decode(service_t* s, const service_serial_t* buffer) {
- s->pid = (buffer->pid[3] << 24) |
- (buffer->pid[2] << 16) |
- (buffer->pid[1] << 8) |
- (buffer->pid[0]);
+ uint64_t tai = ((uint64_t) buffer->status_change[0] << 56) |
+ ((uint64_t) buffer->status_change[1] << 48) |
+ ((uint64_t) buffer->status_change[2] << 40) |
+ ((uint64_t) buffer->status_change[3] << 32) |
+ ((uint64_t) buffer->status_change[4] << 24) |
+ ((uint64_t) buffer->status_change[5] << 16) |
+ ((uint64_t) buffer->status_change[6] << 8) |
+ ((uint64_t) buffer->status_change[7]);
- s->status_change = ((uint64_t) buffer->status_change[7] << 56) |
- ((uint64_t) buffer->status_change[6] << 48) |
- ((uint64_t) buffer->status_change[5] << 40) |
- ((uint64_t) buffer->status_change[4] << 32) |
- ((uint64_t) buffer->status_change[3] << 24) |
- ((uint64_t) buffer->status_change[2] << 16) |
- ((uint64_t) buffer->status_change[1] << 8) |
- ((uint64_t) buffer->status_change[0]);
+ s->status_change = tai - 4611686018427387914ULL;
- s->fail_count = buffer->failcount[0];
- s->return_code = buffer->return_code[0];
+ s->state = buffer->state;
+ s->return_code = buffer->return_code;
+ s->fail_count = buffer->fail_count;
+ s->restart_file = (buffer->flags >> 4) & 0x03;
+ s->restart_manual = (buffer->flags >> 2) & 0x03;
+ s->last_exit = (buffer->flags >> 0) & 0x03;
- s->state = (buffer->flags[0] >> 6) & 0x0F;
- s->restart_file = (buffer->flags[0] >> 4) & 0x03;
- s->restart_manual = (buffer->flags[0] >> 2) & 0x03;
+ s->pid = (buffer->pid[0] << 0) |
+ (buffer->pid[1] << 8) |
+ (buffer->pid[2] << 16) |
+ (buffer->pid[3] << 24);
- s->last_exit = (buffer->flags[1] >> 6) & 0x03;
- s->restart_file = (buffer->flags[1] >> 5) & 0x01;
- s->paused = (buffer->flags[1] >> 4) & 0x01;
- s->is_log_service = (buffer->flags[1] >> 3) & 0x01;
- s->log_service = (buffer->flags[1] >> 2) & 0x01 ? (void*) 1 : (void*) 0;
+ s->paused = buffer->paused;
+ s->restart_manual = buffer->restart;
}
diff --git a/src/service.c b/src/service.c
@@ -12,16 +12,16 @@
#include <unistd.h>
-service_t services[SV_SERVICE_MAX];
-int services_size = 0;
-char runlevel[SV_NAME_MAX];
-int service_dir;
-const char* service_dir_path;
-int control_socket;
-int null_fd;
-bool verbose = false;
-dependency_t depends[SV_DEPENDENCY_MAX];
-int depends_size;
+service_t services[SV_SERVICE_MAX];
+int services_size = 0;
+char runlevel[SV_NAME_MAX];
+int service_dir;
+const char* service_dir_path;
+int control_socket;
+int null_fd;
+bool verbose = false;
+service_t* depends[SV_DEPENDENCY_MAX][2];
+int depends_size;
service_t* service_get(const char* name) {
for (int i = 0; i < services_size; i++) {
@@ -88,8 +88,8 @@ 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].service;
- if (depends[i].depends == d && (s->state != STATE_INACTIVE || service_need_restart(s)))
+ s = depends[i][0];
+ if (depends[i][1] == d && (s->state != STATE_INACTIVE || service_need_restart(s)))
return true;
}
return false;
diff --git a/src/stage.c b/src/stage.c
@@ -58,7 +58,6 @@ void service_stage(int stage) {
_exit(1);
}
- int child;
int sig = 0;
sigemptyset(&ss);
@@ -75,7 +74,7 @@ void service_stage(int stage) {
reclaim_console();
- if (child == pid && stage == 0) {
+ if (stage == 0) {
if (!WIFEXITED(exitstat) || WEXITSTATUS(exitstat) != 0) {
if (WIFSIGNALED(exitstat)) {
/* this is stage 1 */
diff --git a/src/start.c b/src/start.c
@@ -131,22 +131,14 @@ void service_run(service_t* s) {
service_update_status(s);
}
-void service_start(service_t* s, bool* changed) {
+void service_start(service_t* s) {
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);
+ if (depends[i][0] == s)
+ service_start(depends[i][1]);
}
struct stat st;
diff --git a/src/stop.c b/src/stop.c
@@ -9,22 +9,17 @@
#include <unistd.h>
-void service_stop(service_t* s, bool* changed) {
+void service_stop(service_t* s) {
switch (s->state) {
case STATE_ACTIVE_DUMMY:
service_handle_exit(s, false, 0);
- if (changed)
- *changed = true;
s->status_change = time(NULL);
service_update_status(s);
break;
case STATE_ACTIVE_FOREGROUND:
- case STATE_ACTIVE_PID:
case STATE_SETUP:
kill(s->pid, SIGTERM);
- if (changed)
- *changed = true;
s->status_change = time(NULL);
service_update_status(s);
@@ -35,8 +30,6 @@ void service_stop(service_t* s, bool* changed) {
print_error("error: cannot execute ./stop: %s\n");
s->state = STATE_INACTIVE;
}
- if (changed)
- *changed = true;
s->status_change = time(NULL);
service_update_status(s);
@@ -45,8 +38,6 @@ void service_stop(service_t* s, bool* changed) {
case STATE_STOPPING:
case STATE_FINISHING:
kill(s->pid, SIGTERM);
- if (changed)
- *changed = true;
s->status_change = time(NULL);
service_update_status(s);
@@ -61,6 +52,6 @@ void service_kill(service_t* s, int signal) {
if (!s->pid)
return;
- if (s->state == STATE_ACTIVE_FOREGROUND || s->state == STATE_ACTIVE_PID)
+ if (s->state == STATE_ACTIVE_FOREGROUND)
kill(s->pid, signal);
}
diff --git a/src/supervise.c b/src/supervise.c
@@ -44,17 +44,6 @@ static void signal_child(int unused) {
service_handle_exit(s, WIFSIGNALED(status), WIFSIGNALED(status) ? WTERMSIG(status) : WEXITSTATUS(status));
}
-static void check_deaths(void) {
- service_t* s;
- for (int i = 0; i < services_size; i++) {
- s = &services[i];
- if (s->state == STATE_ACTIVE_PID) {
- if (kill(s->pid, 0) == -1 && errno == ESRCH)
- service_handle_exit(s, false, 0);
- }
- }
-}
-
static void check_services(void) {
service_t* s;
for (int i = 0; i < services_size; i++) {
@@ -63,13 +52,13 @@ static void check_services(void) {
continue;
if (service_need_restart(s)) {
if (s->state == STATE_INACTIVE) {
- service_start(s, NULL);
+ service_start(s);
s->status_change = time(NULL);
service_update_status(s);
}
} else {
if (s->state != STATE_INACTIVE) {
- service_stop(s, NULL);
+ service_stop(s);
s->status_change = time(NULL);
service_update_status(s);
}
@@ -77,31 +66,26 @@ static void check_services(void) {
}
}
-static void accept_socket(void) {
- int client_fd;
- if ((client_fd = accept(control_socket, NULL, NULL)) == -1) {
- if (errno == EWOULDBLOCK) {
- sleep(SV_ACCEPT_INTERVAL);
- } else {
- print_error("error: cannot accept client from control-socket: %s\n");
- }
- } else {
- service_handle_client(client_fd);
- }
-}
static void control_sockets(void) {
-#if SV_RUNIT_COMPAT != 0
service_t* s;
- char cmd;
+ char cmd, chr;
+ bool read_signo = false;
for (int i = 0; i < services_size; i++) {
s = &services[i];
-
- while (recv(s->control, &cmd, 1, MSG_DONTWAIT) == 1) {
- service_handle_command_runit(s, cmd);
+ while (read(s->control, &chr, 1) == 1) {
+ printf("handling '%c' from %s\n", chr, s->name);
+ if (read_signo) {
+ service_handle_command(s, cmd, chr);
+ read_signo = false;
+ } else if (chr == X_XUP || chr == X_XDOWN) {
+ cmd = chr;
+ read_signo = true;
+ } else {
+ service_handle_command(s, cmd, 0);
+ }
}
}
-#endif
}
int service_supervise(const char* service_dir_, const char* runlevel_, bool force_socket) {
@@ -120,81 +104,28 @@ int service_supervise(const char* service_dir_, const char* runlevel_, bool forc
// setenv("SERVICE_RUNLEVEL", runlevel, true);
- umask(0002);
-
- char socket_path[PATH_MAX];
- snprintf(socket_path, PATH_MAX, SV_CONTROL_SOCKET, runlevel);
-
if ((null_fd = open("/dev/null", O_RDWR)) == -1) {
print_error("error: cannot open /dev/null: %s\n");
null_fd = 1;
}
- struct stat socket_stat;
- if (force_socket) {
- if (unlink(socket_path) == -1 && errno != ENOENT) {
- 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);
- return 1;
- }
- // create socket
- if ((control_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- print_error("error: cannot create socket: %s\n");
- return 1;
- }
-
- // bind socket to address
- struct sockaddr_un addr = { 0 };
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
- if (bind(control_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
- 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("error: cannot listen to control socket: %s\n");
- return 1;
- }
-
- int sockflags = fcntl(control_socket, F_GETFL, 0);
- if (sockflags == -1) {
- 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");
- }
-
printf(":: starting services on '%s'\n", runlevel);
- if (service_refresh_directory() < 0)
- return 1;
-
- printf(":: started services\n");
-
// accept connections and handle requests
while (daemon_running) {
- check_deaths();
service_refresh_directory();
check_services();
control_sockets();
- accept_socket();
+ sleep(1);
}
- close(control_socket);
-
- if (unlink(socket_path) == -1 && errno != ENOENT) {
- print_error("error: cannot unlink socket: %s\n");
- }
printf(":: terminating\n");
service_t* s;
for (int i = 0; i < services_size; i++) {
s = &services[i];
- service_stop(s, NULL);
+ service_stop(s);
}
time_t start = time(NULL);
diff --git a/src/util.c b/src/util.c
@@ -3,9 +3,10 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <signal.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <string.h>
-#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -96,12 +97,23 @@ void sigblock_all(int unblock) {
sigset_t ss;
sigemptyset(&ss);
sigfillset(&ss);
-/* sigaddset(&ss, SIGALRM);
- sigaddset(&ss, SIGCHLD);
- sigaddset(&ss, SIGCONT);
- sigaddset(&ss, SIGHUP);
- sigaddset(&ss, SIGINT);
- sigaddset(&ss, SIGPIPE);
- sigaddset(&ss, SIGTERM);*/
+ /* sigaddset(&ss, SIGALRM);
+ sigaddset(&ss, SIGCHLD);
+ sigaddset(&ss, SIGCONT);
+ sigaddset(&ss, SIGHUP);
+ sigaddset(&ss, SIGINT);
+ sigaddset(&ss, SIGPIPE);
+ sigaddset(&ss, SIGTERM);*/
sigprocmask(unblock, &ss, NULL);
}
+
+
+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;
+}