--- /dev/null
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "supervisor.h"
+#include "utils/log_utils.h"
+#include "utils/sys_utils.h"
+#include <stdio.h>
+#include <assert.h>
+
+#include "core/framework.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+typedef struct {
+ char *name;
+ char *path;
+ char **args;
+ bool nomanual;
+ bool autorestart;
+ char *stdout_path;
+ char *stderr_path;
+
+ pid_t pid;
+ int running;
+} supervisor_control_block_t;
+
+static void supervisor_spawn(supervisor_control_block_t *scb);
+static void supervisor_free_scb(int count, supervisor_control_block_t *scb);
+static void supervisor_on_signal(int signo);
+
+static volatile sig_atomic_t supervisor_got_signal_stop = 0;
+static bool nts_manual;
+
+int supervisor_run(void) {
+ int scb_count = framework_config.supervisor.rules_count;
+ supervisor_control_block_t *scb = (supervisor_control_block_t*)malloc(sizeof(supervisor_control_block_t) * framework_config.supervisor.rules_count);
+ if(scb == 0) {
+ log_error("malloc failed\n");
+ return NTS_ERR_FAILED;
+ }
+
+ for(int i = 0; i < scb_count; i++) {
+ scb[i].name = strdup(framework_config.supervisor.rules[i].name);
+ scb[i].path = strdup(framework_config.supervisor.rules[i].path);
+ scb[i].args = malloc(sizeof(char *) * (framework_config.supervisor.rules[i].args_count + 2));
+ scb[i].args[0] = strdup(framework_config.supervisor.rules[i].path);
+ for(int j = 0; j < framework_config.supervisor.rules[i].args_count; j++) {
+ scb[i].args[j + 1] = strdup(framework_config.supervisor.rules[i].args[j]);
+ }
+ scb[i].args[framework_config.supervisor.rules[i].args_count + 1] = 0;
+ scb[i].autorestart = framework_config.supervisor.rules[i].autorestart;
+ scb[i].nomanual = framework_config.supervisor.rules[i].nomanual;
+ scb[i].stdout_path = framework_config.supervisor.rules[i].stdout_path ? strdup(framework_config.supervisor.rules[i].stdout_path) : 0;
+ scb[i].stderr_path = framework_config.supervisor.rules[i].stderr_path ? strdup(framework_config.supervisor.rules[i].stderr_path) : 0;
+ scb[i].pid = 0;
+ scb[i].running = 0;
+ }
+
+ nts_manual = framework_environment.nts.manual;
+
+ signal(SIGINT, supervisor_on_signal);
+ signal(SIGTERM, supervisor_on_signal);
+ signal(SIGQUIT, supervisor_on_signal);
+
+ for(int i = 0; i < scb_count; i++) {
+ supervisor_spawn(&scb[i]);
+ log_add_verbose(1, "[supervisor] spawning %s... with pid %lu\n", scb[i].name, scb[i].pid);
+ }
+
+ int running = 1;
+ while(running) {
+ int defunct_status;
+ pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
+ if(defunct_pid > 0) {
+ for(int i = 0; i < scb_count; i++) {
+ if(scb[i].pid == defunct_pid) {
+ log_add_verbose(1, "[supervisor] process %s (pid=%lu) exited with status %d\n", scb[i].name, defunct_pid, defunct_status);
+ scb[i].running = 0;
+ if(scb[i].autorestart) {
+ supervisor_spawn(&scb[i]);
+ log_add_verbose(1, "[supervisor] respawned %s (pid=%lu)\n", scb[i].name, scb[i].pid);
+ }
+ }
+ }
+ }
+
+ if(supervisor_got_signal_stop) {
+ for(int i = 0; i < scb_count; i++) {
+ if(scb[i].running) {
+ log_add_verbose(1, "[supervisor] sending %d to %s (pid=%lu)...\n", supervisor_got_signal_stop, scb[i].name, scb[i].pid);
+ kill(scb[i].pid, supervisor_got_signal_stop);
+ }
+ }
+ supervisor_got_signal_stop = 0;
+ running = 0;
+ }
+
+ sleep(1);
+ }
+
+ //after SIGTERM was forwarded
+ running = 1;
+ while(running) {
+ int defunct_status;
+ pid_t defunct_pid = waitpid(-1, &defunct_status, WNOHANG);
+ if(defunct_pid > 0) {
+ char *name = 0;
+ for(int i = 0; i < scb_count; i++) {
+ if(scb[i].pid == defunct_pid) {
+ scb[i].running = 0;
+ name = scb[i].name;
+ }
+ }
+ log_add_verbose(1, "[supervisor] process %s (pid=%d) exited with status %d\n", name, defunct_pid, defunct_status);
+ }
+
+ running = 0;
+ for(int i = 0; i < scb_count; i++) {
+ if(scb[i].running == 1) {
+ running = 1;
+ }
+ }
+ }
+
+ supervisor_free_scb(scb_count, scb);
+ framework_free();
+
+ return NTS_ERR_OK;
+}
+
+static void supervisor_spawn(supervisor_control_block_t *scb) {
+ if(nts_manual && scb->nomanual) {
+ return;
+ }
+
+ scb->running = 1;
+ scb->pid = fork();
+ if(scb->pid == -1) {
+ log_error("fork() failed\n");
+ return;
+ }
+
+ if(scb->pid == 0) {
+ //child process
+ int stdout_fd = 0;
+ int stderr_fd = 0;
+
+ signal(SIGINT, 0);
+ signal(SIGTERM, 0);
+ signal(SIGQUIT, 0);
+ framework_free();
+ setsid();
+
+ if(scb->stdout_path) {
+ if(scb->stdout_path[0] == 0) {
+ free(scb->stdout_path);
+ scb->stdout_path = strdup("/dev/null");
+ }
+ stdout_fd = open(scb->stdout_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ dup2(stdout_fd, STDOUT_FILENO);
+ }
+
+ if(scb->stderr_path) {
+ if(scb->stderr_path[0] == 0) {
+ free(scb->stderr_path);
+ scb->stderr_path = strdup("/dev/null");
+ }
+ stderr_fd = open(scb->stderr_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ dup2(stderr_fd, STDERR_FILENO);
+ }
+
+ execv(scb->path, scb->args);
+ _exit(0);
+ }
+}
+
+static void supervisor_free_scb(int count, supervisor_control_block_t *scb) {
+ for(int i = 0; i < count; i++) {
+ free(scb[i].name);
+ free(scb[i].path);
+ int j = 0;
+ while(scb[i].args[j]) {
+ free(scb[i].args[j]);
+ j++;
+ }
+ free(scb[i].args);
+ free(scb[i].stdout_path);
+ free(scb[i].stderr_path);
+ }
+
+ free(scb);
+}
+
+static void supervisor_on_signal(int signo) {
+ supervisor_got_signal_stop = signo;
+}