vdr  1.7.27
runvdr.c
Go to the documentation of this file.
00001 /* runvdr.c: launch vdr, handle restarts
00002  *
00003  * Copyright (C) 2004 Darren Salt & contributors
00004  * Contributors: Henning Glawe
00005  *
00006  * This program is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU General Public License as published by the Free
00008  * Software Foundation; either version 2 of the License, or (at your option)
00009  * any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00013  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00014  * for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc., 59
00018  * Temple Place - Suite 330, Boston, MA 02111-1307, USA. Or point your
00019  * browser to http://www.gnu.org/copyleft/gpl.html
00020  *
00021  * Email:
00022  *  Author/maintainer:
00023  *  - Darren Salt: linux@youmustbejoking.demon.co.uk
00024  *  Contributors:
00025  *  - Henning Glawe: glaweh@physik.fu-berlin.de
00026  */
00027 
00028 #define _GNU_SOURCE
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <stdbool.h>
00033 #include <ctype.h>
00034 #include <signal.h>
00035 #include <errno.h>
00036 #include <time.h>
00037 #include <syslog.h>
00038 #include <grp.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <fcntl.h>
00042 #include <dirent.h>
00043 #include <sys/param.h>
00044 #include <sys/wait.h>
00045 #include <unistd.h>
00046 #include <pwd.h>
00047 
00048 #define PIDFILE "/var/run/vdr.pid"
00049 #define VDRBIN "/usr/bin/vdr"
00050 
00051 #define errmsg(reason,...) \
00052   do { \
00053     fprintf (stderr, "%s: " reason "\n", progname, ## __VA_ARGS__); \
00054     exit (1); \
00055   } while (0)
00056 
00057 #define errno_msg(reason,...) \
00058   do { \
00059     fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (errno)); \
00060     exit (2); \
00061   } while (0)
00062 
00063 #define _errno_msg(reason,...) \
00064   do { \
00065     fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (errno)); \
00066     _exit (2); \
00067   } while (0)
00068 
00069 #define errno_log(reason,...) \
00070   do { \
00071     int err = errno; \
00072     fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (err)); \
00073     syslog (LOG_ERR, reason ": %s", ## __VA_ARGS__, strerror (err)); \
00074     exit (2); \
00075   } while (0)
00076 
00077 #define _errno_log(reason,...) \
00078   do { \
00079     int err = errno; \
00080     fprintf (stderr, "%s: " reason ": %s\n", progname, ## __VA_ARGS__, strerror (err)); \
00081     syslog (LOG_ERR, reason ": %s", ## __VA_ARGS__, strerror (err)); \
00082     _exit (2); \
00083   } while (0)
00084 
00085 #define errexit(fn, reason,...) \
00086   do { if ((fn) == -1) { errno_msg (reason, ## __VA_ARGS__); } } while (0)
00087 
00088 #define _errexit(fn, reason,...) \
00089   do { if ((fn) == -1) { _errno_msg (reason, ## __VA_ARGS__); } } while (0)
00090 
00091 
00092 static const char *progname;
00093 
00094 static const char mod_dvb[] = "dvb-core\0\0";
00095 static const char mod_budget[] = "budget-core\0\0";
00096 #define BASEMOD (budget ? mod_budget : mod_dvb)
00097 
00098 #define NUM_STOPTIMES 5
00099 static time_t stoptimes[NUM_STOPTIMES];
00100 static size_t stoptimecount = 0;
00101 
00102 static volatile int usr1 = 0;
00103 
00104 static pid_t vdr = 0;
00105 
00106 
00107 typedef struct {
00108   size_t length;
00109   char **items;
00110 } List;
00111 
00112 
00113 static int
00114 dowait (int which)
00115 {
00116   int status;
00117   while (1)
00118   {
00119     switch (waitpid (which, &status, 0))
00120     {
00121       case -1:
00122         if (errno != ECHILD)
00123           errno_msg ("problem in wait()");
00124         return -1;
00125       case 0:
00126         break;
00127       default:
00128         if (WIFEXITED (status))
00129           return WEXITSTATUS (status);
00130         if (WIFSIGNALED (status))
00131           return WTERMSIG (status) | 0x10000;
00132         return -1;
00133     }
00134   }
00135 }
00136 
00137 
00138 static void
00139 sig_quit (int sig)
00140 {
00141   if (vdr > 0)
00142   {
00143     kill (vdr, sig);
00144     vdr = 0;
00145     dowait (-1);
00146   }
00147   exit (0);
00148 }
00149 
00150 
00151 static void
00152 sig_propagate (int sig)
00153 {
00154   signal (sig, sig_propagate);
00155   if (sig == SIGUSR1)
00156     usr1 = 1;
00157   if (vdr > 0)
00158     kill (vdr, sig);
00159 }
00160 
00161 
00162 static void
00163 sig_default (int sig)
00164 {
00165   signal (sig, sig_default);
00166 }
00167 
00168 
00169 static char *
00170 parse_modules_24 (char *line, int budget)
00171 {
00172   line = strchr (line, '[');
00173   if (!line)
00174     return strdup (BASEMOD); /* unknown format */
00175   char *mod = strchr (++line, ']');
00176   if (!mod)
00177     return strdup (BASEMOD); /* unknown format */
00178   *mod = 0;
00179   /* |line| now points to "foo bar baz" (from "[foo bar baz]") */
00180   mod = NULL;
00181   errexit (asprintf (&mod, "%s %s ", line, BASEMOD), "finding module names");
00182   /* replace spaces with NULs */
00183   char *space = mod;
00184   while ((space = strchr (space + 1, ' ')) != NULL)
00185     *space = 0;
00186   return mod;
00187 }
00188 
00189 
00190 static char *
00191 parse_modules_26 (char *line, int budget)
00192 {
00193   /* line == "module size usage dependencies state address" */
00194   if ((line = strchr (line, ' ')) == NULL ||
00195       (line = strchr (line + 1, ' ')) == NULL ||
00196       (line = strchr (line + 1, ' ')) == NULL)
00197     return strdup (BASEMOD); /* unknown format */
00198   /* line == "dependencies state address" */
00199   char *mod = strchr (++line, ' ');
00200   if (!mod)
00201     return strdup (BASEMOD); /* unknown format */
00202   *mod = 0;
00203   /* line == "dependencies" (comma-separated list) */
00204   if (line[0] == '-' && line[1] == 0)
00205     return strdup (BASEMOD); /* no dependent modules */
00206   mod = NULL;
00207   errexit (asprintf (&mod, "%s%s,", line, BASEMOD), "finding module names");
00208   /* replace commas with NULs */
00209   char *comma = mod;
00210   while ((comma = strchr (comma + 1, ',')) != NULL)
00211     *comma = 0;
00212   return mod;
00213 }
00214 
00215 
00216 static const char *
00217 getenv_default (const char *var, const char *dflt)
00218 {
00219   const char *v = getenv (var);
00220   return (v && *v) ? v : dflt;
00221 }
00222 
00223 
00224 static void
00225 list_append (List *list, const char *item)
00226 {
00227   int l = list->length;
00228   list->items = realloc (list->items, ++list->length * sizeof (const char *));
00229   if (!list->items)
00230     errmsg ("out of memory");
00231   list->items[l] = item ? strdup (item) : NULL;
00232   if (item && !list->items[l])
00233     errmsg ("out of memory");
00234 }
00235 
00236 
00237 static void
00238 list_free (List *list)
00239 {
00240   unsigned int i;
00241   if (list)
00242   {
00243     if (list->items)
00244     {
00245       for (i = 0; i < list->length; ++i)
00246         free (list->items[i]);
00247       free (list->items);
00248       list->items = NULL;
00249     }
00250     list->length = 0;
00251   }
00252 }
00253 
00254 
00255 static size_t
00256 list_find (List *list, const char *cmp)
00257 {
00258   unsigned int i;
00259   if (list && list->length)
00260     for (i = 0; i < list->length; ++i)
00261       if (!strcmp (list->items[i], cmp))
00262         return i;
00263   return -1;
00264 }
00265 
00266 
00267 static void
00268 list_remove (List *list, size_t index)
00269 {
00270   if (!list || index >= list->length)
00271     return;
00272 
00273   --list->length;
00274   if (index < list->length)
00275     memmove (&list->items[index], &list->items[index + 1],
00276              (list->length - index) * sizeof (char **));
00277 }
00278 
00279 
00280 static void
00281 scan_plugins (List *args)
00282 {
00283   const char *cfgdir, *plugindir, *prefix, *order;
00284   FILE *fd;
00285   DIR *dir;
00286   struct dirent *entry;
00287   List installed_plugins = {0}, ordered_plugins = {0}, leftout_plugins = {0};
00288   char *line = NULL;
00289   size_t linelength = 0;
00290   int check_patchlevel;
00291   unsigned int i;
00292 
00293   cfgdir = getenv_default ("PLUGIN_CFG_DIR", "/etc/vdr/plugins");
00294   plugindir = getenv_default ("PLUGIN_DIR", "/usr/lib/vdr/plugins");
00295   prefix = getenv_default ("PLUGIN_PREFIX", "libvdr-");
00296   order = getenv_default ("PLUGIN_ORDER_FILE", "/etc/vdr/plugins/order.conf");
00297   check_patchlevel = !strcmp (getenv_default ("PLUGIN_CHECK_PATCHLEVEL", ""),
00298                               "yes");
00299 
00300   /* Find installed plugins */
00301   dir = opendir (plugindir);
00302   if (!dir)
00303     errno_msg ("can't scan %s", plugindir);
00304   errno = 0;
00305   while ((entry = readdir (dir)) != NULL)
00306   {
00307     char *p;
00308     if (strncmp (entry->d_name, prefix, strlen (prefix)))
00309       continue;
00310     p = strstr (entry->d_name, VERSION);
00311     if (!p || p != entry->d_name + strlen (entry->d_name) - strlen (VERSION) ||
00312         strncmp (p - 4, ".so.", 4))
00313       continue;
00314     p[-4] = 0; /* hmm... */
00315     list_append (&installed_plugins, entry->d_name + strlen (prefix));
00316   }
00317   if (errno || closedir (dir))
00318     errno_msg ("can't scan %s", plugindir);
00319 
00320   if (check_patchlevel)
00321   {
00322     /* extract patchlevel info */
00323     List dpkg = {0};
00324     int cpid;
00325     int fp[2];
00326     if (pipe (fp))
00327       errno_msg ("can't open pipe for dpkg");
00328     switch (cpid = vfork ())
00329     {
00330     case -1:
00331       errno_msg ("couldn't run dpkg");
00332 
00333     case 0:
00334       if (close (fp[0]) || close (STDOUT_FILENO)
00335           || dup2 (fp[1], STDOUT_FILENO) == -1)
00336         _errno_msg ("couldn't run dpkg");
00337       setenv ("LANG", "en", 1);
00338       list_append (&dpkg, "dpkg");
00339       list_append (&dpkg, "-s");
00340       list_append (&dpkg, "--");
00341       list_append (&dpkg, "vdr");
00342       for (i = 0; i < installed_plugins.length; ++i)
00343       {
00344         _errexit (asprintf (&line, "vdr-plugin-%s", installed_plugins.items[i]),
00345                   "finding module patchlevels");
00346         list_append (&dpkg, line);
00347         free (line);
00348       }
00349       execvp ("dpkg", dpkg.items);
00350       _errno_msg ("couldn't run dpkg");
00351 
00352     default:
00353       {
00354         char *pkg = NULL;
00355         char *patchlevels[installed_plugins.length + 1];
00356 
00357         close (fp[1]);
00358         fd = fdopen (fp[0], "r");
00359         for (i = 0; i <= installed_plugins.length; ++i)
00360           patchlevels[i] = NULL;
00361         for (;;)
00362         {
00363           ssize_t l = getline (&line, &linelength, fd);
00364           if (l < 0)
00365             break;
00366           if (l && line[l - 1] == '\n')
00367             line[--l] = 0;
00368           if (!strncasecmp (line, "Package: ", 9))
00369           {
00370             free (pkg);
00371             pkg = strdup (line + 9);
00372             if (!pkg)
00373               errmsg ("out of memory");
00374           }
00375           else if (pkg && !strncasecmp (line, "Patchlevel: ", 12))
00376           {
00377             int p = !strcmp (pkg, "vdr")
00378                     ? installed_plugins.length
00379                     : (strlen (pkg) > 11)
00380                       ? list_find (&installed_plugins, pkg + 11)
00381                       : (size_t) -1;
00382             if (p != -1)
00383             {
00384               patchlevels[p] = strdup (line + 12);
00385               if (!patchlevels[p])
00386                 errmsg ("out of memory");
00387             }
00388             free (pkg);
00389             pkg = NULL;
00390           }
00391         }
00392         free (pkg);
00393         if (dowait (cpid) != 0)
00394           exit (2);
00395         close (fp[0]);
00396         fclose (fd);
00397         if (patchlevels[installed_plugins.length])
00398           for (i = 0; i < installed_plugins.length; ++i)
00399             if (patchlevels[i]
00400                 && !strcmp (patchlevels[i],
00401                             patchlevels[installed_plugins.length]))
00402               list_append (&leftout_plugins, installed_plugins.items[i]);
00403         for (i = 0; i <= installed_plugins.length; ++i)
00404           free (patchlevels[i]);
00405         for (i = 0; i < leftout_plugins.length; ++i)
00406           list_remove (&installed_plugins,
00407                        list_find (&installed_plugins,
00408                                   leftout_plugins.items[i]));
00409       }
00410     }
00411   }
00412 
00413   fd = fopen (order, "r");
00414   if (!fd && errno != ENOENT)
00415     errno_msg ("can't read %s", order);
00416 
00417   /* Load plugin order */
00418   if (fd)
00419   {
00420     while (!feof (fd) && !ferror (fd))
00421     {
00422       ssize_t l = getline (&line, &linelength, fd);
00423       if (l < 0)
00424         break;
00425       if (l && line[l - 1] == '\n')
00426         line[--l] = 0;
00427       if (!line[0] || line[0] == '#')
00428         continue;
00429       if (line[0] == '-')
00430       {
00431         list_remove (&installed_plugins,
00432                      list_find (&installed_plugins, line + 1));
00433         continue;
00434       }
00435       l = list_find (&installed_plugins, line);
00436       if (l != -1)
00437       {
00438         list_remove (&installed_plugins, l);
00439         list_append (&ordered_plugins, line);
00440       }
00441     }
00442     if (ferror (fd) || fclose (fd))
00443       errno_msg ("can't read %s", order);
00444   }
00445 
00446   /* Append unordered plugins to ordered plugins */
00447   for (i = 0; i < installed_plugins.length; ++i)
00448     list_append (&ordered_plugins, installed_plugins.items[i]);
00449   list_free (&installed_plugins);
00450 
00451   /* Add the command-line arguments for each plugin */
00452   for (i = 0; i < ordered_plugins.length; ++i)
00453   {
00454     char *file = NULL;
00455     errexit (asprintf (&file, "%s/plugin.%s.conf", cfgdir,
00456                        ordered_plugins.items[i]),
00457              "plugin scan");
00458     fd = fopen (file, "r");
00459     if (!fd && errno != ENOENT)
00460       errno_msg ("can't read %s", order);
00461     free (file);
00462 
00463     if (!fd)
00464       errexit (asprintf (&file, "-P%s", ordered_plugins.items[i]),
00465                "plugin scan");
00466     else
00467     {
00468       char *p, *q;
00469       ssize_t l = getdelim (&line, &linelength, 256, fd); /* slurp */
00470       if (ferror (fd) || fclose (fd))
00471         errno_msg ("can't read %s", order);
00472 
00473       if (l && line[l - 1] == '\n')
00474         line[--l] = 0;
00475 
00476       /* Lose comment lines */
00477       p = line;
00478       do
00479       {
00480         if (*p == '\n')
00481           *p++ = ' ';
00482         if (*p != '#')
00483           continue;
00484         q = strchr (p, '\n');
00485         if (q)
00486           memmove (p, q + 1, strlen (q));
00487         else
00488           *p = 0;
00489       } while ((p = strchr (p, '\n')) != NULL);
00490 
00491       errexit (asprintf (&file, "-P%s %s", ordered_plugins.items[i], line),
00492                "plugin scan");
00493     }
00494     list_append (args, file);
00495     free (file);
00496   }
00497 
00498   if (leftout_plugins.length)
00499   {
00500     fputs ("WARNING: The following plugins have been left out due to"
00501            "possible binary incompatibility:", stderr);
00502     for (i = 0; i < leftout_plugins.length; ++i)
00503       fprintf (stderr, " %s", leftout_plugins.items[i]);
00504     fputs ("\n", stderr);
00505   }
00506 
00507   list_free (&ordered_plugins);
00508   free (line);
00509 }
00510 
00511 
00512 static void
00513 pidfile_write (void)
00514 {
00515   char pidbuf[12];
00516   int fd = open (PIDFILE, O_CREAT | O_EXCL | O_WRONLY, 0600);
00517   if (fd < 0)
00518   {
00519     if (errno == EEXIST)
00520       errmsg ("pidfile exists - is vdr already running?");
00521     errno_msg ("couldn't create pidfile");
00522   }
00523   snprintf (pidbuf, sizeof (pidbuf), "%d\n", getpid ());
00524   write (fd, pidbuf, strlen (pidbuf));
00525   if (close (fd))
00526     errno_msg ("couldn't create pidfile");
00527 }
00528 
00529 
00530 static void
00531 pidfile_remove (void)
00532 {
00533   char pidbuf[12];
00534   int fd = open (PIDFILE, O_RDONLY);
00535   if (fd < 0)
00536     return;
00537   memset (pidbuf, 0, sizeof (pidbuf));
00538   read (fd, pidbuf, sizeof (pidbuf) - 1);
00539   pid_t pid = atoi (pidbuf);
00540   if (pid != getpid () && !kill (pid, 0))
00541     syslog (LOG_INFO, "erk, pidfile doesn't contain my PID");
00542   else if (unlink (PIDFILE))
00543     fprintf (stderr, "%s: unlink pidfile: %s\n", progname, strerror (errno));
00544   if (close (fd))
00545     fprintf (stderr, "%s: close pidfile: %s\n", progname, strerror (errno));
00546 }
00547 
00548 
00549 int
00550 main (int argc, char *argv[])
00551 {
00552   progname = argv[0];
00553   List vdr_opts = {0};
00554   bool daemonise = true;
00555   bool nptl = true;
00556   bool logio = false;
00557   bool mod_reload = false;
00558   int argp;
00559 
00560   signal (SIGHUP, sig_quit);
00561   signal (SIGINT, sig_quit);
00562   signal (SIGTERM, sig_quit);
00563   signal (SIGUSR1, sig_propagate);
00564   signal (SIGUSR2, SIG_IGN);
00565   signal (SIGCHLD, sig_default);
00566 
00567   for (argp = 1; argp < argc; ++argp)
00568   {
00569     bool on = (argv[argp][0] == '-');
00570     switch (((on || argv[argp][0] == '+') && argv[argp][1] && !argv[argp][2])
00571             ? argv[argp][1] : 0)        /* '*' in "-*" or "+*", else NUL */
00572     {
00573     case 'n': daemonise  = !on; continue;
00574     case 'k': nptl       = !on; continue;
00575     case 'l': logio      =  on; continue;
00576     case 'r': mod_reload =  on; continue;
00577 
00578     case '-':
00579       if (argv[argp][0] == '-')
00580       {
00581         ++argp;
00582         goto found_last_arg;
00583       }
00584       /* else fall through */
00585     default:
00586       errmsg ("usage: runvdr [-n|+n] [-k|+k] [-l|+l] [-r|+r] -- [OPTIONS]");
00587     }
00588   }
00589   found_last_arg:
00590 
00591   if (!nptl)
00592   {
00593     /* Check for NPTL and re-exec if present - VDR /may/ not run well with NPTL */
00594     size_t pth_l = confstr (_CS_GNU_LIBPTHREAD_VERSION, 0, 0);
00595     char *pth = (char *)malloc (pth_l);  
00596     if (confstr (_CS_GNU_LIBPTHREAD_VERSION, pth, pth_l) > 0)
00597     {
00598       if (strstr (pth, "NPTL"))
00599       {
00600         setenv ("LD_ASSUME_KERNEL", "2.4.21", 1);
00601         execve ("/proc/self/exe", argv, environ);
00602         errno_msg ("couldn't reload myself");
00603         return 2;
00604       }
00605     }
00606     free (pth);
00607   }
00608 
00609   openlog ("vdr", LOG_PID | LOG_CONS, LOG_DAEMON);
00610 
00611   struct stat st;
00612   if (stat (VDRBIN, &st))
00613   {
00614     if (errno == ENOENT)
00615       errmsg ("sorry, no vdr binary is not installed");
00616     errno_msg ("error when checking %s", VDRBIN);
00617   }
00618 
00619   if (daemonise && daemon (0, 0))
00620     errno_msg ("daemonise");
00621 
00622   atexit (pidfile_remove);
00623   pidfile_write ();
00624 
00625   char *modules = NULL;
00626 
00627   if (mod_reload)
00628   {
00629     char *line = NULL;
00630     size_t linelen = 0, linealloc = 0;
00631     FILE *fd = fopen ("/proc/modules", "rb");
00632     if (!fd)
00633       errno_msg ("open /proc/modules");
00634 
00635     for (;;)
00636     {
00637       int c;
00638       linelen = 0;
00639       while ((c = fgetc (fd)) != -1 && c != '\n')
00640       {
00641         if (linelen + 2 >= linealloc)
00642         {
00643           line = realloc (line, linealloc += 64);
00644           if (!line)
00645             errno_msg ("read /proc/modules");
00646         }
00647         line[linelen] = c;
00648         ++linelen;
00649       }
00650       if (ferror (fd))
00651         errno_msg ("read /proc/modules");
00652       if (feof (fd))
00653         break;
00654       if (!linelen)
00655         continue;
00656       line[linelen] = 0;
00657       if (!strncmp (line, "dvb-core", 8) && isspace (line[8]))
00658       {
00659         free (modules);
00660         modules = parse_modules_24 (line, 0);
00661       }
00662       else if (!strncmp (line, "dvb_core", 8) && isspace (line[8]))
00663       {
00664         free (modules);
00665         modules = parse_modules_26 (line, 0);
00666       }
00667       else if (!strncmp (line, "budget-core", 11) && isspace (line[11]))
00668       {
00669         free (modules);
00670         modules = parse_modules_24 (line, 1);
00671       }
00672       else if (!strncmp (line, "budget_core", 11) && isspace (line[11]))
00673       {
00674         free (modules);
00675         modules = parse_modules_26 (line, 1);
00676       }
00677     }
00678     errexit (fclose (fd), "close /proc/modules");
00679     free (line);
00680   }
00681 
00682   while (1)
00683   {
00684     int i = argp - 1;
00685 
00686     list_free (&vdr_opts);
00687     list_append (&vdr_opts, "vdr");
00688     while (argv[++i])
00689       list_append (&vdr_opts, argv[i]);
00690     scan_plugins (&vdr_opts);
00691     list_append (&vdr_opts, NULL);
00692     switch (vdr = vfork ())
00693     {
00694       int status;
00695 
00696       case -1:
00697         errno_log ("couldn't start vdr");
00698         exit (2);
00699 
00700       case 0: /* child process - run vdr */
00701         setsid ();
00702         if (getuid () == 0)
00703         {
00704           const struct passwd *pwd = getpwnam ("vdr");
00705           gid_t groups[NGROUPS];
00706           char *cwd;
00707           int numgroups = NGROUPS;
00708 
00709           getgrouplist ("vdr", pwd->pw_gid, groups, &numgroups);
00710           chdir (pwd->pw_dir);
00711           setenv ("SHELL", pwd->pw_shell, 1);
00712           setenv ("USER", "vdr", 1);
00713           setenv ("MAIL", "/var/mail/vdr", 1);
00714           setenv ("PATH", "/bin:/usr/bin", 1);
00715           setenv ("PWD", cwd = get_current_dir_name (), 1);
00716           free (cwd);
00717           setenv ("HOME", pwd->pw_dir, 1);
00718           setenv ("LOGNAME", "vdr", 1);
00719           if (setregid (pwd->pw_gid, pwd->pw_gid))
00720             _errno_log ("couldn't set gid for vdr");
00721           if (numgroups > 0 && setgroups (numgroups, groups))
00722             _errno_log ("couldn't set groups for vdr");
00723           if (setreuid (pwd->pw_uid, pwd->pw_uid))
00724             _errno_log ("couldn't set uid for vdr");
00725         }
00726         execv (VDRBIN, vdr_opts.items);
00727         /* Eek, failed - log and exit*/
00728         _errno_log ("couldn't start %s [%d]", VDRBIN, errno);
00729 
00730       default: /* parent process - wait for child to exit */
00731         syslog (LOG_INFO, "vdr started, pid %d", vdr);
00732         status = dowait (-1);
00733 
00734         /* get stop time */
00735         if (stoptimecount == NUM_STOPTIMES)
00736         {
00737           memmove (stoptimes, stoptimes + 1,
00738                    sizeof (stoptimes) - sizeof (stoptimes[0]));
00739           time (&stoptimes[NUM_STOPTIMES - 1]);
00740         }
00741         else
00742           time (&stoptimes[stoptimecount++]);
00743 
00744         /* do some logging; exit if requested */
00745         if (status & 0x10000)
00746           syslog (LOG_INFO, "vdr exited, signal %d", status & 0xFFFF);
00747         else
00748           syslog (LOG_INFO, "vdr exited, status %d", status);
00749         if (status < 1 || status == 2)
00750           exit (0);
00751 
00752         /* reload modules if requested */
00753         if (status == 1 && modules)
00754         {
00755           int status, cpid;
00756           syslog (LOG_INFO, "reloading modules, restarting vdr");
00757           sleep (10);
00758           const char *mod = modules;
00759           while (mod && *mod)
00760           {
00761             switch (cpid = vfork ())
00762             {
00763               case -1:
00764                 break;
00765               case 0:
00766                 execl ("/sbin/rmmod", "rmmod", mod, NULL);
00767                 _exit (errno);
00768               default:
00769                 status = dowait (cpid);
00770                 if (status)
00771                   syslog (LOG_INFO, "rmmod %s failed: status %d",
00772                           mod, status);
00773             }
00774             mod += strlen (mod) + 1;
00775           }
00776           switch (cpid = vfork ())
00777           {
00778             case -1:
00779               break;
00780             case 0:
00781               execl ("/sbin/modprobe", "modprobe", "dvb", NULL);
00782               exit (0);
00783             default:
00784               status = dowait (cpid);
00785               if (status)
00786                 syslog (LOG_INFO, "modprobe dvb failed: status %d", status);
00787           }
00788         }
00789         sleep (1);
00790 
00791         /* stop time too recent? too many exits recently? */
00792         if (stoptimecount == NUM_STOPTIMES &&
00793             (stoptimes[NUM_STOPTIMES] - stoptimes[0]) < 60)
00794         {
00795           syslog (LOG_ERR, "vdr is being respawned too often - sleeping");
00796           usr1 = 0;
00797           struct timespec t = { 300, 0 };
00798           while (nanosleep (&t, &t))
00799             if (usr1)
00800               break;
00801         }
00802     }
00803   }
00804 }