start.c (3073B) download
1#include "service.h"
2
3#include <errno.h>
4#include <fcntl.h>
5#include <grp.h>
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13
14static void set_pipes(struct service* s) {
15 if (s->is_log_service) {
16 close(s->log_pipe.write);
17 dup2(s->log_pipe.read, STDIN_FILENO);
18 close(s->log_pipe.read);
19 dup2(null_fd, STDOUT_FILENO);
20 dup2(null_fd, STDERR_FILENO);
21 } else if (s->log_service) { // aka has_log_service
22 close(s->log_service->log_pipe.read);
23 dup2(s->log_service->log_pipe.write, STDOUT_FILENO);
24 dup2(s->log_service->log_pipe.write, STDERR_FILENO);
25 close(s->log_service->log_pipe.write);
26 dup2(null_fd, STDIN_FILENO);
27 } else if (stat_mode("log") & S_IWRITE) { // is not
28 int log_fd;
29 if ((log_fd = open("log", O_WRONLY | O_TRUNC)) == -1)
30 log_fd = null_fd;
31
32 dup2(null_fd, STDIN_FILENO);
33 dup2(log_fd, STDOUT_FILENO);
34 dup2(log_fd, STDERR_FILENO);
35 } else if (S_ISREG(stat_mode("nolog"))) {
36 dup2(null_fd, STDIN_FILENO);
37 dup2(null_fd, STDOUT_FILENO);
38 dup2(null_fd, STDERR_FILENO);
39 } else {
40 char service_log[PATH_MAX];
41 int log_fd;
42
43 snprintf(service_log, PATH_MAX, "%s/%s.log", SV_LOG_DIR, s->name);
44
45 if ((log_fd = open(service_log, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1)
46 log_fd = null_fd;
47
48 dup2(null_fd, STDIN_FILENO);
49 dup2(log_fd, STDOUT_FILENO);
50 dup2(log_fd, STDERR_FILENO);
51 }
52}
53
54void service_run(struct service* s) {
55 struct stat st;
56
57 if (fstatat(s->dir, "run", &st, 0) != -1 && st.st_mode & S_IXUSR) {
58 service_update_state(s, STATE_ACTIVE_FOREGROUND);
59 } else if (fstatat(s->dir, "start", &st, 0) != -1 && st.st_mode & S_IXUSR) {
60 service_update_state(s, STATE_STARTING);
61 } else if (fstatat(s->dir, "depends", &st, 0) != -1 && st.st_mode & S_IREAD) {
62 service_update_state(s, STATE_ACTIVE_DUMMY);
63 } else {
64 // fprint(1, "warn: %s: `run`, `start` or `depends` not found\n", s->name);
65 service_update_state(s, STATE_INACTIVE);
66 }
67
68 if (s->state != STATE_ACTIVE_DUMMY) {
69 if ((s->pid = fork()) == -1) {
70 fprint(1, "error: cannot fork process: %r\n");
71 exit(1);
72 } else if (s->pid == 0) { // child
73 if (setsid() == -1)
74 fprint(1, "error: cannot setsid: %r\n");
75
76 fchdir(s->dir);
77 set_pipes(s);
78
79 if (s->state == STATE_STARTING) {
80 execl("./start", "./start", NULL);
81 } else {
82 execl("./run", "./run", NULL);
83 }
84 fprint(1, "error: cannot execute service: %r\n");
85 _exit(1);
86 }
87 }
88}
89
90void service_start(struct service* s) {
91 struct stat st;
92
93 if (!daemon_running || s->state != STATE_INACTIVE)
94 return;
95
96 print("starting %s\n", s->name);
97 for (int i = 0; i < s->children_size; i++) {
98 service_start(s->children[i]);
99 }
100
101 if (fstatat(s->dir, "setup", &st, 0) != -1 && st.st_mode & S_IXUSR) {
102 if ((s->pid = fork_dup_cd_exec(s->dir, "./setup", null_fd, null_fd, null_fd)) == -1) {
103 fprint(1, "error: cannot execute ./setup: %r\n");
104 service_update_state(s, STATE_INACTIVE);
105 } else {
106 service_update_state(s, STATE_SETUP);
107 }
108 } else {
109 service_run(s);
110 }
111 print("started %s \n", s->name);
112}