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.
This commit is contained in:
parent
0bb2356a5f
commit
b2290d30a8
3 changed files with 115 additions and 8 deletions
|
@ -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();
|
||||
|
|
112
src/spawn.c
112
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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue