supervise.c (5521B)
1 #include "config.h" 2 #include "service.h" 3 #include "util.h" 4 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <limits.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/socket.h> 12 #include <sys/stat.h> 13 #include <sys/un.h> 14 #include <sys/wait.h> 15 #include <unistd.h> 16 17 18 bool daemon_running = true; 19 20 static void signal_child(int unused) { 21 (void) unused; 22 23 int status; 24 pid_t died_pid; 25 service_t* s = NULL; 26 27 if ((died_pid = wait(&status)) == -1) { 28 print_error("error: cannot wait for process: %s\n"); 29 return; 30 } 31 32 if (!WIFEXITED(status) && !WIFSIGNALED(status)) 33 return; 34 35 for (int i = 0; i < services_size; i++) { 36 if (services[i].pid == died_pid) { 37 s = &services[i]; 38 break; 39 } 40 } 41 if (s == NULL) 42 return; 43 44 service_handle_exit(s, WIFSIGNALED(status), WIFSIGNALED(status) ? WTERMSIG(status) : WEXITSTATUS(status)); 45 } 46 47 static void check_deaths(void) { 48 service_t* s; 49 for (int i = 0; i < services_size; i++) { 50 s = &services[i]; 51 if (s->state == STATE_ACTIVE_PID) { 52 if (kill(s->pid, 0) == -1 && errno == ESRCH) 53 service_handle_exit(s, false, 0); 54 } 55 } 56 } 57 58 static void check_services(void) { 59 service_t* s; 60 for (int i = 0; i < services_size; i++) { 61 s = &services[i]; 62 if (s->state == STATE_DEAD) 63 continue; 64 if (service_need_restart(s)) { 65 if (s->state == STATE_INACTIVE) { 66 service_start(s, NULL); 67 s->status_change = time(NULL); 68 service_update_status(s); 69 } 70 } else { 71 if (s->state != STATE_INACTIVE) { 72 service_stop(s, NULL); 73 s->status_change = time(NULL); 74 service_update_status(s); 75 } 76 } 77 } 78 } 79 80 static void accept_socket(void) { 81 int client_fd; 82 if ((client_fd = accept(control_socket, NULL, NULL)) == -1) { 83 if (errno == EWOULDBLOCK) { 84 sleep(SV_ACCEPT_INTERVAL); 85 } else { 86 print_error("error: cannot accept client from control-socket: %s\n"); 87 } 88 } else { 89 service_handle_client(client_fd); 90 } 91 } 92 93 static void control_sockets(void) { 94 #if SV_RUNIT_COMPAT != 0 95 service_t* s; 96 char cmd; 97 for (int i = 0; i < services_size; i++) { 98 s = &services[i]; 99 100 while (recv(s->control, &cmd, 1, MSG_DONTWAIT) == 1) { 101 service_handle_command_runit(s, cmd); 102 } 103 } 104 #endif 105 } 106 107 int service_supervise(const char* service_dir_, const char* runlevel_, bool force_socket) { 108 struct sigaction sigact = { 0 }; 109 sigact.sa_handler = signal_child; 110 sigaction(SIGCHLD, &sigact, NULL); 111 sigact.sa_handler = SIG_IGN; 112 sigaction(SIGPIPE, &sigact, NULL); 113 114 strncpy(runlevel, runlevel_, SV_NAME_MAX); 115 service_dir_path = service_dir_; 116 if ((service_dir = open(service_dir_, O_DIRECTORY)) == -1) { 117 print_error("error: cannot open directory %s: %s\n", service_dir_); 118 return 1; 119 } 120 121 // setenv("SERVICE_RUNLEVEL", runlevel, true); 122 123 umask(0002); 124 125 char socket_path[PATH_MAX]; 126 snprintf(socket_path, PATH_MAX, SV_CONTROL_SOCKET, runlevel); 127 128 if ((null_fd = open("/dev/null", O_RDWR)) == -1) { 129 print_error("error: cannot open /dev/null: %s\n"); 130 null_fd = 1; 131 } 132 133 struct stat socket_stat; 134 if (force_socket) { 135 if (unlink(socket_path) == -1 && errno != ENOENT) { 136 print_error("error: cannot unlink socket: %s\n"); 137 } 138 } else if (stat(socket_path, &socket_stat) != -1 && S_ISREG(socket_stat.st_mode)) { 139 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); 140 return 1; 141 } 142 // create socket 143 if ((control_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 144 print_error("error: cannot create socket: %s\n"); 145 return 1; 146 } 147 148 // bind socket to address 149 struct sockaddr_un addr = { 0 }; 150 addr.sun_family = AF_UNIX; 151 strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); 152 if (bind(control_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) { 153 print_error("error: cannot bind %s to socket: %s\n", socket_path); 154 return 1; 155 } 156 157 // listen for connections 158 if (listen(control_socket, 5) == -1) { 159 print_error("error: cannot listen to control socket: %s\n"); 160 return 1; 161 } 162 163 int sockflags = fcntl(control_socket, F_GETFL, 0); 164 if (sockflags == -1) { 165 print_error("warn: fcntl-getflags on control-socket failed: %s\n"); 166 } else if (fcntl(control_socket, F_SETFL, sockflags | O_NONBLOCK) == -1) { 167 print_error("warn: fcntl-setflags on control-socket failed: %s\n"); 168 } 169 170 printf(":: starting services on '%s'\n", runlevel); 171 172 if (service_refresh_directory() < 0) 173 return 1; 174 175 printf(":: started services\n"); 176 177 // accept connections and handle requests 178 while (daemon_running) { 179 check_deaths(); 180 service_refresh_directory(); 181 check_services(); 182 control_sockets(); 183 accept_socket(); 184 } 185 186 close(control_socket); 187 188 if (unlink(socket_path) == -1 && errno != ENOENT) { 189 print_error("error: cannot unlink socket: %s\n"); 190 } 191 192 printf(":: terminating\n"); 193 194 service_t* s; 195 for (int i = 0; i < services_size; i++) { 196 s = &services[i]; 197 service_stop(s, NULL); 198 } 199 200 time_t start = time(NULL); 201 int running; 202 do { 203 sleep(1); // sleep for one second 204 running = 0; 205 for (int i = 0; i < services_size; i++) { 206 if (services[i].state != STATE_INACTIVE) 207 running++; 208 } 209 printf(":: %d running...\r", running); 210 } while (running > 0 && (time(NULL) - start) < SV_STOP_TIMEOUT); 211 212 printf("\n"); 213 214 for (int i = 0; i < services_size; i++) { 215 if (services[i].pid) { 216 printf(":: killing %s\n", services[i].name); 217 service_kill(&services[i], SIGKILL); 218 } 219 } 220 221 printf(":: all services stopped\n"); 222 223 signal(SIGPIPE, SIG_DFL); 224 signal(SIGCHLD, SIG_DFL); 225 signal(SIGINT, SIG_DFL); 226 signal(SIGCONT, SIG_DFL); 227 return 0; 228 }