vdr
1.7.27
|
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 }