39 #include <sys/types.h> 43 #include <sys/param.h> 48 #define PIDFILE "/var/run/vdr.pid" 49 #define VDRBIN "/usr/bin/vdr" 51 #define errmsg(reason,...) \ 53 fprintf (stderr, "%s: " reason "\n", progname, ## __VA_ARGS__); \ 57 #define errno_msg(reason,...) \ 59 fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (errno)); \ 63 #define _errno_msg(reason,...) \ 65 fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (errno)); \ 69 #define errno_log(reason,...) \ 72 fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (err)); \ 73 syslog (LOG_ERR, reason ": %s", ## __VA_ARGS__, strerror (err)); \ 77 #define _errno_log(reason,...) \ 80 fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (err)); \ 81 syslog (LOG_ERR, reason ": %s", ## __VA_ARGS__, strerror (err)); \ 85 #define errexit(fn, reason,...) \ 86 do { if ((fn) == -1) { errno_msg (reason, ## __VA_ARGS__); } } while (0) 88 #define _errexit(fn, reason,...) \ 89 do { if ((fn) == -1) { _errno_msg (reason, ## __VA_ARGS__); } } while (0) 94 static const char mod_dvb[] =
"dvb-core\0\0";
96 #define BASEMOD (budget ? mod_budget : mod_dvb) 98 #define NUM_STOPTIMES 5 119 switch (waitpid (which, &status, 0))
128 if (WIFEXITED (status))
129 return WEXITSTATUS (status);
130 if (WIFSIGNALED (status))
131 return WTERMSIG (status) | 0x10000;
172 line = strchr (line,
'[');
175 char *mod = strchr (++line,
']');
181 errexit (asprintf (&mod,
"%s %s ", line,
BASEMOD),
"finding module names");
184 while ((space = strchr (space + 1,
' ')) != NULL)
194 if ((line = strchr (line,
' ')) == NULL ||
195 (line = strchr (line + 1,
' ')) == NULL ||
196 (line = strchr (line + 1,
' ')) == NULL)
199 char *mod = strchr (++line,
' ');
204 if (line[0] ==
'-' && line[1] == 0)
207 errexit (asprintf (&mod,
"%s%s,", line,
BASEMOD),
"finding module names");
210 while ((comma = strchr (comma + 1,
',')) != NULL)
219 const char *v = getenv (var);
220 return (v && *v) ? v : dflt;
228 list->
items = realloc (list->
items, ++list->
length * sizeof (
const char *));
231 list->
items[l] = item ? strdup (item) : NULL;
232 if (item && !list->
items[l])
245 for (i = 0; i < list->
length; ++i)
246 free (list->
items[i]);
260 for (i = 0; i < list->
length; ++i)
261 if (!strcmp (list->
items[i], cmp))
270 if (!list || index >= list->
length)
274 if (index < list->length)
275 memmove (&list->
items[index], &list->
items[index + 1],
276 (list->
length - index) * sizeof (
char **));
283 const char *cfgdir, *plugindir, *prefix, *order;
286 struct dirent *entry;
287 List installed_plugins = {0}, ordered_plugins = {0}, leftout_plugins = {0};
289 size_t linelength = 0;
290 int check_patchlevel;
294 plugindir =
getenv_default (
"PLUGIN_DIR",
"/usr/lib/vdr/plugins");
296 order =
getenv_default (
"PLUGIN_ORDER_FILE",
"/etc/vdr/plugins/order.conf");
297 check_patchlevel = !strcmp (
getenv_default (
"PLUGIN_CHECK_PATCHLEVEL",
""),
301 dir = opendir (plugindir);
305 while ((entry = readdir (dir)) != NULL)
308 if (strncmp (entry->d_name, prefix, strlen (prefix)))
310 p = strstr (entry->d_name,
VERSION);
311 if (!p || p != entry->d_name + strlen (entry->d_name) - strlen (
VERSION) ||
312 strncmp (p - 4,
".so.", 4))
315 list_append (&installed_plugins, entry->d_name + strlen (prefix));
317 if (errno || closedir (dir))
320 if (check_patchlevel)
328 switch (cpid = vfork ())
334 if (close (fp[0]) || close (STDOUT_FILENO)
335 || dup2 (fp[1], STDOUT_FILENO) == -1)
337 setenv (
"LANG",
"en", 1);
342 for (i = 0; i < installed_plugins.
length; ++i)
344 _errexit (asprintf (&line,
"vdr-plugin-%s", installed_plugins.
items[i]),
345 "finding module patchlevels");
349 execvp (
"dpkg", dpkg.
items);
355 char *patchlevels[installed_plugins.
length + 1];
358 fd = fdopen (fp[0],
"r");
359 for (i = 0; i <= installed_plugins.
length; ++i)
360 patchlevels[i] = NULL;
363 ssize_t l = getline (&line, &linelength, fd);
366 if (l && line[l - 1] ==
'\n')
368 if (!strncasecmp (line,
"Package: ", 9))
371 pkg = strdup (line + 9);
375 else if (pkg && !strncasecmp (line,
"Patchlevel: ", 12))
377 int p = !strcmp (pkg,
"vdr")
378 ? installed_plugins.
length 379 : (strlen (pkg) > 11)
380 ?
list_find (&installed_plugins, pkg + 11)
384 patchlevels[p] = strdup (line + 12);
397 if (patchlevels[installed_plugins.
length])
398 for (i = 0; i < installed_plugins.
length; ++i)
400 && !strcmp (patchlevels[i],
401 patchlevels[installed_plugins.
length]))
403 for (i = 0; i <= installed_plugins.
length; ++i)
404 free (patchlevels[i]);
405 for (i = 0; i < leftout_plugins.length; ++i)
408 leftout_plugins.
items[i]));
413 fd = fopen (order,
"r");
414 if (!fd && errno != ENOENT)
420 while (!feof (fd) && !ferror (fd))
422 ssize_t l = getline (&line, &linelength, fd);
425 if (l && line[l - 1] ==
'\n')
427 if (!line[0] || line[0] ==
'#')
432 list_find (&installed_plugins, line + 1));
435 l =
list_find (&installed_plugins, line);
442 if (ferror (fd) || fclose (fd))
447 for (i = 0; i < installed_plugins.
length; ++i)
452 for (i = 0; i < ordered_plugins.length; ++i)
455 errexit (asprintf (&file,
"%s/plugin.%s.conf", cfgdir,
456 ordered_plugins.items[i]),
458 fd = fopen (file,
"r");
459 if (!fd && errno != ENOENT)
464 errexit (asprintf (&file,
"-P%s", ordered_plugins.items[i]),
469 ssize_t l = getdelim (&line, &linelength, 256, fd);
470 if (ferror (fd) || fclose (fd))
473 if (l && line[l - 1] ==
'\n')
484 q = strchr (p,
'\n');
486 memmove (p, q + 1, strlen (q));
489 }
while ((p = strchr (p,
'\n')) != NULL);
491 errexit (asprintf (&file,
"-P%s %s", ordered_plugins.items[i], line),
498 if (leftout_plugins.length)
500 fputs (
"WARNING: The following plugins have been left out due to" 501 "possible binary incompatibility:", stderr);
502 for (i = 0; i < leftout_plugins.length; ++i)
503 fprintf (stderr,
" %s", leftout_plugins.items[i]);
504 fputs (
"\n", stderr);
516 int fd = open (
PIDFILE, O_CREAT | O_EXCL | O_WRONLY, 0600);
520 errmsg (
"pidfile exists - is vdr already running?");
523 snprintf (pidbuf,
sizeof (pidbuf),
"%d\n", getpid ());
524 write (fd, pidbuf, strlen (pidbuf));
534 int fd = open (
PIDFILE, O_RDONLY);
537 memset (pidbuf, 0,
sizeof (pidbuf));
538 read (fd, pidbuf,
sizeof (pidbuf) - 1);
539 pid_t pid = atoi (pidbuf);
540 if (pid != getpid () && !kill (pid, 0))
541 syslog (LOG_INFO,
"erk, pidfile doesn't contain my PID");
543 fprintf (stderr,
"%s: unlink pidfile: %s\n",
progname, strerror (errno));
545 fprintf (stderr,
"%s: close pidfile: %s\n",
progname, strerror (errno));
554 bool daemonise =
true;
557 bool mod_reload =
false;
564 signal (SIGUSR2, SIG_IGN);
567 for (argp = 1; argp < argc; ++argp)
569 bool on = (argv[argp][0] ==
'-');
570 switch (((on || argv[argp][0] ==
'+') && argv[argp][1] && !argv[argp][2])
573 case 'n': daemonise = !on;
continue;
574 case 'k': nptl = !on;
continue;
575 case 'l': logio = on;
continue;
576 case 'r': mod_reload = on;
continue;
579 if (argv[argp][0] ==
'-')
586 errmsg (
"usage: runvdr [-n|+n] [-k|+k] [-l|+l] [-r|+r] -- [OPTIONS]");
594 size_t pth_l = confstr (_CS_GNU_LIBPTHREAD_VERSION, 0, 0);
595 char *pth = (
char *)malloc (pth_l);
596 if (confstr (_CS_GNU_LIBPTHREAD_VERSION, pth, pth_l) > 0)
598 if (strstr (pth,
"NPTL"))
600 setenv (
"LD_ASSUME_KERNEL",
"2.4.21", 1);
601 execve (
"/proc/self/exe", argv, environ);
609 openlog (
"vdr", LOG_PID | LOG_CONS, LOG_DAEMON);
615 errmsg (
"sorry, no vdr binary is not installed");
619 if (daemonise && daemon (0, 0))
625 char *modules = NULL;
630 size_t linelen = 0, linealloc = 0;
631 FILE *fd = fopen (
"/proc/modules",
"rb");
639 while ((c = fgetc (fd)) != -1 && c !=
'\n')
641 if (linelen + 2 >= linealloc)
643 line = realloc (line, linealloc += 64);
657 if (!strncmp (line,
"dvb-core", 8) && isspace (line[8]))
662 else if (!strncmp (line,
"dvb_core", 8) && isspace (line[8]))
667 else if (!strncmp (line,
"budget-core", 11) && isspace (line[11]))
672 else if (!strncmp (line,
"budget_core", 11) && isspace (line[11]))
678 errexit (fclose (fd),
"close /proc/modules");
692 switch (
vdr = vfork ())
704 const struct passwd *pwd = getpwnam (
"vdr");
705 gid_t groups[NGROUPS];
707 int numgroups = NGROUPS;
709 getgrouplist (
"vdr", pwd->pw_gid, groups, &numgroups);
711 setenv (
"SHELL", pwd->pw_shell, 1);
712 setenv (
"USER",
"vdr", 1);
713 setenv (
"MAIL",
"/var/mail/vdr", 1);
714 setenv (
"PATH",
"/bin:/usr/bin", 1);
715 setenv (
"PWD", cwd = get_current_dir_name (), 1);
717 setenv (
"HOME", pwd->pw_dir, 1);
718 setenv (
"LOGNAME",
"vdr", 1);
719 if (setregid (pwd->pw_gid, pwd->pw_gid))
721 if (numgroups > 0 && setgroups (numgroups, groups))
723 if (setreuid (pwd->pw_uid, pwd->pw_uid))
731 syslog (LOG_INFO,
"vdr started, pid %d",
vdr);
745 if (status & 0x10000)
746 syslog (LOG_INFO,
"vdr exited, signal %d", status & 0xFFFF);
748 syslog (LOG_INFO,
"vdr exited, status %d", status);
749 if (status < 1 || status == 2)
753 if (status == 1 && modules)
756 syslog (LOG_INFO,
"reloading modules, restarting vdr");
758 const char *mod = modules;
761 switch (cpid = vfork ())
766 execl (
"/sbin/rmmod",
"rmmod", mod, NULL);
771 syslog (LOG_INFO,
"rmmod %s failed: status %d",
774 mod += strlen (mod) + 1;
776 switch (cpid = vfork ())
781 execl (
"/sbin/modprobe",
"modprobe",
"dvb", NULL);
786 syslog (LOG_INFO,
"modprobe dvb failed: status %d", status);
795 syslog (LOG_ERR,
"vdr is being respawned too often - sleeping");
797 struct timespec t = { 300, 0 };
798 while (nanosleep (&t, &t))
static size_t stoptimecount
#define errmsg(reason,...)
static void sig_propagate(int sig)
#define errno_log(reason,...)
static void pidfile_remove(void)
#define _errexit(fn, reason,...)
static void pidfile_write(void)
static const char mod_dvb[]
static void list_append(List *list, const char *item)
static void scan_plugins(List *args)
static const char * progname
static time_t stoptimes[NUM_STOPTIMES]
#define _errno_log(reason,...)
static void sig_quit(int sig)
static size_t list_find(List *list, const char *cmp)
static const char * getenv_default(const char *var, const char *dflt)
static void list_remove(List *list, size_t index)
static char * parse_modules_24(char *line, int budget)
static const char * VERSION
static void list_free(List *list)
#define _errno_msg(reason,...)
int main(int argc, char *argv[])
static void sig_default(int sig)
static const char mod_budget[]
static char * parse_modules_26(char *line, int budget)
#define errno_msg(reason,...)
static int dowait(int which)
#define errexit(fn, reason,...)