diff options
author | Leah Neukirchen <leah@vuxu.org> | 2023-10-21 18:32:28 +0200 |
---|---|---|
committer | Leah Neukirchen <leah@vuxu.org> | 2023-10-21 18:32:28 +0200 |
commit | 56e9eedfba7b68c925a5d0563b0e86d3fcb7f189 (patch) | |
tree | fd2c814df7c80402c8e2733ebcd7115efb69191d | |
parent | d0631e9d3732003dcc377eeb1fdcc39a5d8b9c7d (diff) | |
download | nitro-56e9eedfba7b68c925a5d0563b0e86d3fcb7f189.tar.gz nitro-56e9eedfba7b68c925a5d0563b0e86d3fcb7f189.tar.xz nitro-56e9eedfba7b68c925a5d0563b0e86d3fcb7f189.zip |
load and start services
-rw-r--r-- | nitro.c | 264 |
1 files changed, 195 insertions, 69 deletions
diff --git a/nitro.c b/nitro.c index 1bd32d0..d8ccadc 100644 --- a/nitro.c +++ b/nitro.c @@ -35,7 +35,10 @@ enum process_events { }; struct process { + struct process *next; + char name[64]; + char tag[64]; uv_timer_t timer; uv_process_t main; // uv_process_t log; @@ -48,6 +51,8 @@ struct process { char log_buffer[4096]; }; +struct process *process_head; + void disarm_timeout(struct process *p); void process_step(struct process *p, enum process_events ev); @@ -112,18 +117,21 @@ read_proc_log(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) struct process *p = stream->data; if (nread < 0) { - printf("LOG ERROR: %s\n", strerror(-nread)); + printf("LOG ERROR: %s\n", uv_strerror(nread)); return; } if (nread == UV_EOF) return; uv_buf_t b[] = { - { .base = "Wrote: ", .len = 7 }, + { .base = p->tag, .len = strlen(p->tag) }, { .base = buf->base, .len = nread }, }; + /* printf("isref: %d\n", uv_has_ref((uv_handle_t *)&p->wr_handle)); + printf("got log: %.*s\n", nread, buf->base); + */ uv_write(&p->wr_handle, (uv_stream_t *)&log_input, b, 2, done); } @@ -154,8 +162,12 @@ proc_launch(struct process *p) options.stdio_count = 3; options.stdio = child_stdio; options.exit_cb = callback_exit; - options.args = (const char *[]){"./slowexit.rb", "20", (char*)0}; - options.file = options.args[0]; + + char path[1024]; + snprintf(path, sizeof path, "%s/run", p->name); + + options.args = (char *[]){path, 0}; + options.file = path; int r = uv_spawn(loop, &p->main, &options); if (r) { @@ -166,6 +178,8 @@ proc_launch(struct process *p) p->start = uv_now(loop); p->state = PROC_STARTING; + snprintf(p->tag, sizeof p->tag, "%s[%d]: ", p->name, p->main.pid); + arm_timeout(p, 100); } @@ -326,29 +340,15 @@ process_step(struct process *p, enum process_events ev) } } -struct process mainproc; - void callback_signal(uv_signal_t *handle, int signum) { switch (signum) { case SIGINT: + case SIGTERM: uv_signal_stop(handle); uv_stop(loop); break; - - case SIGUSR1: - process_step(&mainproc, EVNT_WANT_UP); - break; - case SIGUSR2: - process_step(&mainproc, EVNT_WANT_DOWN); - break; - case SIGWINCH: - process_step(&mainproc, EVNT_WANT_RESTART); - break; - - default: - /* ignore */ } } @@ -364,15 +364,14 @@ void read_log(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { if (nread < 0) { - printf("LOG ERROR: %s\n", strerror(-nread)); + fprintf(stderr, "log error: %s\n", uv_strerror(nread)); uv_read_stop(stream); return; } if (nread == UV_EOF) return; - printf("LOG READ %ld\n", nread); - printf("LOG: %.*s\n", (int)nread, buf->base); + printf("LOG: %.*s", (int)nread, buf->base); } void @@ -391,23 +390,73 @@ open_control_socket() { // ignore errors } - struct sockaddr_un addr = { 0 }; - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof addr.sun_path - 1); - - controlsock = socket(AF_UNIX, SOCK_DGRAM, 0); - if (controlsock < 0) { - perror("nitro: socket"); - exit(111); - } - unlink(path); - mode_t mask = umask(0077); - int r = bind(controlsock, (struct sockaddr *)&addr, sizeof addr); - umask(mask); - if (r < 0) { - perror("nitro: bind"); - exit(111); - } + struct sockaddr_un addr = { 0 }; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof addr.sun_path - 1); + + controlsock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (controlsock < 0) { + perror("nitro: socket"); + exit(111); + } + unlink(path); + mode_t mask = umask(0077); + int r = bind(controlsock, (struct sockaddr *)&addr, sizeof addr); + umask(mask); + if (r < 0) { + perror("nitro: bind"); + exit(111); + } +} + +struct process * +new_service(char *name) +{ + struct stat st; + if (name[0] == '.') + return 0; + if (stat(name, &st) < 0) /* we are in SVDIR */ + return 0; + if (!S_ISDIR(st.st_mode)) + return 0; + + struct process *p = calloc(sizeof (struct process), 1); + strcpy(p->name, name); + p->state = PROC_DELAY; + + p->next = process_head; + process_head = p; + + return p; +} + +struct process * +find_service(char *name) +{ + for (struct process *p = process_head; p; p = p->next) + if (strcmp(p->name, name) == 0) + return p; + + return new_service(name); +} + +int +charsig(char c) +{ + switch (c) { + case 'p': return SIGSTOP; + case 'c': return SIGCONT; + case 'h': return SIGHUP; + case 'a': return SIGALRM; + case 'i': return SIGINT; + case 'q': return SIGQUIT; + case '1': return SIGUSR1; + case '2': return SIGUSR2; + case 't': return SIGTERM; + case 'k': return SIGKILL; + } + + return 0; } void @@ -418,10 +467,10 @@ callback_control_socket(uv_poll_t *handle, int status, int events) return; } - char buf[256]; - struct sockaddr_un src; - socklen_t srclen; - ssize_t r = recvfrom(controlsock, buf, sizeof buf, + char buf[256]; + struct sockaddr_un src; + socklen_t srclen; + ssize_t r = recvfrom(controlsock, buf, sizeof buf, MSG_DONTWAIT, (struct sockaddr *)&src, &srclen); if (r == sizeof buf) { @@ -435,49 +484,116 @@ callback_control_socket(uv_poll_t *handle, int status, int events) return; } - printf("got %ld from %d [%d %d]\n", r, srclen, status, events); + printf("got %ld from %d [%d %d]\n", r, srclen, status, events); + + if (r == 0) + return; + + // chop trailing newline + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = 0; - if (srclen > 0) { - char reply[] = "hewwo!\n"; - sendto(controlsock, reply, sizeof reply, + switch (buf[0]) { + case 'l': + for (struct process *p = process_head; p; p = p->next) { + printf("%s[%d] %d\n", p->name, p->main.pid, p->state); + } + goto ok; + case 'u': + case 'd': + case 'r': + { + struct process *p = find_service(buf + 1); + if (p) { + if (buf[0] == 'u') + process_step(p, EVNT_WANT_UP); + else if (buf[0] == 'd') + process_step(p, EVNT_WANT_DOWN); + else if (buf[0] == 'r') + process_step(p, EVNT_WANT_RESTART); + goto ok; + } + goto fail; + } + default: + if (charsig(buf[0])) { + struct process *p = find_service(buf + 1); + if (p && p->main.pid) { + kill(p->main.pid, charsig(buf[0])); + goto ok; + } + } + goto fail; + } + + +ok: + if (srclen > 0) { + char reply[] = "ok\n"; + sendto(controlsock, reply, sizeof reply, MSG_DONTWAIT, (struct sockaddr *)&src, srclen); - } + } + return; + +fail: + if (srclen > 0) { + char reply[] = "error\n"; + sendto(controlsock, reply, sizeof reply, + MSG_DONTWAIT, (struct sockaddr *)&src, srclen); + } } -int -main() +void +load_services() { - signal(SIGPIPE, SIG_IGN); + DIR *dir = opendir("."); + if (!dir) + abort(); - loop = uv_default_loop(); + struct dirent *ent; + while ((ent = readdir(dir))) + new_service(ent->d_name); - uv_disable_stdio_inheritance(); + closedir(dir); +} - open_control_socket(); +int +main(int argc, char *argv[]) +{ + if (argc < 1) + return 111; - /* we use plain poll access for the control socket, so we can - handle requests without any memory overhead. */ - uv_poll_t control_poll; - uv_poll_init(loop, &control_poll, controlsock); + loop = uv_default_loop(); + uv_disable_stdio_inheritance(); - uv_poll_start(&control_poll, UV_READABLE, callback_control_socket); + const char *dir = "/var/service"; + if (argc == 2) + dir = argv[1]; - uv_signal_t sigusr1; - uv_signal_init(loop, &sigusr1); - uv_signal_start(&sigusr1, callback_signal, SIGUSR1); + if (chdir(dir) < 0) { + perror("nitro: chdir"); + return 111; + } - uv_signal_t sigusr2; - uv_signal_init(loop, &sigusr2); - uv_signal_start(&sigusr2, callback_signal, SIGUSR2); + signal(SIGPIPE, SIG_IGN); - uv_signal_t sigwinch; - uv_signal_init(loop, &sigwinch); - uv_signal_start(&sigwinch, callback_signal, SIGWINCH); + uv_signal_t sigterm; + uv_signal_init(loop, &sigterm); + uv_signal_start(&sigterm, callback_signal, SIGTERM); uv_signal_t sigint; uv_signal_init(loop, &sigint); uv_signal_start(&sigint, callback_signal, SIGINT); + open_control_socket(); + + /* we use plain poll access for the control socket, so we can + handle requests without any memory overhead. */ + uv_poll_t control_poll; + uv_poll_init(loop, &control_poll, controlsock); + + uv_poll_start(&control_poll, UV_READABLE, callback_control_socket); + uv_pipe(globallogfd, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE); uv_pipe_t log_pipe; uv_pipe_init(loop, &log_pipe, 0); @@ -486,10 +602,20 @@ main() uv_pipe_open(&log_input, globallogfd[1]); uv_read_start((uv_stream_t *)&log_pipe, fixed_log_buffer, read_log); - proc_launch(&mainproc); + load_services(); printf("nitro up at %d\n", getpid()); + for (struct process *p = process_head; p; p = p->next) { + char path[1024]; + struct stat st; + snprintf(path, sizeof path, "%s/down", p->name); + if (stat(path, &st)) + process_step(p, EVNT_WANT_DOWN); + else + process_step(p, EVNT_WANT_UP); + } + uv_run(loop, UV_RUN_DEFAULT); uv_loop_close(loop); |