diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 5d0e1f4d..375e54b2 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -38,7 +38,8 @@ #include "epggrab.h" #include "epggrab/private.h" -#define XMLTV_FIND_GRABBERS "/usr/bin/tv_find_grabbers" +#define XMLTV_FIND "tv_find_grabbers" +#define XMLTV_GRAB "tv_grab_" static epggrab_channel_tree_t _xmltv_channels; static epggrab_module_t *_xmltv_module; @@ -527,30 +528,66 @@ static void _xmltv_load_grabbers ( void ) size_t i, outlen, p, n; char *outbuf; char name[1000]; + char *tmp, *path; /* Load data */ - outlen = spawn_and_store_stdout(XMLTV_FIND_GRABBERS, NULL, &outbuf); - if ( outlen < 1 ) { - tvhlog(LOG_ERR, "xmltv", "%s failed", XMLTV_FIND_GRABBERS); - return; - } + outlen = spawn_and_store_stdout(XMLTV_FIND, NULL, &outbuf); /* Process */ - p = n = i = 0; - while ( i < outlen ) { - if ( outbuf[i] == '\n' || outbuf[i] == '\0' ) { - outbuf[i] = '\0'; - sprintf(name, "XMLTV: %s", &outbuf[n]); - epggrab_module_int_create(NULL, &outbuf[p], name, 3, &outbuf[p], + if ( outlen ) { + p = n = i = 0; + while ( i < outlen ) { + if ( outbuf[i] == '\n' || outbuf[i] == '\0' ) { + outbuf[i] = '\0'; + sprintf(name, "XMLTV: %s", &outbuf[n]); + epggrab_module_int_create(NULL, &outbuf[p], name, 3, &outbuf[p], NULL, _xmltv_parse, NULL, NULL); - p = n = i + 1; - } else if ( outbuf[i] == '|' ) { - outbuf[i] = '\0'; - n = i + 1; + p = n = i + 1; + } else if ( outbuf[i] == '|' ) { + outbuf[i] = '\0'; + n = i + 1; + } + i++; } - i++; + free(outbuf); + + /* Internal search */ + } else if ((tmp = getenv("PATH"))) { + tvhlog(LOG_DEBUG, "epggrab", "using internal grab search"); + char bin[256]; + char desc[] = "--description"; + char *argv[] = { + NULL, + desc, + NULL + }; + path = strdup(tmp); + tmp = strtok(path, ":"); + while (tmp) { + DIR *dir; + struct dirent *de; + struct stat st; + if ((dir = opendir(tmp))) { + while ((de = readdir(dir))) { + if (strstr(de->d_name, XMLTV_GRAB) != de->d_name) continue; + snprintf(bin, sizeof(bin), "%s/%s", tmp, de->d_name); + if (lstat(bin, &st)) continue; + if (!(st.st_mode & S_IEXEC)) continue; + if (!S_ISREG(st.st_mode)) continue; + if ((outlen = spawn_and_store_stdout(bin, argv, &outbuf))) { + if (outbuf[outlen-1] == '\n') outbuf[outlen-1] = '\0'; + snprintf(name, sizeof(name), "XMLTV: %s", outbuf); + epggrab_module_int_create(NULL, bin, name, 3, bin, + NULL, _xmltv_parse, NULL, NULL); + free(outbuf); + } + } + } + closedir(dir); + tmp = strtok(NULL, ":"); + } + free(path); } - free(outbuf); } void xmltv_init ( void ) diff --git a/src/spawn.c b/src/spawn.c index 953a2c79..f12e9e10 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include "tvheadend.h" #include "file.h" @@ -43,6 +45,38 @@ typedef struct spawn { const char *name; } spawn_t; +/* + * Search PATH for executable + */ +static int +_find_exec ( const char *name, char *out, size_t len ) +{ + int ret = 0; + char bin[512]; + char *path, *tmp; + DIR *dir; + struct dirent *de; + struct stat st; + if (!(path = getenv("PATH"))) return 0; + path = strdup(path); + tmp = strtok(path, ":"); + while (tmp && !ret) { + if (!(dir = opendir(tmp))) continue; + while ((de = readdir(dir))) { + if (strstr(de->d_name, name) != de->d_name) continue; + snprintf(bin, sizeof(bin), "%s/%s", tmp, de->d_name); + if (lstat(bin, &st)) continue; + if (!S_ISREG(st.st_mode) || !(st.st_mode & S_IEXEC)) continue; + strncpy(out, bin, len); + ret = 1; + break; + } + closedir(dir); + tmp = strtok(NULL, ":"); + } + free(path); + return ret; +} /** * The reaper is called once a second to finish of any pending spawns @@ -118,18 +152,21 @@ spawn_enq(const char *name, int pid) */ int -spawn_and_store_stdout(const char *prog, char *const argv[], char **outp) +spawn_and_store_stdout(const char *prog, char *argv[], char **outp) { pid_t p; int fd[2], f; - const char *local_argv[2]; + char bin[256]; + const char *local_argv[2] = { NULL, NULL }; - if(argv == NULL) { - local_argv[0] = prog; - local_argv[1] = NULL; - argv = (void *)local_argv; + if (*prog != '/' && *prog != '.') { + if (!_find_exec(prog, bin, sizeof(bin))) return -1; + prog = bin; } + if(!argv) argv = (void *)local_argv; + if (!argv[0]) argv[0] = (char*)prog; + pthread_mutex_lock(&fork_lock); if(pipe(fd) == -1) { @@ -188,9 +225,19 @@ spawn_and_store_stdout(const char *prog, char *const argv[], char **outp) * The function will return the size of the buffer */ int -spawnv(const char *prog, char *const argv[]) +spawnv(const char *prog, char *argv[]) { pid_t p; + char bin[256]; + const char *local_argv[2] = { NULL, NULL }; + + if (*prog != '/' && *prog != '.') { + if (!_find_exec(prog, bin, sizeof(bin))) return -1; + prog = bin; + } + + if(!argv) argv = (void *)local_argv; + if (!argv[0]) argv[0] = (char*)prog; p = fork(); diff --git a/src/spawn.h b/src/spawn.h index 41fb20c8..606a375b 100644 --- a/src/spawn.h +++ b/src/spawn.h @@ -19,9 +19,9 @@ #ifndef SPAWN_H #define SPAWN_H -int spawn_and_store_stdout(const char *prog, char *const argv[], char **outp); +int spawn_and_store_stdout(const char *prog, char *argv[], char **outp); -int spawnv(const char *prog, char *const argv[]); +int spawnv(const char *prog, char *argv[]); void spawn_reaper(void);