|
|
|
@ -6,6 +6,7 @@
|
|
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include "sys-socket.h"
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
@ -13,6 +14,7 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
#ifdef SOCK_CLOEXEC
|
|
|
|
|
static int use_sock_cloexec;
|
|
|
|
@ -538,10 +540,24 @@ pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int fdevent_open_logger_pipe(const char *logger) {
|
|
|
|
|
/* create write pipe and spawn process */
|
|
|
|
|
typedef struct fdevent_cmd_pipe {
|
|
|
|
|
pid_t pid;
|
|
|
|
|
int fds[2];
|
|
|
|
|
const char *cmd;
|
|
|
|
|
time_t start;
|
|
|
|
|
} fdevent_cmd_pipe;
|
|
|
|
|
|
|
|
|
|
typedef struct fdevent_cmd_pipes {
|
|
|
|
|
fdevent_cmd_pipe *ptr;
|
|
|
|
|
size_t used;
|
|
|
|
|
size_t size;
|
|
|
|
|
} fdevent_cmd_pipes;
|
|
|
|
|
|
|
|
|
|
static fdevent_cmd_pipes cmd_pipes;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) {
|
|
|
|
|
char *args[4];
|
|
|
|
|
int to_log_fds[2];
|
|
|
|
|
int devnull = fdevent_open_devnull();
|
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
|
@ -549,31 +565,129 @@ static int fdevent_open_logger_pipe(const char *logger) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pipe(to_log_fds)) {
|
|
|
|
|
close(devnull);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
fdevent_setfd_cloexec(to_log_fds[0]);
|
|
|
|
|
fdevent_setfd_cloexec(to_log_fds[1]);
|
|
|
|
|
|
|
|
|
|
*(const char **)&args[0] = "/bin/sh";
|
|
|
|
|
*(const char **)&args[1] = "-c";
|
|
|
|
|
*(const char **)&args[2] = logger;
|
|
|
|
|
args[3] = NULL;
|
|
|
|
|
|
|
|
|
|
pid = fdevent_fork_execve(args[0], args, NULL, to_log_fds[0], devnull, devnull, -1);
|
|
|
|
|
pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1);
|
|
|
|
|
|
|
|
|
|
if (pid > 0) {
|
|
|
|
|
/*(future: save pipe fds, pid, and command line to restart if child exits)*/
|
|
|
|
|
close(devnull);
|
|
|
|
|
close(to_log_fds[0]);
|
|
|
|
|
return to_log_fds[1];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int errnum = errno;
|
|
|
|
|
close(devnull);
|
|
|
|
|
close(to_log_fds[0]);
|
|
|
|
|
close(to_log_fds[1]);
|
|
|
|
|
errno = errnum;
|
|
|
|
|
}
|
|
|
|
|
return pid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void fdevent_waitpid_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) {
|
|
|
|
|
pid_t pid = fcp->pid;
|
|
|
|
|
if (pid > 0) {
|
|
|
|
|
switch (waitpid(pid, NULL, WNOHANG)) {
|
|
|
|
|
case 0: return;
|
|
|
|
|
case -1: if (errno == EINTR) return; /* fall through */
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
fcp->pid = -1;
|
|
|
|
|
}
|
|
|
|
|
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
|
|
|
|
/* restart child process using existing pipe fds */
|
|
|
|
|
fcp->start = ts;
|
|
|
|
|
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd, fcp->fds[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_waitpid_logger_pipes(time_t ts) {
|
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
|
fdevent_waitpid_logger_pipe(cmd_pipes.ptr+i, ts);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_reaped_logger_pipe(pid_t pid) {
|
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
|
if (fcp->pid == pid) {
|
|
|
|
|
time_t ts = time(NULL);
|
|
|
|
|
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
|
|
|
|
fcp->start = ts;
|
|
|
|
|
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fcp->pid = -1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_close_logger_pipes(void) {
|
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
|
close(fcp->fds[0]);
|
|
|
|
|
if (fcp->fds[1] != STDERR_FILENO) close(fcp->fds[1]);
|
|
|
|
|
}
|
|
|
|
|
free(cmd_pipes.ptr);
|
|
|
|
|
cmd_pipes.ptr = NULL;
|
|
|
|
|
cmd_pipes.used = 0;
|
|
|
|
|
cmd_pipes.size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_breakagelog_logger_pipe(int fd) {
|
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
|
if (fcp->fds[1] != fd) continue;
|
|
|
|
|
fcp->fds[1] = STDERR_FILENO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void fdevent_init_logger_pipe(const char *cmd, int fds[2], pid_t pid) {
|
|
|
|
|
fdevent_cmd_pipe *fcp;
|
|
|
|
|
if (cmd_pipes.used == cmd_pipes.size) {
|
|
|
|
|
cmd_pipes.size += 4;
|
|
|
|
|
cmd_pipes.ptr =
|
|
|
|
|
realloc(cmd_pipes.ptr, cmd_pipes.size * sizeof(fdevent_cmd_pipe));
|
|
|
|
|
force_assert(cmd_pipes.ptr);
|
|
|
|
|
}
|
|
|
|
|
fcp = cmd_pipes.ptr + cmd_pipes.used++;
|
|
|
|
|
fcp->cmd = cmd; /* note: cmd must persist in memory (or else copy here) */
|
|
|
|
|
fcp->fds[0] = fds[0];
|
|
|
|
|
fcp->fds[1] = fds[1];
|
|
|
|
|
fcp->pid = pid;
|
|
|
|
|
fcp->start = time(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int fdevent_open_logger_pipe(const char *logger) {
|
|
|
|
|
int fds[2];
|
|
|
|
|
pid_t pid;
|
|
|
|
|
if (pipe(fds)) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
fdevent_setfd_cloexec(fds[0]);
|
|
|
|
|
fdevent_setfd_cloexec(fds[1]);
|
|
|
|
|
|
|
|
|
|
pid = fdevent_open_logger_pipe_spawn(logger, fds[0]);
|
|
|
|
|
|
|
|
|
|
if (pid > 0) {
|
|
|
|
|
fdevent_init_logger_pipe(logger, fds, pid);
|
|
|
|
|
return fds[1];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int errnum = errno;
|
|
|
|
|
close(fds[0]);
|
|
|
|
|
close(fds[1]);
|
|
|
|
|
errno = errnum;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|