From: Jaroslav Kysela Date: Sun, 16 Nov 2014 20:05:59 +0000 (+0100) Subject: spawn: do not use syslog calls in the child process X-Git-Tag: v4.1~759 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b2290d30a85281a48ca667c2eb5edceb01bdad52;p=thirdparty%2Ftvheadend.git 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. --- diff --git a/src/main.c b/src/main.c index c3fd56b46..b98fdcca9 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 f3530b342..a6748ea38 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 64e734bff..36ae3226c 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 */