IPTV: pipe - add respawn option and environment option
This commit is contained in:
parent
68b07236d0
commit
98854eaacd
9 changed files with 132 additions and 20 deletions
|
@ -125,5 +125,12 @@
|
||||||
<dt>Streaming Priority
|
<dt>Streaming Priority
|
||||||
<dd>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.
|
<dd>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.
|
||||||
|
|
||||||
|
<dt>Environment (pipe)
|
||||||
|
<dd>IPTV : List of environment variables for pipe (like PATH=/bin:/sbin)
|
||||||
|
separated by spaces. The backslash character is handled like
|
||||||
|
in URL.
|
||||||
|
|
||||||
|
<dt>Respawn (pipe)
|
||||||
|
<dd>IPTV : Respawn the executed process when it dies.
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -287,7 +287,7 @@ char *epggrab_module_grab_spawn ( void *m )
|
||||||
tvhlog(LOG_INFO, mod->id, "grab %s", mod->path);
|
tvhlog(LOG_INFO, mod->id, "grab %s", mod->path);
|
||||||
|
|
||||||
/* Grab */
|
/* 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)
|
if (outlen < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -683,7 +683,7 @@ static void _xmltv_load_grabbers ( void )
|
||||||
char *tmp, *tmp2 = NULL, *path;
|
char *tmp, *tmp2 = NULL, *path;
|
||||||
|
|
||||||
/* Load data */
|
/* 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);
|
outlen = file_readall(rd, &outbuf);
|
||||||
if (rd >= 0)
|
if (rd >= 0)
|
||||||
close(rd);
|
close(rd);
|
||||||
|
@ -731,7 +731,7 @@ static void _xmltv_load_grabbers ( void )
|
||||||
if (!(st.st_mode & S_IEXEC)) continue;
|
if (!(st.st_mode & S_IEXEC)) continue;
|
||||||
if (!S_ISREG(st.st_mode)) continue;
|
if (!S_ISREG(st.st_mode)) continue;
|
||||||
rd = -1;
|
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) {
|
(outlen = file_readall(rd, &outbuf)) > 0) {
|
||||||
close(rd);
|
close(rd);
|
||||||
if (outbuf[outlen-1] == '\n') outbuf[outlen-1] = '\0';
|
if (outbuf[outlen-1] == '\n') outbuf[outlen-1] = '\0';
|
||||||
|
|
|
@ -373,15 +373,11 @@ iptv_input_recv_packets ( iptv_mux_t *im, ssize_t len )
|
||||||
&im->mm_iptv_buffer, NULL, NULL);
|
&im->mm_iptv_buffer, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
iptv_input_mux_started ( iptv_mux_t *im )
|
iptv_input_fd_started ( iptv_mux_t *im )
|
||||||
{
|
{
|
||||||
tvhpoll_event_t ev = { 0 };
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
mpegts_mux_nice_name((mpegts_mux_t*)im, buf, sizeof(buf));
|
tvhpoll_event_t ev = { 0 };
|
||||||
|
|
||||||
/* Allocate input buffer */
|
|
||||||
sbuf_init_fixed(&im->mm_iptv_buffer, IPTV_BUF_SIZE);
|
|
||||||
|
|
||||||
/* Setup poll */
|
/* Setup poll */
|
||||||
if (im->mm_iptv_fd > 0) {
|
if (im->mm_iptv_fd > 0) {
|
||||||
|
@ -391,12 +387,25 @@ iptv_input_mux_started ( iptv_mux_t *im )
|
||||||
|
|
||||||
/* Error? */
|
/* Error? */
|
||||||
if (tvhpoll_add(iptv_poll, &ev, 1) == -1) {
|
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);
|
tvherror("iptv", "%s - failed to add to poll q", buf);
|
||||||
close(im->mm_iptv_fd);
|
close(im->mm_iptv_fd);
|
||||||
im->mm_iptv_fd = -1;
|
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 */
|
/* Install table handlers */
|
||||||
mpegts_mux_t *mm = (mpegts_mux_t*)im;
|
mpegts_mux_t *mm = (mpegts_mux_t*)im;
|
||||||
|
|
|
@ -138,6 +138,20 @@ const idclass_t iptv_mux_class =
|
||||||
.name = "Service Name",
|
.name = "Service Name",
|
||||||
.off = offsetof(iptv_mux_t, mm_iptv_svcname),
|
.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,
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
static int
|
static int
|
||||||
iptv_pipe_start ( iptv_mux_t *im, const char *_raw, const url_t *url )
|
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;
|
int i = 1, rd;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
@ -82,7 +82,34 @@ iptv_pipe_start ( iptv_mux_t *im, const char *_raw, const url_t *url )
|
||||||
}
|
}
|
||||||
argv[i] = NULL;
|
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);
|
tvherror("iptv", "Unable to start pipe '%s' (wrong executable?)", raw);
|
||||||
return -1;
|
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->mm_iptv_fd = rd;
|
||||||
im->im_data = (void *)(intptr_t)pid;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,13 +156,31 @@ iptv_pipe_read ( iptv_mux_t *im )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
tvherror("iptv", "stdin pipe unexpectedly closed: %s",
|
|
||||||
r < 0 ? strerror(errno) : "No data");
|
|
||||||
close(rd);
|
close(rd);
|
||||||
pid = (intptr_t)im->im_data;
|
pid = (intptr_t)im->im_data;
|
||||||
spawn_kill(pid, SIGKILL);
|
spawn_kill(pid, SIGKILL);
|
||||||
im->mm_iptv_fd = -1;
|
im->mm_iptv_fd = -1;
|
||||||
im->im_data = NULL;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
sbuf_append(&im->mm_iptv_buffer, buf, r);
|
sbuf_append(&im->mm_iptv_buffer, buf, r);
|
||||||
|
|
|
@ -54,6 +54,7 @@ struct iptv_input
|
||||||
mpegts_input_t;
|
mpegts_input_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int iptv_input_fd_started ( iptv_mux_t *im );
|
||||||
void iptv_input_mux_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 );
|
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_muxname;
|
||||||
char *mm_iptv_svcname;
|
char *mm_iptv_svcname;
|
||||||
|
|
||||||
|
int mm_iptv_respawn;
|
||||||
|
time_t mm_iptv_respawn_last;
|
||||||
|
char *mm_iptv_env;
|
||||||
|
|
||||||
sbuf_t mm_iptv_buffer;
|
sbuf_t mm_iptv_buffer;
|
||||||
|
|
||||||
iptv_handler_t *im_handler;
|
iptv_handler_t *im_handler;
|
||||||
|
|
34
src/spawn.c
34
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).
|
* Execute the given program and return its standard output as file-descriptor (pipe).
|
||||||
*/
|
*/
|
||||||
int
|
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;
|
pid_t p;
|
||||||
int fd[2], f, maxfd;
|
int fd[2], f, i, maxfd;
|
||||||
char bin[256];
|
char bin[256];
|
||||||
const char *local_argv[2] = { NULL, NULL };
|
const char *local_argv[2] = { NULL, NULL };
|
||||||
|
char **e, **e0, **e2, **e3, *p1, *p2;
|
||||||
|
|
||||||
if (*prog != '/' && *prog != '.') {
|
if (*prog != '/' && *prog != '.') {
|
||||||
if (!find_exec(prog, bin, sizeof(bin))) return -1;
|
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) argv = (void *)local_argv;
|
||||||
if (!argv[0]) argv[0] = (char*)prog;
|
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);
|
maxfd = sysconf(_SC_OPEN_MAX);
|
||||||
|
|
||||||
pthread_mutex_lock(&fork_lock);
|
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++)
|
for (f = 3; f < maxfd; f++)
|
||||||
close(f);
|
close(f);
|
||||||
|
|
||||||
execve(prog, argv, environ);
|
execve(prog, argv, e);
|
||||||
spawn_error("pid %d cannot execute %s -- %s\n",
|
spawn_error("pid %d cannot execute %s -- %s\n",
|
||||||
getpid(), prog, strerror(errno));
|
getpid(), prog, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -25,7 +25,8 @@ void spawn_error ( const char *fmt, ... );
|
||||||
|
|
||||||
int find_exec ( const char *name, char *out, size_t len );
|
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);
|
int spawnv(const char *prog, char *argv[], pid_t *pid, int redir_stdout, int redir_stderr);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue