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);
51 static volatile sig_atomic_t supervisor_got_signal_stop = 0;
52 static bool nts_manual;
54 int supervisor_run(void) {
55 int scb_count = framework_config.supervisor.rules_count;
56 supervisor_control_block_t *scb = (supervisor_control_block_t*)malloc(sizeof(supervisor_control_block_t) * framework_config.supervisor.rules_count);
58 log_error("malloc failed\n");
59 return NTS_ERR_FAILED;
62 for(int i = 0; i < scb_count; i++) {
63 scb[i].name = strdup(framework_config.supervisor.rules[i].name);
64 scb[i].path = strdup(framework_config.supervisor.rules[i].path);
65 scb[i].args = malloc(sizeof(char *) * (framework_config.supervisor.rules[i].args_count + 2));
66 scb[i].args[0] = strdup(framework_config.supervisor.rules[i].path);
67 for(int j = 0; j < framework_config.supervisor.rules[i].args_count; j++) {
68 scb[i].args[j + 1] = strdup(framework_config.supervisor.rules[i].args[j]);
70 scb[i].args[framework_config.supervisor.rules[i].args_count + 1] = 0;
71 scb[i].autorestart = framework_config.supervisor.rules[i].autorestart;
72 scb[i].nomanual = framework_config.supervisor.rules[i].nomanual;
73 scb[i].stdout_path = framework_config.supervisor.rules[i].stdout_path ? strdup(framework_config.supervisor.rules[i].stdout_path) : 0;
74 scb[i].stderr_path = framework_config.supervisor.rules[i].stderr_path ? strdup(framework_config.supervisor.rules[i].stderr_path) : 0;
79 nts_manual = framework_environment.nts.manual;
81 signal(SIGINT, supervisor_on_signal);
82 signal(SIGTERM, supervisor_on_signal);
83 signal(SIGQUIT, supervisor_on_signal);
85 for(int i = 0; i < scb_count; i++) {
86 supervisor_spawn(&scb[i]);
87 log_add_verbose(1, "[supervisor] spawning %s... with pid %lu\n", scb[i].name, scb[i].pid);
93 pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
95 for(int i = 0; i < scb_count; i++) {
96 if(scb[i].pid == defunct_pid) {
97 log_add_verbose(1, "[supervisor] process %s (pid=%lu) exited with status %d\n", scb[i].name, defunct_pid, defunct_status);
99 if(scb[i].autorestart) {
100 supervisor_spawn(&scb[i]);
101 log_add_verbose(1, "[supervisor] respawned %s (pid=%lu)\n", scb[i].name, scb[i].pid);
107 if(supervisor_got_signal_stop) {
108 for(int i = 0; i < scb_count; i++) {
110 log_add_verbose(1, "[supervisor] sending %d to %s (pid=%lu)...\n", supervisor_got_signal_stop, scb[i].name, scb[i].pid);
111 kill(scb[i].pid, supervisor_got_signal_stop);
114 supervisor_got_signal_stop = 0;
121 //after SIGTERM was forwarded
125 pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
126 if(defunct_pid > 0) {
128 for(int i = 0; i < scb_count; i++) {
129 if(scb[i].pid == defunct_pid) {
134 log_add_verbose(1, "[supervisor] process %s (pid=%d) exited with status %d\n", name, defunct_pid, defunct_status);
138 for(int i = 0; i < scb_count; i++) {
139 if(scb[i].running == 1) {
145 supervisor_free_scb(scb_count, scb);
151 static void supervisor_spawn(supervisor_control_block_t *scb) {
152 if(nts_manual && scb->nomanual) {
159 log_error("fork() failed\n");
174 if(scb->stdout_path) {
175 if(scb->stdout_path[0] == 0) {
176 free(scb->stdout_path);
177 scb->stdout_path = strdup("/dev/null");
179 stdout_fd = open(scb->stdout_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
180 dup2(stdout_fd, STDOUT_FILENO);
183 if(scb->stderr_path) {
184 if(scb->stderr_path[0] == 0) {
185 free(scb->stderr_path);
186 scb->stderr_path = strdup("/dev/null");
188 stderr_fd = open(scb->stderr_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
189 dup2(stderr_fd, STDERR_FILENO);
192 execv(scb->path, scb->args);
197 static void supervisor_free_scb(int count, supervisor_control_block_t *scb) {
198 for(int i = 0; i < count; i++) {
202 while(scb[i].args[j]) {
203 free(scb[i].args[j]);
207 free(scb[i].stdout_path);
208 free(scb[i].stderr_path);
214 static void supervisor_on_signal(int signo) {
215 supervisor_got_signal_stop = signo;