diff --git a/docs/html/config_muxes.html b/docs/html/config_muxes.html index 6aff2166..766f657a 100644 --- a/docs/html/config_muxes.html +++ b/docs/html/config_muxes.html @@ -125,5 +125,12 @@
Streaming Priority
IPTV : The mux priority value for streamed channels through HTTP or HTSP (higher value = higher priority to use services from this mux). Value 0 means use the standard streaming network priority value. +
Environment (pipe) +
IPTV : List of environment variables for pipe (like PATH=/bin:/sbin) + separated by spaces. The backslash character is handled like + in URL. + +
Respawn (pipe) +
IPTV : Respawn the executed process when it dies. diff --git a/src/epggrab/module.c b/src/epggrab/module.c index 43d2b1c8..b8554e93 100644 --- a/src/epggrab/module.c +++ b/src/epggrab/module.c @@ -287,7 +287,7 @@ char *epggrab_module_grab_spawn ( void *m ) tvhlog(LOG_INFO, mod->id, "grab %s", mod->path); /* Grab */ - outlen = spawn_and_give_stdout(mod->path, NULL, &rd, NULL, 1); + outlen = spawn_and_give_stdout(mod->path, NULL, NULL, &rd, NULL, 1); if (outlen < 0) goto error; diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index e859aa67..7c547234 100755 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -683,7 +683,7 @@ static void _xmltv_load_grabbers ( void ) char *tmp, *tmp2 = NULL, *path; /* Load data */ - if (spawn_and_give_stdout(XMLTV_FIND, NULL, &rd, NULL, 1) >= 0) + if (spawn_and_give_stdout(XMLTV_FIND, NULL, NULL, &rd, NULL, 1) >= 0) outlen = file_readall(rd, &outbuf); if (rd >= 0) close(rd); @@ -731,7 +731,7 @@ static void _xmltv_load_grabbers ( void ) if (!(st.st_mode & S_IEXEC)) continue; if (!S_ISREG(st.st_mode)) continue; rd = -1; - if (spawn_and_give_stdout(bin, argv, &rd, NULL, 1) >= 0 && + if (spawn_and_give_stdout(bin, argv, NULL, &rd, NULL, 1) >= 0 && (outlen = file_readall(rd, &outbuf)) > 0) { close(rd); if (outbuf[outlen-1] == '\n') outbuf[outlen-1] = '\0'; diff --git a/src/input/mpegts/iptv/iptv.c b/src/input/mpegts/iptv/iptv.c index 254ec727..ce36fceb 100644 --- a/src/input/mpegts/iptv/iptv.c +++ b/src/input/mpegts/iptv/iptv.c @@ -373,15 +373,11 @@ iptv_input_recv_packets ( iptv_mux_t *im, ssize_t len ) &im->mm_iptv_buffer, NULL, NULL); } -void -iptv_input_mux_started ( iptv_mux_t *im ) +int +iptv_input_fd_started ( iptv_mux_t *im ) { - tvhpoll_event_t ev = { 0 }; char buf[256]; - mpegts_mux_nice_name((mpegts_mux_t*)im, buf, sizeof(buf)); - - /* Allocate input buffer */ - sbuf_init_fixed(&im->mm_iptv_buffer, IPTV_BUF_SIZE); + tvhpoll_event_t ev = { 0 }; /* Setup poll */ if (im->mm_iptv_fd > 0) { @@ -391,12 +387,25 @@ iptv_input_mux_started ( iptv_mux_t *im ) /* Error? */ if (tvhpoll_add(iptv_poll, &ev, 1) == -1) { + mpegts_mux_nice_name((mpegts_mux_t*)im, buf, sizeof(buf)); tvherror("iptv", "%s - failed to add to poll q", buf); close(im->mm_iptv_fd); im->mm_iptv_fd = -1; - return; + return -1; } } + return 0; +} + +void +iptv_input_mux_started ( iptv_mux_t *im ) +{ + + /* Allocate input buffer */ + sbuf_init_fixed(&im->mm_iptv_buffer, IPTV_BUF_SIZE); + + if (iptv_input_fd_started(im)) + return; /* Install table handlers */ mpegts_mux_t *mm = (mpegts_mux_t*)im; diff --git a/src/input/mpegts/iptv/iptv_mux.c b/src/input/mpegts/iptv/iptv_mux.c index 6858690c..c743d7e4 100644 --- a/src/input/mpegts/iptv/iptv_mux.c +++ b/src/input/mpegts/iptv/iptv_mux.c @@ -138,6 +138,20 @@ const idclass_t iptv_mux_class = .name = "Service Name", .off = offsetof(iptv_mux_t, mm_iptv_svcname), }, + { + .type = PT_BOOL, + .id = "iptv_respawn", + .name = "Respawn (pipe)", + .off = offsetof(iptv_mux_t, mm_iptv_respawn), + .opts = PO_ADVANCED, + }, + { + .type = PT_STR, + .id = "iptv_env", + .name = "Environment (pipe)", + .off = offsetof(iptv_mux_t, mm_iptv_env), + .opts = PO_ADVANCED, + }, {} } }; diff --git a/src/input/mpegts/iptv/iptv_pipe.c b/src/input/mpegts/iptv/iptv_pipe.c index 0595eec0..15839a0e 100644 --- a/src/input/mpegts/iptv/iptv_pipe.c +++ b/src/input/mpegts/iptv/iptv_pipe.c @@ -34,7 +34,7 @@ static int iptv_pipe_start ( iptv_mux_t *im, const char *_raw, const url_t *url ) { - char *argv[64], *f, *raw, *s, *p, *a; + char *argv[64], *envp[32], *f, *raw, *s, *p, *a; int i = 1, rd; pid_t pid; @@ -82,7 +82,34 @@ iptv_pipe_start ( iptv_mux_t *im, const char *_raw, const url_t *url ) } argv[i] = NULL; - if (spawn_and_give_stdout(raw, argv, &rd, &pid, 1)) { + s = im->mm_iptv_env ? tvh_strdupa(im->mm_iptv_env) : (char *)""; + i = 0; + while (*s && i < ARRAY_SIZE(envp) - 1) { + f = s; + while (*s && *s != '=') + s++; + if (*s != '=') + break; + while (*s && *s != ' ') { + while (*s && *s != ' ' && *s != '\\') + s++; + if (*s == '\\') { + memmove(s, s + 1, strlen(s)); + if (*s) + s++; + } + } + if (f != s) { + if (*s) { + *s = '\0'; + s++; + } + envp[i++] = f; + } + } + envp[i] = NULL; + + if (spawn_and_give_stdout(raw, argv, envp, &rd, &pid, 1)) { tvherror("iptv", "Unable to start pipe '%s' (wrong executable?)", raw); return -1; } @@ -93,7 +120,10 @@ iptv_pipe_start ( iptv_mux_t *im, const char *_raw, const url_t *url ) im->mm_iptv_fd = rd; im->im_data = (void *)(intptr_t)pid; - iptv_input_mux_started(im); + im->mm_iptv_respawn_last = dispatch_clock; + + if (url) + iptv_input_mux_started(im); return 0; } @@ -126,13 +156,31 @@ iptv_pipe_read ( iptv_mux_t *im ) continue; } if (r <= 0) { - tvherror("iptv", "stdin pipe unexpectedly closed: %s", - r < 0 ? strerror(errno) : "No data"); close(rd); pid = (intptr_t)im->im_data; spawn_kill(pid, SIGKILL); im->mm_iptv_fd = -1; im->im_data = NULL; + if (dispatch_clock < im->mm_iptv_respawn_last + 2) { + tvherror("iptv", "stdin pipe unexpectedly closed: %s", + r < 0 ? strerror(errno) : "No data"); + } else { + /* avoid deadlock here */ + pthread_mutex_unlock(&iptv_lock); + pthread_mutex_lock(&global_lock); + pthread_mutex_lock(&iptv_lock); + if (im->mm_active) { + if (iptv_pipe_start(im, im->mm_iptv_url, NULL)) { + tvherror("iptv", "unable to respawn %s", im->mm_iptv_url); + } else { + iptv_input_fd_started(im); + im->mm_iptv_respawn_last = dispatch_clock; + } + } + pthread_mutex_unlock(&iptv_lock); + pthread_mutex_unlock(&global_lock); + pthread_mutex_lock(&iptv_lock); + } break; } sbuf_append(&im->mm_iptv_buffer, buf, r); diff --git a/src/input/mpegts/iptv/iptv_private.h b/src/input/mpegts/iptv/iptv_private.h index 749a4869..d7f1af3a 100644 --- a/src/input/mpegts/iptv/iptv_private.h +++ b/src/input/mpegts/iptv/iptv_private.h @@ -54,6 +54,7 @@ struct iptv_input mpegts_input_t; }; +int iptv_input_fd_started ( iptv_mux_t *im ); void iptv_input_mux_started ( iptv_mux_t *im ); void iptv_input_recv_packets ( iptv_mux_t *im, ssize_t len ); @@ -91,6 +92,10 @@ struct iptv_mux char *mm_iptv_muxname; char *mm_iptv_svcname; + int mm_iptv_respawn; + time_t mm_iptv_respawn_last; + char *mm_iptv_env; + sbuf_t mm_iptv_buffer; iptv_handler_t *im_handler; diff --git a/src/spawn.c b/src/spawn.c index ba78a9ed..7775f2c1 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -329,12 +329,14 @@ spawn_enq(const char *name, int pid) * Execute the given program and return its standard output as file-descriptor (pipe). */ int -spawn_and_give_stdout(const char *prog, char *argv[], int *rd, pid_t *pid, int redir_stderr) +spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], + int *rd, pid_t *pid, int redir_stderr) { pid_t p; - int fd[2], f, maxfd; + int fd[2], f, i, maxfd; char bin[256]; const char *local_argv[2] = { NULL, NULL }; + char **e, **e0, **e2, **e3, *p1, *p2; if (*prog != '/' && *prog != '.') { if (!find_exec(prog, bin, sizeof(bin))) return -1; @@ -344,6 +346,32 @@ spawn_and_give_stdout(const char *prog, char *argv[], int *rd, pid_t *pid, int r if (!argv) argv = (void *)local_argv; if (!argv[0]) argv[0] = (char*)prog; + if (!envp || !envp[0]) { + e = environ; + } else { + for (i = 0, e2 = environ; *e2; i++, e2++); + for (f = 0, e2 = envp; *e2; f++, e2++); + e = alloca((i + f + 1) * sizeof(char *)); + memcpy(e, environ, i * sizeof(char *)); + e0 = e + i; + *e0 = NULL; + for (e2 = envp; *e2; e2++) { + for (e3 = e; *e3; e3++) { + p1 = strchr(*e2, '='); + p2 = strchr(*e3, '='); + if (p1 - *e2 == p2 - *e3 && !strncmp(*e2, *e3, p1 - *e2)) { + *e3 = *e2; + break; + } + } + if (!*e3) { + *e0++ = *e2; + *e0 = NULL; + } + } + *e0 = NULL; + } + maxfd = sysconf(_SC_OPEN_MAX); pthread_mutex_lock(&fork_lock); @@ -387,7 +415,7 @@ spawn_and_give_stdout(const char *prog, char *argv[], int *rd, pid_t *pid, int r for (f = 3; f < maxfd; f++) close(f); - execve(prog, argv, environ); + execve(prog, argv, e); spawn_error("pid %d cannot execute %s -- %s\n", getpid(), prog, strerror(errno)); exit(1); diff --git a/src/spawn.h b/src/spawn.h index f4d5930b..e6be04af 100644 --- a/src/spawn.h +++ b/src/spawn.h @@ -25,7 +25,8 @@ void spawn_error ( const char *fmt, ... ); int find_exec ( const char *name, char *out, size_t len ); -int spawn_and_give_stdout(const char *prog, char *argv[], int *rd, pid_t *pid, int redir_stderr); +int spawn_and_give_stdout(const char *prog, char *argv[], char *envp[], + int *rd, pid_t *pid, int redir_stderr); int spawnv(const char *prog, char *argv[], pid_t *pid, int redir_stdout, int redir_stderr);