1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
20 #include "supervisor.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
26 #include "core/framework.h"
27 #include <sys/types.h>
29 #include <sys/types.h>
45 } supervisor_control_block_t;
47 static void supervisor_spawn(supervisor_control_block_t *scb);
48 static void supervisor_free_scb(int count, supervisor_control_block_t *scb);
49 static void supervisor_on_signal(int signo);
50 static void supervisor_on_sigusr(int signo);
52 static volatile sig_atomic_t supervisor_got_signal_stop = 0;
53 static volatile sig_atomic_t supervisor_got_signal_reload = 0;
54 static bool nts_manual;
56 int supervisor_run(int argc, char **argv) {
58 if(file_exists("/opt/dev/deploy/.env")) {
64 fp = fopen("/opt/dev/deploy/.env", "r");
66 log_add_verbose(1, "[supervisor] found /opt/dev/deploy/.env\n");
68 while ((read = getline(&line, &len, fp)) != -1) {
69 if(line[strlen(line) - 1] == '\n') {
70 line[strlen(line) - 1] = 0;
73 log_add_verbose(1, "[supervisor] adding .env var: %s\n", line);
82 supervisor_got_signal_reload = 0;
83 supervisor_got_signal_stop = 0;
85 int scb_count = framework_config.supervisor.rules_count;
86 supervisor_control_block_t *scb = (supervisor_control_block_t*)malloc(sizeof(supervisor_control_block_t) * framework_config.supervisor.rules_count);
88 log_error("malloc failed\n");
89 return NTS_ERR_FAILED;
92 for(int i = 0; i < scb_count; i++) {
93 scb[i].name = strdup(framework_config.supervisor.rules[i].name);
94 scb[i].path = strdup(framework_config.supervisor.rules[i].path);
95 scb[i].args = malloc(sizeof(char *) * (framework_config.supervisor.rules[i].args_count + 2));
96 scb[i].args[0] = strdup(framework_config.supervisor.rules[i].path);
97 for(int j = 0; j < framework_config.supervisor.rules[i].args_count; j++) {
98 scb[i].args[j + 1] = strdup(framework_config.supervisor.rules[i].args[j]);
100 scb[i].args[framework_config.supervisor.rules[i].args_count + 1] = 0;
101 scb[i].autorestart = framework_config.supervisor.rules[i].autorestart;
102 scb[i].nomanual = framework_config.supervisor.rules[i].nomanual;
103 scb[i].stdout_path = framework_config.supervisor.rules[i].stdout_path ? strdup(framework_config.supervisor.rules[i].stdout_path) : 0;
104 scb[i].stderr_path = framework_config.supervisor.rules[i].stderr_path ? strdup(framework_config.supervisor.rules[i].stderr_path) : 0;
109 nts_manual = framework_environment.nts.manual;
111 signal(SIGINT, supervisor_on_signal);
112 signal(SIGTERM, supervisor_on_signal);
113 signal(SIGQUIT, supervisor_on_signal);
114 signal(SIGUSR1, supervisor_on_sigusr);
116 for(int i = 0; i < scb_count; i++) {
117 supervisor_spawn(&scb[i]);
118 log_add_verbose(1, "[supervisor] spawning %s... with pid %lu\n", scb[i].name, scb[i].pid);
124 pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
125 if(defunct_pid > 0) {
126 for(int i = 0; i < scb_count; i++) {
127 if(scb[i].pid == defunct_pid) {
128 log_add_verbose(1, "[supervisor] process %s (pid=%lu) exited with status %d\n", scb[i].name, defunct_pid, defunct_status);
130 if(scb[i].autorestart) {
131 supervisor_spawn(&scb[i]);
132 log_add_verbose(1, "[supervisor] respawned %s (pid=%lu)\n", scb[i].name, scb[i].pid);
138 if(supervisor_got_signal_stop) {
139 for(int i = 0; i < scb_count; i++) {
141 log_add_verbose(1, "[supervisor] sending %d to %s (pid=%lu)...\n", supervisor_got_signal_stop, scb[i].name, scb[i].pid);
142 kill(scb[i].pid, supervisor_got_signal_stop);
145 supervisor_got_signal_stop = 0;
152 //after SIGTERM was forwarded
156 pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
157 if(defunct_pid > 0) {
159 for(int i = 0; i < scb_count; i++) {
160 if(scb[i].pid == defunct_pid) {
165 log_add_verbose(1, "[supervisor] process %s (pid=%d) exited with status %d\n", name, defunct_pid, defunct_status);
169 for(int i = 0; i < scb_count; i++) {
170 if(scb[i].running == 1) {
176 supervisor_free_scb(scb_count, scb);
179 if(supervisor_got_signal_reload) {
180 if(framework_init(argc, argv) != NTS_ERR_OK) {
181 log_error(LOG_COLOR_BOLD_RED"framework_init() error\n");
186 log_add_verbose(1, "[supervisor] SIGUSR1 received, restarting everything... (this is a *new* logfile)\n");
188 goto supervisor_start;
194 static void supervisor_spawn(supervisor_control_block_t *scb) {
195 if(nts_manual && scb->nomanual) {
202 log_error("fork() failed\n");
217 if(scb->stdout_path) {
218 if(scb->stdout_path[0] == 0) {
219 free(scb->stdout_path);
220 scb->stdout_path = strdup("/dev/null");
222 stdout_fd = open(scb->stdout_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
223 dup2(stdout_fd, STDOUT_FILENO);
226 if(scb->stderr_path) {
227 if(scb->stderr_path[0] == 0) {
228 free(scb->stderr_path);
229 scb->stderr_path = strdup("/dev/null");
231 stderr_fd = open(scb->stderr_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
232 dup2(stderr_fd, STDERR_FILENO);
235 execv(scb->path, scb->args);
240 static void supervisor_free_scb(int count, supervisor_control_block_t *scb) {
241 for(int i = 0; i < count; i++) {
245 while(scb[i].args[j]) {
246 free(scb[i].args[j]);
250 free(scb[i].stdout_path);
251 free(scb[i].stderr_path);
257 static void supervisor_on_signal(int signo) {
258 supervisor_got_signal_stop = signo;
261 static void supervisor_on_sigusr(int signo) {
262 supervisor_got_signal_stop = SIGTERM;
263 supervisor_got_signal_reload = 1;