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);