From b2290d30a85281a48ca667c2eb5edceb01bdad52 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 16 Nov 2014 21:05:59 +0100 Subject: [PATCH] spawn: do not use syslog calls in the child process The syslog routines uses private mutex so it can cause various crashes and other misbehaviour. Use pipes to send messages from the child processes. --- src/main.c | 3 ++ src/spawn.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/spawn.h | 8 ++++ 3 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index c3fd56b4..b98fdcca 100644 --- a/src/main.c +++ b/src/main.c @@ -795,6 +795,8 @@ main(int argc, char **argv) * Initialize subsystems */ + spawn_init(); + dbus_server_init(opt_dbus, opt_dbus_session); intlconv_init(); @@ -943,6 +945,7 @@ main(int argc, char **argv) tvhftrace("main", intlconv_done); tvhftrace("main", urlparse_done); tvhftrace("main", idnode_done); + tvhftrace("main", spawn_done); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); tvhlog_end(); diff --git a/src/spawn.c b/src/spawn.c index f3530b34..a6748ea3 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -43,12 +43,87 @@ pthread_mutex_t spawn_mutex = PTHREAD_MUTEX_INITIALIZER; static LIST_HEAD(, spawn) spawns; +static char *spawn_info_buf = NULL; +static char *spawn_error_buf = NULL; + +static th_pipe_t spawn_pipe_info; +static th_pipe_t spawn_pipe_error; + typedef struct spawn { LIST_ENTRY(spawn) link; pid_t pid; const char *name; } spawn_t; +/* + * + */ +#define SPAWN_PIPE_READ_SIZE 4096 + +static void +spawn_pipe_read( th_pipe_t *p, char **_buf, int level ) +{ + char *buf = *_buf, *s; + size_t len; + int r; + + if (buf == NULL) { + buf = malloc(SPAWN_PIPE_READ_SIZE); + buf[0] = '\0'; + buf[SPAWN_PIPE_READ_SIZE - 1] = 0; + *_buf = buf; + } + while (1) { + len = strlen(buf); + r = read(p->rd, buf + len, SPAWN_PIPE_READ_SIZE - 1 - len); + if (r < 1) { + if (errno == EAGAIN) + break; + if (ERRNO_AGAIN(errno)) + continue; + break; + } + while ((s = strchr(buf, '\n')) != NULL) { + *s++ = '\0'; + tvhlog(level, "spawn", "%s", buf); + memmove(buf, s, strlen(s) + 1); + } + if (strlen(buf) == SPAWN_PIPE_READ_SIZE - 1) { + tvherror("spawn", "pipe buffer full"); + buf[0] = '\0'; + } + } +} + +static void +spawn_pipe_write( th_pipe_t *p, const char *fmt, va_list ap ) +{ + char buf[512]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + write(p->wr, buf, strlen(buf)); +} + +void +spawn_info( const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + spawn_pipe_write(&spawn_pipe_info, fmt, ap); + va_end(ap); +} + +void +spawn_error( const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + spawn_pipe_write(&spawn_pipe_error, fmt, ap); + va_end(ap); +} + /* * Search PATH for executable */ @@ -93,6 +168,9 @@ spawn_reap(char *stxt, size_t stxtlen) int status, res; spawn_t *s; + spawn_pipe_read(&spawn_pipe_info, &spawn_info_buf, LOG_INFO); + spawn_pipe_read(&spawn_pipe_error, &spawn_error_buf, LOG_ERR); + pid = waitpid(-1, &status, WNOHANG); if(pid < 1) return -EAGAIN; @@ -206,9 +284,8 @@ spawn_and_store_stdout(const char *prog, char *argv[], char **outp) f = open("/dev/null", O_RDWR); if(f == -1) { - syslog(LOG_ERR, - "spawn: pid %d cannot open /dev/null for redirect %s -- %s", - getpid(), prog, strerror(errno)); + spawn_error("pid %d cannot open /dev/null for redirect %s -- %s", + getpid(), prog, strerror(errno)); exit(1); } @@ -216,9 +293,11 @@ spawn_and_store_stdout(const char *prog, char *argv[], char **outp) dup2(f, 2); close(f); + spawn_info("Executing \"%s\"\n", prog); + execve(prog, argv, environ); - syslog(LOG_ERR, "spawn: pid %d cannot execute %s -- %s", - getpid(), prog, strerror(errno)); + spawn_error("pid %d cannot execute %s -- %s\n", + getpid(), prog, strerror(errno)); exit(1); } @@ -264,10 +343,10 @@ spawnv(const char *prog, char *argv[]) if(p == 0) { close(0); close(2); - syslog(LOG_INFO, "spawn: Executing \"%s\"", prog); + spawn_info("Executing \"%s\"\n", prog); execve(prog, argv, environ); - syslog(LOG_ERR, "spawn: pid %d cannot execute %s -- %s", - getpid(), prog, strerror(errno)); + spawn_error("pid %d cannot execute %s -- %s\n", + getpid(), prog, strerror(errno)); close(1); exit(1); } @@ -275,3 +354,20 @@ spawnv(const char *prog, char *argv[]) spawn_enq(prog, p); return 0; } + +/* + * + */ +void spawn_init(void) +{ + tvh_pipe(O_NONBLOCK, &spawn_pipe_info); + tvh_pipe(O_NONBLOCK, &spawn_pipe_error); +} + +void spawn_done(void) +{ + tvh_pipe_close(&spawn_pipe_error); + tvh_pipe_close(&spawn_pipe_info); + free(spawn_error_buf); + free(spawn_info_buf); +} diff --git a/src/spawn.h b/src/spawn.h index 64e734bf..36ae3226 100644 --- a/src/spawn.h +++ b/src/spawn.h @@ -19,6 +19,10 @@ #ifndef SPAWN_H #define SPAWN_H +void spawn_info ( const char *fmt, ... ); + +void spawn_error ( const char *fmt, ... ); + int find_exec ( const char *name, char *out, size_t len ); int spawn_and_store_stdout(const char *prog, char *argv[], char **outp); @@ -29,4 +33,8 @@ int spawn_reap(char *stxt, size_t stxtlen); void spawn_reaper(void); +void spawn_init(void); + +void spawn_done(void); + #endif /* SPAWN_H */