vdr  2.6.9
vdr.c
Go to the documentation of this file.
1 /*
2  * vdr.c: Video Disk Recorder main program
3  *
4  * Copyright (C) 2000-2021 Klaus Schmidinger
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  *
21  * The author can be reached at vdr@tvdr.de
22  *
23  * The project's page is at http://www.tvdr.de
24  *
25  * $Id: vdr.c 5.16 2024/03/29 21:46:50 kls Exp $
26  */
27 
28 #include <getopt.h>
29 #include <grp.h>
30 #include <langinfo.h>
31 #include <locale.h>
32 #include <malloc.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <sys/capability.h>
37 #include <sys/prctl.h>
38 #ifdef SDNOTIFY
39 #include <systemd/sd-daemon.h>
40 #endif
41 #include <termios.h>
42 #include <unistd.h>
43 #include "args.h"
44 #include "audio.h"
45 #include "channels.h"
46 #include "config.h"
47 #include "cutter.h"
48 #include "device.h"
49 #include "diseqc.h"
50 #include "dvbdevice.h"
51 #include "eitscan.h"
52 #include "epg.h"
53 #include "i18n.h"
54 #include "interface.h"
55 #include "keys.h"
56 #include "libsi/si.h"
57 #include "lirc.h"
58 #include "menu.h"
59 #include "osdbase.h"
60 #include "plugin.h"
61 #include "recording.h"
62 #include "shutdown.h"
63 #include "skinclassic.h"
64 #include "skinlcars.h"
65 #include "skinsttng.h"
66 #include "sourceparams.h"
67 #include "sources.h"
68 #include "status.h"
69 #include "svdrp.h"
70 #include "themes.h"
71 #include "timers.h"
72 #include "tools.h"
73 #include "transfer.h"
74 #include "videodir.h"
75 
76 #define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
77 #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
78 #define MEMCLEANUPDELTA 3600 // seconds between memory cleanups
79 #define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
80 #define SHUTDOWNRETRY 360 // seconds before trying again to shut down
81 #define SHUTDOWNFORCEPROMPT 5 // seconds to wait in user prompt to allow forcing shutdown
82 #define SHUTDOWNCANCELPROMPT 5 // seconds to wait in user prompt to allow canceling shutdown
83 #define RESTARTCANCELPROMPT 5 // seconds to wait in user prompt before restarting on SIGHUP
84 #define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
85 #define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
86 #define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
87 #define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
88 #define TIMERCHECKDELTA 5 // seconds between checks for timers that need to see their channel
89 #define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
90 #define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
91 #define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
92 #define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
93 
94 #define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
95 
96 static int LastSignal = 0;
97 
98 static bool SetUser(const char *User, bool UserDump)
99 {
100  if (User) {
101  struct passwd *user = isnumber(User) ? getpwuid(atoi(User)) : getpwnam(User);
102  if (!user) {
103  fprintf(stderr, "vdr: unknown user: '%s'\n", User);
104  return false;
105  }
106  if (setgid(user->pw_gid) < 0) {
107  fprintf(stderr, "vdr: cannot set group id %u: %s\n", (unsigned int)user->pw_gid, strerror(errno));
108  return false;
109  }
110  if (initgroups(user->pw_name, user->pw_gid) < 0) {
111  fprintf(stderr, "vdr: cannot set supplemental group ids for user %s: %s\n", user->pw_name, strerror(errno));
112  return false;
113  }
114  if (setuid(user->pw_uid) < 0) {
115  fprintf(stderr, "vdr: cannot set user id %u: %s\n", (unsigned int)user->pw_uid, strerror(errno));
116  return false;
117  }
118  if (UserDump && prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0)
119  fprintf(stderr, "vdr: warning - cannot set dumpable: %s\n", strerror(errno));
120  setenv("HOME", user->pw_dir, 1);
121  setenv("USER", user->pw_name, 1);
122  setenv("LOGNAME", user->pw_name, 1);
123  setenv("SHELL", user->pw_shell, 1);
124  }
125  return true;
126 }
127 
128 static bool DropCaps(void)
129 {
130  // drop all capabilities except selected ones
131  cap_t caps_all = cap_get_proc();
132  if (!caps_all) {
133  fprintf(stderr, "vdr: cap_get_proc failed: %s\n", strerror(errno));
134  return false;
135  }
136  cap_flag_value_t cap_flag_value;
137  if (cap_get_flag(caps_all, CAP_SYS_TIME, CAP_PERMITTED , &cap_flag_value)) {
138  fprintf(stderr, "vdr: cap_get_flag failed: %s\n", strerror(errno));
139  return false;
140  }
141  cap_t caps;
142  if (cap_flag_value == CAP_SET)
143  caps = cap_from_text("= cap_sys_nice,cap_sys_time,cap_net_raw=ep");
144  else {
145  fprintf(stdout,"vdr: OS does not support cap_sys_time\n");
146  caps = cap_from_text("= cap_sys_nice,cap_net_raw=ep");
147  }
148  if (!caps) {
149  fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
150  return false;
151  }
152  if (cap_set_proc(caps) == -1) {
153  fprintf(stderr, "vdr: cap_set_proc failed: %s\n", strerror(errno));
154  cap_free(caps);
155  return false;
156  }
157  cap_free(caps);
158  return true;
159 }
160 
161 static bool SetKeepCaps(bool On)
162 {
163  // set keeping capabilities during setuid() on/off
164  if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
165  fprintf(stderr, "vdr: prctl failed\n");
166  return false;
167  }
168  return true;
169 }
170 
171 static void SignalHandler(int signum)
172 {
173  switch (signum) {
174  case SIGPIPE:
175  break;
176  case SIGHUP:
177  LastSignal = signum;
178  break;
179  default:
180  LastSignal = signum;
181  Interface->Interrupt();
183  }
184  signal(signum, SignalHandler);
185 }
186 
187 static void Watchdog(int signum)
188 {
189  // Something terrible must have happened that prevented the 'alarm()' from
190  // being called in time, so let's get out of here:
191  esyslog("PANIC: watchdog timer expired - exiting!");
192 #ifdef SDNOTIFY
193  sd_notify(0, "STOPPING=1\nSTATUS=PANIC");
194 #endif
195  exit(1);
196 }
197 
198 int main(int argc, char *argv[])
199 {
200  // Save terminal settings:
201 
202  struct termios savedTm;
203  bool HasStdin = (tcgetpgrp(STDIN_FILENO) == getpid() || getppid() != (pid_t)1) && tcgetattr(STDIN_FILENO, &savedTm) == 0;
204 
205  // Initiate locale:
206 
207  setlocale(LC_ALL, "");
208 
209  // Command line options:
210 
211 #define dd(a, b) (*a ? a : b)
212 #define DEFAULTSVDRPPORT 6419
213 #define DEFAULTWATCHDOG 0 // seconds
214 #define DEFAULTVIDEODIR VIDEODIR
215 #define DEFAULTCONFDIR dd(CONFDIR, VideoDirectory)
216 #define DEFAULTARGSDIR dd(ARGSDIR, "/etc/vdr/conf.d")
217 #define DEFAULTCACHEDIR dd(CACHEDIR, VideoDirectory)
218 #define DEFAULTRESDIR dd(RESDIR, ConfigDirectory)
219 #define DEFAULTPLUGINDIR PLUGINDIR
220 #define DEFAULTLOCDIR LOCDIR
221 #define DEFAULTEPGDATAFILENAME "epg.data"
222 
223  bool StartedAsRoot = false;
224  const char *VdrUser = NULL;
225  bool UserDump = false;
226  int SVDRPport = DEFAULTSVDRPPORT;
227  const char *AudioCommand = NULL;
228  const char *VideoDirectory = DEFAULTVIDEODIR;
229  const char *ConfigDirectory = NULL;
230  const char *CacheDirectory = NULL;
231  const char *ResourceDirectory = NULL;
232  const char *LocaleDirectory = DEFAULTLOCDIR;
233  const char *EpgDataFileName = DEFAULTEPGDATAFILENAME;
234  bool DisplayHelp = false;
235  bool DisplayVersion = false;
236  bool DaemonMode = false;
237  int SysLogTarget = LOG_USER;
238  bool MuteAudio = false;
239  int WatchdogTimeout = DEFAULTWATCHDOG;
240  const char *Terminal = NULL;
241  const char *OverrideCharacterTable = NULL;
242 
243  bool UseKbd = true;
244  const char *LircDevice = NULL;
245 #if !defined(REMOTE_KBD)
246  UseKbd = false;
247 #endif
248 #if defined(REMOTE_LIRC)
249  LircDevice = LIRC_DEVICE;
250 #endif
251 #if defined(VDR_USER)
252  VdrUser = VDR_USER;
253 #endif
254 #ifdef SDNOTIFY
255  time_t SdWatchdog = 0;
256  int SdWatchdogTimeout = 0;
257 #endif
258 
259  cArgs *Args = NULL;
260  if (argc == 1) {
261  Args = new cArgs(argv[0]);
262  if (Args->ReadDirectory(DEFAULTARGSDIR)) {
263  argc = Args->GetArgc();
264  argv = Args->GetArgv();
265  }
266  }
267 
268  cVideoDirectory::SetName(VideoDirectory);
269  cPluginManager PluginManager(DEFAULTPLUGINDIR);
270 
271  static struct option long_options[] = {
272  { "audio", required_argument, NULL, 'a' },
273  { "cachedir", required_argument, NULL, 'c' | 0x100 },
274  { "chartab", required_argument, NULL, 'c' | 0x200 },
275  { "config", required_argument, NULL, 'c' },
276  { "daemon", no_argument, NULL, 'd' },
277  { "device", required_argument, NULL, 'D' },
278  { "dirnames", required_argument, NULL, 'd' | 0x100 },
279  { "edit", required_argument, NULL, 'e' | 0x100 },
280  { "epgfile", required_argument, NULL, 'E' },
281  { "filesize", required_argument, NULL, 'f' | 0x100 },
282  { "genindex", required_argument, NULL, 'g' | 0x100 },
283  { "grab", required_argument, NULL, 'g' },
284  { "help", no_argument, NULL, 'h' },
285  { "instance", required_argument, NULL, 'i' },
286  { "lib", required_argument, NULL, 'L' },
287  { "lirc", optional_argument, NULL, 'l' | 0x100 },
288  { "localedir",required_argument, NULL, 'l' | 0x200 },
289  { "log", required_argument, NULL, 'l' },
290  { "mute", no_argument, NULL, 'm' },
291  { "no-kbd", no_argument, NULL, 'n' | 0x100 },
292  { "plugin", required_argument, NULL, 'P' },
293  { "port", required_argument, NULL, 'p' },
294  { "record", required_argument, NULL, 'r' },
295  { "resdir", required_argument, NULL, 'r' | 0x100 },
296  { "showargs", optional_argument, NULL, 's' | 0x200 },
297  { "shutdown", required_argument, NULL, 's' },
298  { "split", no_argument, NULL, 's' | 0x100 },
299  { "terminal", required_argument, NULL, 't' },
300  { "updindex", required_argument, NULL, 'u' | 0x200 },
301  { "user", required_argument, NULL, 'u' },
302  { "userdump", no_argument, NULL, 'u' | 0x100 },
303  { "version", no_argument, NULL, 'V' },
304  { "vfat", no_argument, NULL, 'v' | 0x100 },
305  { "video", required_argument, NULL, 'v' },
306  { "watchdog", required_argument, NULL, 'w' },
307  { NULL, no_argument, NULL, 0 }
308  };
309 
310  int c;
311  while ((c = getopt_long(argc, argv, "a:c:dD:e:E:g:hi:l:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) {
312  switch (c) {
313  case 'a': AudioCommand = optarg;
314  break;
315  case 'c' | 0x100:
316  CacheDirectory = optarg;
317  break;
318  case 'c' | 0x200:
319  OverrideCharacterTable = optarg;
320  break;
321  case 'c': ConfigDirectory = optarg;
322  break;
323  case 'd': DaemonMode = true;
324  break;
325  case 'D': if (*optarg == '-') {
327  break;
328  }
329  if (isnumber(optarg)) {
330  int n = atoi(optarg);
331  if (0 <= n && n < MAXDEVICES) {
333  break;
334  }
335  }
336  fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
337  return 2;
338  case 'd' | 0x100: {
339  char *s = optarg;
340  if (*s != ',') {
341  int n = strtol(s, &s, 10);
342  if (n <= 0 || n >= PATH_MAX) { // PATH_MAX includes the terminating 0
343  fprintf(stderr, "vdr: invalid directory path length: %s\n", optarg);
344  return 2;
345  }
346  DirectoryPathMax = n;
347  if (!*s)
348  break;
349  if (*s != ',') {
350  fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
351  return 2;
352  }
353  }
354  s++;
355  if (!*s)
356  break;
357  if (*s != ',') {
358  int n = strtol(s, &s, 10);
359  if (n <= 0 || n > NAME_MAX) { // NAME_MAX excludes the terminating 0
360  fprintf(stderr, "vdr: invalid directory name length: %s\n", optarg);
361  return 2;
362  }
363  DirectoryNameMax = n;
364  if (!*s)
365  break;
366  if (*s != ',') {
367  fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
368  return 2;
369  }
370  }
371  s++;
372  if (!*s)
373  break;
374  int n = strtol(s, &s, 10);
375  if (n != 0 && n != 1) {
376  fprintf(stderr, "vdr: invalid directory encoding: %s\n", optarg);
377  return 2;
378  }
379  DirectoryEncoding = n;
380  if (*s) {
381  fprintf(stderr, "vdr: unexpected data: %s\n", optarg);
382  return 2;
383  }
384  }
385  break;
386  case 'e' | 0x100:
387  return CutRecording(optarg) ? 0 : 2;
388  case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
389  break;
390  case 'f' | 0x100:
391  Setup.MaxVideoFileSize = StrToNum(optarg) / MEGABYTE(1);
396  break;
397  case 'g' | 0x100:
398  return GenerateIndex(optarg) ? 0 : 2;
399  case 'g': SetSVDRPGrabImageDir(*optarg != '-' ? optarg : NULL);
400  break;
401  case 'h': DisplayHelp = true;
402  break;
403  case 'i': if (isnumber(optarg)) {
404  InstanceId = atoi(optarg);
405  if (InstanceId >= 0)
406  break;
407  }
408  fprintf(stderr, "vdr: invalid instance id: %s\n", optarg);
409  return 2;
410  case 'l': {
411  char *p = strchr(optarg, '.');
412  if (p)
413  *p = 0;
414  if (isnumber(optarg)) {
415  int l = atoi(optarg);
416  if (0 <= l && l <= 3) {
417  SysLogLevel = l;
418  if (!p)
419  break;
420  *p = '.';
421  if (isnumber(p + 1)) {
422  int l = atoi(p + 1);
423  if (0 <= l && l <= 7) {
424  int targets[] = { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
425  SysLogTarget = targets[l];
426  break;
427  }
428  }
429  }
430  }
431  if (p)
432  *p = '.';
433  fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
434  return 2;
435  }
436  case 'L': if (access(optarg, R_OK | X_OK) == 0)
437  PluginManager.SetDirectory(optarg);
438  else {
439  fprintf(stderr, "vdr: can't access plugin directory: %s\n", optarg);
440  return 2;
441  }
442  break;
443  case 'l' | 0x100:
444  LircDevice = optarg ? optarg : LIRC_DEVICE;
445  break;
446  case 'l' | 0x200:
447  if (access(optarg, R_OK | X_OK) == 0)
448  LocaleDirectory = optarg;
449  else {
450  fprintf(stderr, "vdr: can't access locale directory: %s\n", optarg);
451  return 2;
452  }
453  break;
454  case 'm': MuteAudio = true;
455  break;
456  case 'n' | 0x100:
457  UseKbd = false;
458  break;
459  case 'p': if (isnumber(optarg))
460  SVDRPport = atoi(optarg);
461  else {
462  fprintf(stderr, "vdr: invalid port number: %s\n", optarg);
463  return 2;
464  }
465  break;
466  case 'P': PluginManager.AddPlugin(optarg);
467  break;
468  case 'r': cRecordingUserCommand::SetCommand(optarg);
469  break;
470  case 'r' | 0x100:
471  ResourceDirectory = optarg;
472  break;
473  case 's': ShutdownHandler.SetShutdownCommand(optarg);
474  break;
475  case 's' | 0x100:
477  break;
478  case 's' | 0x200: {
479  const char *ArgsDir = optarg ? optarg : DEFAULTARGSDIR;
480  cArgs Args(argv[0]);
481  if (!Args.ReadDirectory(ArgsDir)) {
482  fprintf(stderr, "vdr: can't read arguments from directory: %s\n", ArgsDir);
483  return 2;
484  }
485  int c = Args.GetArgc();
486  char **v = Args.GetArgv();
487  for (int i = 1; i < c; i++)
488  printf("%s\n", v[i]);
489  return 0;
490  }
491  case 't': Terminal = optarg;
492  if (access(Terminal, R_OK | W_OK) < 0) {
493  fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal);
494  return 2;
495  }
496  break;
497  case 'u': if (*optarg)
498  VdrUser = optarg;
499  break;
500  case 'u' | 0x100:
501  UserDump = true;
502  break;
503  case 'u' | 0x200:
504  return GenerateIndex(optarg, true) ? 0 : 2;
505  case 'V': DisplayVersion = true;
506  break;
507  case 'v' | 0x100:
508  DirectoryPathMax = 250;
509  DirectoryNameMax = 40;
510  DirectoryEncoding = true;
511  break;
512  case 'v': VideoDirectory = optarg;
513  while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
514  optarg[strlen(optarg) - 1] = 0;
515  cVideoDirectory::SetName(VideoDirectory);
516  break;
517  case 'w': if (isnumber(optarg)) {
518  int t = atoi(optarg);
519  if (t >= 0) {
520  WatchdogTimeout = t;
521  break;
522  }
523  }
524  fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg);
525  return 2;
526  default: return 2;
527  }
528  }
529 
530  // Help and version info:
531 
532  if (DisplayHelp || DisplayVersion) {
533  if (!PluginManager.HasPlugins())
534  PluginManager.AddPlugin("*"); // adds all available plugins
535  PluginManager.LoadPlugins();
536  if (DisplayHelp) {
537  printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80|
538  " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
539  " --cachedir=DIR save cache files in DIR (default: %s)\n"
540  " --chartab=CHARACTER_TABLE\n"
541  " set the character table to use for strings in the\n"
542  " DVB data stream that don't begin with a character\n"
543  " table indicator, but don't use the standard default\n"
544  " character table (for instance ISO-8859-9)\n"
545  " -c DIR, --config=DIR read config files from DIR (default: %s)\n"
546  " -d, --daemon run in daemon mode\n"
547  " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
548  " there may be several -D options (default: all DVB\n"
549  " devices will be used); if -D- is given, no DVB\n"
550  " devices will be used at all, independent of any\n"
551  " other -D options\n"
552  " --dirnames=PATH[,NAME[,ENC]]\n"
553  " set the maximum directory path length to PATH\n"
554  " (default: %d); if NAME is also given, it defines\n"
555  " the maximum directory name length (default: %d);\n"
556  " the optional ENC can be 0 or 1, and controls whether\n"
557  " special characters in directory names are encoded as\n"
558  " hex values (default: 0); if PATH or NAME are left\n"
559  " empty (as in \",,1\" to only set ENC), the defaults\n"
560  " apply\n"
561  " --edit=REC cut recording REC and exit\n"
562  " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
563  " '%s' in the cache directory)\n"
564  " '-E-' disables this\n"
565  " if FILE is a directory, the default EPG file will be\n"
566  " created in that directory\n"
567  " --filesize=SIZE limit video files to SIZE bytes (default is %dM)\n"
568  " only useful in conjunction with --edit\n"
569  " --genindex=REC generate index for recording REC and exit\n"
570  " -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
571  " given DIR; DIR must be the full path name of an\n"
572  " existing directory, without any \"..\", double '/'\n"
573  " or symlinks (default: none, same as -g-)\n"
574  " -h, --help print this help and exit\n"
575  " -i ID, --instance=ID use ID as the id of this VDR instance (default: 0)\n"
576  " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
577  " 0 = no logging, 1 = errors only,\n"
578  " 2 = errors and info, 3 = errors, info and debug\n"
579  " if logging should be done to LOG_LOCALn instead of\n"
580  " LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7)\n"
581  " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n"
582  " --lirc[=PATH] use a LIRC remote control device, attached to PATH\n"
583  " (default: %s)\n"
584  " --localedir=DIR search for locale files in DIR (default is\n"
585  " %s)\n"
586  " -m, --mute mute audio of the primary DVB device at startup\n"
587  " --no-kbd don't use the keyboard as an input device\n"
588  " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
589  " 0 turns off SVDRP\n"
590  " -P OPT, --plugin=OPT load a plugin defined by the given options\n"
591  " -r CMD, --record=CMD call CMD before and after a recording, and after\n"
592  " a recording has been edited or deleted\n"
593  " --resdir=DIR read resource files from DIR (default: %s)\n"
594  " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
595  " --split split edited files at the editing marks (only\n"
596  " useful in conjunction with --edit)\n"
597  " --showargs[=DIR] print the arguments read from DIR and exit\n"
598  " (default: %s)\n"
599  " -t TTY, --terminal=TTY controlling tty\n"
600  " -u USER, --user=USER run as user USER; only applicable if started as\n"
601  " root; USER can be a user name or a numerical id\n"
602  " --updindex=REC update index for recording REC and exit\n"
603  " --userdump allow coredumps if -u is given (debugging)\n"
604  " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
605  " -V, --version print version information and exit\n"
606  " --vfat for backwards compatibility (same as\n"
607  " --dirnames=250,40,1)\n"
608  " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
609  " seconds (default: %d); '0' disables the watchdog\n"
610  "\n",
613  PATH_MAX - 1,
614  NAME_MAX,
618  LIRC_DEVICE,
625  );
626  }
627  if (DisplayVersion)
628  printf("vdr (%s/%s) - The Video Disk Recorder\n", VDRVERSION, APIVERSION);
629  if (PluginManager.HasPlugins()) {
630  if (DisplayHelp)
631  printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n");
632  for (int i = 0; ; i++) {
633  cPlugin *p = PluginManager.GetPlugin(i);
634  if (p) {
635  const char *help = p->CommandLineHelp();
636  printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description());
637  if (DisplayHelp && help) {
638  printf("\n");
639  puts(help);
640  }
641  }
642  else
643  break;
644  }
645  }
646  return 0;
647  }
648 
649  // Log file:
650 
651  if (SysLogLevel > 0)
652  openlog("vdr", LOG_CONS, SysLogTarget); // LOG_PID doesn't work as expected under NPTL
653 
654  // Daemon mode:
655 
656  if (DaemonMode) {
657  if (daemon(1, 0) == -1) {
658  fprintf(stderr, "vdr: %m\n");
659  esyslog("ERROR: %m");
660  return 2;
661  }
662  }
663  else if (Terminal) {
664  // Claim new controlling terminal
665  stdin = freopen(Terminal, "r", stdin);
666  stdout = freopen(Terminal, "w", stdout);
667  stderr = freopen(Terminal, "w", stderr);
668  HasStdin = true;
669  tcgetattr(STDIN_FILENO, &savedTm);
670  }
671 
672  // Set user id in case we were started as root:
673 
674  if (VdrUser && geteuid() == 0) {
675  StartedAsRoot = true;
676  if (strcmp(VdrUser, "root") && strcmp(VdrUser, "0")) {
677  if (!SetKeepCaps(true))
678  return 2;
679  if (!SetUser(VdrUser, UserDump))
680  return 2;
681  if (!SetKeepCaps(false))
682  return 2;
683  if (!DropCaps())
684  return 2;
685  }
686  }
687 
688  // Check the video directory:
689 
690  if (!DirectoryOk(VideoDirectory, true)) {
691  fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory);
692  return 2;
693  }
694 
695  isyslog("VDR version %s started", VDRVERSION);
696  if (StartedAsRoot && VdrUser)
697  isyslog("switched to user '%s'", VdrUser);
698  if (DaemonMode)
699  dsyslog("running as daemon (tid=%d)", cThread::ThreadId());
701 
702  // Set the system character table:
703 
704  char *CodeSet = NULL;
705  if (setlocale(LC_CTYPE, ""))
706  CodeSet = nl_langinfo(CODESET);
707  else {
708  char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed
709  if (LangEnv) {
710  CodeSet = strchr(LangEnv, '.');
711  if (CodeSet)
712  CodeSet++; // skip the dot
713  }
714  }
715  if (CodeSet) {
716  bool known = SI::SetSystemCharacterTable(CodeSet);
717  isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
719  }
722  isyslog("override character table is '%s' - %s", OverrideCharacterTable, known ? "known" : "unknown");
723  }
724 
725  // Initialize internationalization:
726 
727  I18nInitialize(LocaleDirectory);
728 
729  // Main program loop variables - need to be here to have them initialized before any EXIT():
730 
731  cEpgDataReader EpgDataReader;
732  cOsdObject *Menu = NULL;
733  int LastChannel = 0;
734  int LastTimerChannel = -1;
735  int PreviousChannel[2] = { 1, 1 };
736  int PreviousChannelIndex = 0;
737  time_t LastChannelChanged = time(NULL);
738  time_t LastInteract = 0;
739  int MaxLatencyTime = 0;
740  bool IsInfoMenu = false;
741  cSkin *CurrentSkin = NULL;
742  int OldPrimaryDVB = 0;
743 
744  // Load plugins:
745 
746  if (!PluginManager.LoadPlugins(true))
747  EXIT(2);
748 
749  // Directories:
750 
751  if (!ConfigDirectory)
752  ConfigDirectory = DEFAULTCONFDIR;
753  cPlugin::SetConfigDirectory(ConfigDirectory);
754  if (!CacheDirectory)
755  CacheDirectory = DEFAULTCACHEDIR;
756  cPlugin::SetCacheDirectory(CacheDirectory);
757  if (!ResourceDirectory)
758  ResourceDirectory = DEFAULTRESDIR;
759  cPlugin::SetResourceDirectory(ResourceDirectory);
760  cThemes::SetThemesDirectory("/var/lib/vdr/data/themes");
761 
762  // Configuration data:
763 
764  Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
765  Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
766  Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
767  Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true);
768  cChannels::Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
769  cTimers::Load(AddDirectory(ConfigDirectory, "timers.conf"));
770  Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
771  RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"));
772  SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
773  Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
774  KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);
775  Folders.Load(AddDirectory(ConfigDirectory, "folders.conf"));
776  CamResponsesLoad(AddDirectory(ConfigDirectory, "camresponses.conf"), true);
777  DoneRecordingsPattern.Load(AddDirectory(CacheDirectory, "donerecs.data"));
778 
780  const char *msg = "no fonts available - OSD will not show any text!";
781  fprintf(stderr, "vdr: %s\n", msg);
782  esyslog("ERROR: %s", msg);
783  }
784 
785  // Recordings:
786 
788 
789  // EPG data:
790 
791  if (EpgDataFileName) {
792  const char *EpgDirectory = NULL;
793  if (DirectoryOk(EpgDataFileName)) {
794  EpgDirectory = EpgDataFileName;
795  EpgDataFileName = DEFAULTEPGDATAFILENAME;
796  }
797  else if (*EpgDataFileName != '/' && *EpgDataFileName != '.')
798  EpgDirectory = CacheDirectory;
799  if (EpgDirectory)
800  cSchedules::SetEpgDataFileName(AddDirectory(EpgDirectory, EpgDataFileName));
801  else
802  cSchedules::SetEpgDataFileName(EpgDataFileName);
803  EpgDataReader.Start();
804  }
805 
806  // DVB interfaces:
807 
810 
811  // Initialize plugins:
812 
813  if (!PluginManager.InitializePlugins())
814  EXIT(2);
815 
816  // Primary device:
817 
819  if (!cDevice::PrimaryDevice() || !cDevice::PrimaryDevice()->HasDecoder()) {
820  if (cDevice::PrimaryDevice() && !cDevice::PrimaryDevice()->HasDecoder())
821  isyslog("device %d has no MPEG decoder", cDevice::PrimaryDevice()->DeviceNumber() + 1);
822  for (int i = 0; i < cDevice::NumDevices(); i++) {
823  cDevice *d = cDevice::GetDevice(i);
824  if (d && d->HasDecoder()) {
825  isyslog("trying device number %d instead", i + 1);
826  if (cDevice::SetPrimaryDevice(i + 1)) {
827  Setup.PrimaryDVB = i + 1;
828  break;
829  }
830  }
831  }
832  if (!cDevice::PrimaryDevice()) {
833  const char *msg = "no primary device found - using first device!";
834  fprintf(stderr, "vdr: %s\n", msg);
835  esyslog("ERROR: %s", msg);
837  EXIT(2);
838  if (!cDevice::PrimaryDevice()) {
839  const char *msg = "no primary device found - giving up!";
840  fprintf(stderr, "vdr: %s\n", msg);
841  esyslog("ERROR: %s", msg);
842  EXIT(2);
843  }
844  }
845  }
846  OldPrimaryDVB = Setup.PrimaryDVB;
847 
848  // Check for timers in automatic start time window:
849 
851 
852  // User interface:
853 
854  Interface = new cInterface;
855 
856  // Default skins:
857 
858  new cSkinLCARS;
859  new cSkinSTTNG;
860  new cSkinClassic;
863  CurrentSkin = Skins.Current();
864 
865  // Start plugins:
866 
867  if (!PluginManager.StartPlugins())
868  EXIT(2);
869 
870  // Set skin and theme in case they're implemented by a plugin:
871 
872  if (!CurrentSkin || CurrentSkin == Skins.Current() && strcmp(Skins.Current()->Name(), Setup.OSDSkin) != 0) {
875  }
876 
877  // Remote Controls:
878  if (LircDevice)
879  cLircRemote::NewLircRemote(LircDevice);
880  if (!DaemonMode && HasStdin && UseKbd)
881  new cKbdRemote;
882  Interface->LearnKeys();
883 
884  // External audio:
885 
886  if (AudioCommand)
887  new cExternalAudio(AudioCommand);
888 
889  // Positioner:
890 
891  if (!cPositioner::GetPositioner()) // no plugin has created a positioner
892  new cDiseqcPositioner;
893 
894  // CAM data:
895 
896  ChannelCamRelations.Load(AddDirectory(CacheDirectory, "cam.data"));
897 
898  // Channel:
899 
901  dsyslog("not all devices ready after %d seconds", DEVICEREADYTIMEOUT);
903  dsyslog("not all CAM slots ready after %d seconds", DEVICEREADYTIMEOUT);
904  if (*Setup.InitialChannel) {
906  if (isnumber(Setup.InitialChannel)) { // for compatibility with old setup.conf files
907  if (const cChannel *Channel = Channels->GetByNumber(atoi(Setup.InitialChannel)))
908  Setup.InitialChannel = Channel->GetChannelID().ToString();
909  }
910  if (const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(Setup.InitialChannel)))
911  Setup.CurrentChannel = Channel->Number();
912  }
913  if (Setup.InitialVolume >= 0)
915  {
917  Channels->SwitchTo(Setup.CurrentChannel);
918  }
919 
920  // Restore volume:
921 
923  if (MuteAudio)
925 
926  // Signal handlers:
927 
928  if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
929  if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
930  if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
931  if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
932  if (WatchdogTimeout > 0)
933  if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN);
934 
935  // Watchdog:
936 
937  if (WatchdogTimeout > 0) {
938  dsyslog("setting watchdog timer to %d seconds", WatchdogTimeout);
939  alarm(WatchdogTimeout); // Initial watchdog timer start
940  }
941 
942 #ifdef SDNOTIFY
943  if (sd_watchdog_enabled(0, NULL) > 0) {
944  uint64_t timeout;
945  SdWatchdog = time(NULL);
946  sd_watchdog_enabled(0, &timeout);
947  SdWatchdogTimeout = (int)timeout/1000000;
948  dsyslog("SD_WATCHDOG enabled with timeout set to %d seconds", SdWatchdogTimeout);
949  }
950 
951  // Startup notification:
952 
953  sd_notify(0, "READY=1\nSTATUS=Ready");
954 #endif
955 
956  // SVDRP:
957 
958  SetSVDRPPorts(SVDRPport, DEFAULTSVDRPPORT);
960 
961  // Main program loop:
962 
963 #define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
964 
965  while (!ShutdownHandler.DoExit()) {
966 #ifdef DEBUGRINGBUFFERS
967  cRingBufferLinear::PrintDebugRBL();
968 #endif
969  // Attach launched player control:
971 
972  time_t Now = time(NULL);
973 
974  // Make sure we have a visible programme in case device usage has changed:
976  static time_t lastTime = 0;
977  if (!cDevice::PrimaryDevice()->HasProgramme()) {
978  if (!CamMenuActive() && Now - lastTime > MINCHANNELWAIT) { // !CamMenuActive() to avoid interfering with the CAM if a CAM menu is open
980  const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel());
981  if (Channel && (Channel->Vpid() || Channel->Apid(0) || Channel->Dpid(0))) {
982  if (cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(Channel->Number())) // try to switch to the original channel...
983  ;
984  else if (LastTimerChannel > 0) {
985  Channel = Channels->GetByNumber(LastTimerChannel);
986  if (Channel && cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(LastTimerChannel)) // ...or the one used by the last timer
987  ;
988  }
989  }
990  lastTime = Now; // don't do this too often
991  LastTimerChannel = -1;
992  }
993  }
994  else
995  lastTime = 0; // makes sure we immediately try again next time
996  }
997  // Update the OSD size:
998  {
999  static time_t lastOsdSizeUpdate = 0;
1000  if (Now != lastOsdSizeUpdate) { // once per second
1002  static int OsdState = 0;
1003  if (cOsdProvider::OsdSizeChanged(OsdState)) {
1004  if (cOsdMenu *OsdMenu = dynamic_cast<cOsdMenu *>(Menu))
1005  OsdMenu->Display();
1006  }
1007  lastOsdSizeUpdate = Now;
1008  }
1009  }
1010  // Restart the Watchdog timer:
1011  if (WatchdogTimeout > 0) {
1012  int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
1013  if (LatencyTime > MaxLatencyTime) {
1014  MaxLatencyTime = LatencyTime;
1015  dsyslog("max. latency time %d seconds", MaxLatencyTime);
1016  }
1017  }
1018 #ifdef SDNOTIFY
1019  // Ping systemd watchdog when half the timeout is elapsed:
1020  if (SdWatchdogTimeout && (Now - SdWatchdog) * 2 > SdWatchdogTimeout) {
1021  sd_notify(0, "WATCHDOG=1");
1022  SdWatchdog = Now;
1023  dsyslog("SD_WATCHDOG ping");
1024  }
1025 #endif
1026  // Handle channel and timer modifications:
1027  static bool ChannelsRenumber = false;
1028  {
1029  // Channels and timers need to be stored in a consistent manner,
1030  // therefore if one of them is changed, we save both.
1031  static time_t ChannelSaveTimeout = 0;
1032  static cStateKey TimersStateKey(true);
1033  static cStateKey ChannelsStateKey(true);
1034  static int ChannelsModifiedByUser = 0;
1035  const cTimers *Timers = cTimers::GetTimersRead(TimersStateKey);
1036  const cChannels *Channels = cChannels::GetChannelsRead(ChannelsStateKey);
1037  if (ChannelSaveTimeout != 1) {
1038  if (Channels) {
1039  if (Channels->ModifiedByUser(ChannelsModifiedByUser))
1040  ChannelSaveTimeout = 1; // triggers an immediate save
1041  else if (!ChannelSaveTimeout)
1042  ChannelSaveTimeout = Now + CHANNELSAVEDELTA;
1043  }
1044  if (Timers)
1045  ChannelSaveTimeout = 1; // triggers an immediate save
1046  }
1047  if (ChannelSaveTimeout && Now > ChannelSaveTimeout && !cRecordControls::Active())
1048  ChannelSaveTimeout = 1; // triggers an immediate save
1049  if (Timers && Channels) {
1050  Channels->Save();
1051  Timers->Save();
1052  ChannelSaveTimeout = 0;
1053  }
1054  if (Channels) {
1055  for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1056  int ChannelModification = Channel->Modification(CHANNELMOD_ALL);
1057  if (ChannelModification & CHANNELMOD_TRANSP)
1058  ChannelsRenumber = true;
1059  if (ChannelModification & CHANNELMOD_RETUNE) {
1061  if (Channel->Number() == cDevice::CurrentChannel() && cDevice::PrimaryDevice()->HasDecoder()) {
1062  if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) {
1063  if (cDevice::ActualDevice()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
1064  isyslog("retuning due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
1065  Channels->SwitchTo(Channel->Number());
1066  }
1067  }
1068  }
1069  cStatus::MsgChannelChange(Channel);
1070  }
1071  }
1072  }
1073  // State keys are removed in reverse order!
1074  if (Channels)
1075  ChannelsStateKey.Remove();
1076  if (Timers)
1077  TimersStateKey.Remove();
1078  if (ChannelSaveTimeout == 1) {
1079  // Only one of them was modified, so we reset the state keys to handle them both in the next turn:
1080  ChannelsStateKey.Reset();
1081  TimersStateKey.Reset();
1082  }
1083  }
1084  // Channel display:
1085  if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
1086  if (!Menu)
1087  Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0);
1088  LastChannel = cDevice::CurrentChannel();
1089  LastChannelChanged = Now;
1090  }
1091  if (Now - LastChannelChanged >= Setup.ZapTimeout && LastChannel != PreviousChannel[PreviousChannelIndex])
1092  PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
1093  {
1094  // Timers and Recordings:
1095  static cStateKey TimersStateKey;
1096  cTimers *Timers = cTimers::GetTimersWrite(TimersStateKey);
1097  {
1098  LOCK_CHANNELS_READ; // Channels are needed for spawning pattern timers!
1099  // Assign events to timers:
1100  static cStateKey SchedulesStateKey;
1101  if (TimersStateKey.StateChanged())
1102  SchedulesStateKey.Reset(); // we assign events if either the Timers or the Schedules have changed
1103  bool TimersModified = false;
1104  if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey)) {
1105  Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll); // setting events shall not trigger a remote timer poll...
1106  if (Timers->AdjustSpawnedTimers()) { // must do this *before* SetEvents()!
1107  StateKeySVDRPRemoteTimersPoll.Reset(); // ...but adjusting spawned timers...
1108  TimersModified = true;
1109  }
1110  if (Timers->SetEvents(Schedules))
1111  TimersModified = true;
1112  if (Timers->SpawnPatternTimers(Schedules)) {
1113  StateKeySVDRPRemoteTimersPoll.Reset(); // ...or spawning new timers must!
1114  TimersModified = true;
1115  }
1116  SchedulesStateKey.Remove();
1117  }
1118  TimersStateKey.Remove(TimersModified); // we need to remove the key here, so that syncing StateKeySVDRPRemoteTimersPoll takes effect!
1119  }
1120  // Must do all following calls with the exact same time!
1121  // Process ongoing recordings:
1122  Timers = cTimers::GetTimersWrite(TimersStateKey);
1123  bool TimersModified = false;
1124  if (cRecordControls::Process(Timers, Now))
1125  TimersModified = true;
1126  // Start new recordings:
1127  if (cTimer *Timer = Timers->GetMatch(Now)) {
1128  if (!cRecordControls::Start(Timers, Timer))
1129  Timer->SetPending(true);
1130  else
1131  LastTimerChannel = Timer->Channel()->Number();
1132  TimersModified = true;
1133  }
1134  // Make sure timers "see" their channel early enough:
1135  static time_t LastTimerCheck = 0;
1136  if (Now - LastTimerCheck > TIMERCHECKDELTA) { // don't do this too often
1137  for (cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
1138  if (Timer->Remote() || Timer->IsPatternTimer())
1139  continue;
1140  bool InVpsMargin = false;
1141  bool NeedsTransponder = false;
1142  if (Timer->HasFlags(tfActive) && !Timer->Recording()) {
1143  if (Timer->HasFlags(tfVps)) {
1144  if (Timer->Matches(Now, true, Setup.VpsMargin))
1145  InVpsMargin = true;
1146  else if (Timer->Event()) {
1147  InVpsMargin = Timer->Event()->StartTime() <= Now && Now < Timer->Event()->EndTime();
1148  NeedsTransponder = Timer->Event()->StartTime() - Now < VPSLOOKAHEADTIME * 3600 && !Timer->Event()->SeenWithin(VPSUPTODATETIME);
1149  }
1150  else {
1152  const cSchedule *Schedule = Schedules->GetSchedule(Timer->Channel());
1153  InVpsMargin = !Schedule; // we must make sure we have the schedule
1154  NeedsTransponder = Schedule && !Schedule->PresentSeenWithin(VPSUPTODATETIME);
1155  }
1156  }
1157  else
1158  NeedsTransponder = Timer->Matches(Now, true, TIMERLOOKAHEADTIME);
1159  }
1160  if (!Timer->Recording())
1161  Timer->SetInVpsMargin(InVpsMargin);
1162  if (NeedsTransponder || InVpsMargin) {
1163  // Find a device that provides the required transponder:
1164  cDevice *Device = cDevice::GetDeviceForTransponder(Timer->Channel(), MINPRIORITY);
1165  if (InVpsMargin) {
1166  if (!Device)
1167  Device = cDevice::GetDeviceForTransponder(Timer->Channel(), Timer->Priority() );
1168  if (!Device)
1169  Device = cDevice::GetDevice(Timer->Channel(), Timer->Priority(), false, false);
1170  }
1171  // Switch the device to the transponder:
1172  if (Device) {
1173  bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
1174  if (!Device->IsTunedToTransponder(Timer->Channel())) {
1175  if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
1176  cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
1177  dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
1178  Device->SwitchChannel(Timer->Channel(), false);
1179  }
1180  Device->SetOccupied(TIMERDEVICETIMEOUT, InVpsMargin ? Timer->Priority() : MINPRIORITY, Now);
1181  if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme()) {
1182  LastTimerChannel = Timer->Channel()->Number();
1183  Skins.QueueMessage(mtInfo, tr("Upcoming recording!")); // the previous SwitchChannel() has switched away the current live channel
1184  }
1185  }
1186  }
1187  }
1188  LastTimerCheck = Now;
1189  }
1190  // Delete expired timers:
1191  if (Timers->DeleteExpired(TimersModified))
1192  TimersModified = true;
1193  // Make sure there is enough free disk space for ongoing recordings:
1194  int MaxPriority = Timers->GetMaxPriority();
1195  if (MaxPriority >= 0)
1196  AssertFreeDiskSpace(MaxPriority);
1197  TimersStateKey.Remove(TimersModified);
1198  }
1199  // Renumber channels on LCN update
1200  if (ChannelsRenumber) {
1202  Channels->ReNumber();
1203  ChannelsRenumber = false;
1204  }
1205  // Recordings:
1206  if (!Menu) {
1209  }
1210  // CAM control:
1211  if (!Menu && !cOsd::IsOpen())
1212  Menu = CamControl();
1213  // Queued messages:
1215  // User Input:
1216  bool NeedsFastResponse = Menu && Menu->NeedsFastResponse();
1217  if (!NeedsFastResponse) {
1218  // Must limit the scope of ControlMutexLock here to not hold the lock during the call to Interface->GetKey().
1219  cMutexLock ControlMutexLock;
1220  cControl *Control = cControl::Control(ControlMutexLock);
1221  NeedsFastResponse = Control && Control->NeedsFastResponse();
1222  }
1223  eKeys key = Interface->GetKey(!NeedsFastResponse);
1224  cOsdObject *Interact = Menu;
1225  cMutexLock ControlMutexLock;
1226  cControl *Control = NULL;
1227  if (!Menu)
1228  Interact = Control = cControl::Control(ControlMutexLock);
1229  if (ISREALKEY(key)) {
1230  EITScanner.Activity();
1231  // Cancel shutdown countdown:
1234  // Set user active for MinUserInactivity time in the future:
1236  }
1237  // Keys that must work independent of any interactive mode:
1238  switch (int(key)) {
1239  // Menu control:
1240  case kMenu: {
1241  key = kNone; // nobody else needs to see this key
1242  bool WasOpen = Interact != NULL;
1243  bool WasMenu = Interact && Interact->IsMenu();
1244  if (Menu)
1245  DELETE_MENU;
1246  else if (Control) {
1247  if (cOsd::IsOpen())
1248  Control->Hide();
1249  else
1250  WasOpen = false;
1251  }
1252  if (!WasOpen || !WasMenu && !Setup.MenuKeyCloses)
1253  Menu = new cMenuMain;
1254  }
1255  break;
1256  // Info:
1257  case kInfo: {
1258  if (IsInfoMenu) {
1259  key = kNone; // nobody else needs to see this key
1260  DELETE_MENU;
1261  }
1262  else if (!Menu) {
1263  IsInfoMenu = true;
1264  if (Control) {
1265  Control->Hide();
1266  Menu = Control->GetInfo();
1267  if (Menu)
1268  Menu->Show();
1269  else
1270  IsInfoMenu = false;
1271  }
1272  else {
1273  cRemote::Put(kOk, true);
1274  cRemote::Put(kSchedule, true);
1275  }
1276  key = kNone; // nobody else needs to see this key
1277  }
1278  }
1279  break;
1280  // Direct main menu functions:
1281  #define DirectMainFunction(function)\
1282  { DELETE_MENU;\
1283  if (Control)\
1284  Control->Hide();\
1285  Menu = new cMenuMain(function);\
1286  key = kNone; } // nobody else needs to see this key
1287  case kSchedule: DirectMainFunction(osSchedule); break;
1288  case kChannels: DirectMainFunction(osChannels); break;
1289  case kTimers: DirectMainFunction(osTimers); break;
1291  case kSetup: DirectMainFunction(osSetup); break;
1292  case kCommands: DirectMainFunction(osCommands); break;
1293  case kUser0 ... kUser9: cRemote::PutMacro(key); key = kNone; break;
1294  case k_Plugin: {
1295  const char *PluginName = cRemote::GetPlugin();
1296  if (PluginName) {
1297  DELETE_MENU;
1298  if (Control)
1299  Control->Hide();
1300  cPlugin *plugin = cPluginManager::GetPlugin(PluginName);
1301  if (plugin) {
1302  Menu = plugin->MainMenuAction();
1303  if (Menu)
1304  Menu->Show();
1305  }
1306  else
1307  esyslog("ERROR: unknown plugin '%s'", PluginName);
1308  }
1309  key = kNone; // nobody else needs to see these keys
1310  }
1311  break;
1312  // Channel up/down:
1313  case kChanUp|k_Repeat:
1314  case kChanUp:
1315  case kChanDn|k_Repeat:
1316  case kChanDn:
1317  if (!Interact) {
1318  Menu = new cDisplayChannel(NORMALKEY(key));
1319  continue;
1320  }
1321  else if (cDisplayChannel::IsOpen() || Control) {
1322  Interact->ProcessKey(key);
1323  continue;
1324  }
1325  else
1326  cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
1327  break;
1328  // Volume control:
1329  case kVolUp|k_Repeat:
1330  case kVolUp:
1331  case kVolDn|k_Repeat:
1332  case kVolDn:
1333  case kMute:
1334  if (key == kMute) {
1335  if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu) {
1336  key = kNone; // nobody else needs to see these keys
1337  break; // no need to display "mute off"
1338  }
1339  }
1340  else
1342  if (!Menu && !cOsd::IsOpen())
1343  Menu = cDisplayVolume::Create();
1345  key = kNone; // nobody else needs to see these keys
1346  break;
1347  // Audio track control:
1348  case kAudio:
1349  if (Control)
1350  Control->Hide();
1351  if (!cDisplayTracks::IsOpen()) {
1352  DELETE_MENU;
1353  Menu = cDisplayTracks::Create();
1354  }
1355  else
1357  key = kNone;
1358  break;
1359  // Subtitle track control:
1360  case kSubtitles:
1361  if (Control)
1362  Control->Hide();
1364  DELETE_MENU;
1366  }
1367  else
1369  key = kNone;
1370  break;
1371  // Pausing live video:
1372  case kPlayPause:
1373  case kPause:
1374  if (!Control) {
1375  DELETE_MENU;
1376  if (Setup.PauseKeyHandling) {
1377  if (Setup.PauseKeyHandling > 1 || Interface->Confirm(tr("Pause live video?"))) {
1379  Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1380  }
1381  }
1382  key = kNone; // nobody else needs to see this key
1383  }
1384  break;
1385  // Instant recording:
1386  case kRecord:
1387  if (!Control) {
1388  if (Setup.RecordKeyHandling) {
1389  if (Setup.RecordKeyHandling > 1 || Interface->Confirm(tr("Start recording?"))) {
1390  if (cRecordControls::Start())
1391  Skins.QueueMessage(mtInfo, tr("Recording started"));
1392  }
1393  }
1394  key = kNone; // nobody else needs to see this key
1395  }
1396  break;
1397  // Power off:
1398  case kPower:
1399  isyslog("Power button pressed");
1400  DELETE_MENU;
1401  // Check for activity, request power button again if active:
1402  if (!ShutdownHandler.ConfirmShutdown(false) && Skins.Message(mtWarning, tr("VDR will shut down later - press Power to force"), SHUTDOWNFORCEPROMPT) != kPower) {
1403  // Not pressed power - set VDR to be non-interactive and power down later:
1405  break;
1406  }
1407  // No activity or power button pressed twice - ask for confirmation:
1408  if (!ShutdownHandler.ConfirmShutdown(true)) {
1409  // Non-confirmed background activity - set VDR to be non-interactive and power down later:
1411  break;
1412  }
1413  // Ask the final question:
1414  if (!Interface->Confirm(tr("Press any key to cancel shutdown"), SHUTDOWNCANCELPROMPT, true))
1415  // If final question was canceled, continue to be active:
1416  break;
1417  // Ok, now call the shutdown script:
1419  // Set VDR to be non-interactive and power down again later:
1421  // Do not attempt to automatically shut down for a while:
1423  break;
1424  default: break;
1425  }
1426  Interact = Menu ? Menu : Control; // might have been closed in the mean time
1427  if (Interact) {
1428  LastInteract = Now;
1429  eOSState state = Interact->ProcessKey(key);
1430  if (state == osUnknown && Interact != Control) {
1431  if (ISMODELESSKEY(key) && Control) {
1432  state = Control->ProcessKey(key);
1433  if (state == osEnd) {
1434  // let's not close a menu when replay ends:
1435  Control = NULL;
1437  continue;
1438  }
1439  }
1440  else if (Now - cRemote::LastActivity() > MENUTIMEOUT)
1441  state = osEnd;
1442  }
1443  switch (state) {
1444  case osPause: DELETE_MENU;
1446  Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1447  break;
1448  case osRecord: DELETE_MENU;
1449  if (cRecordControls::Start())
1450  Skins.QueueMessage(mtInfo, tr("Recording started"));
1451  break;
1452  case osRecordings:
1453  DELETE_MENU;
1454  Control = NULL;
1456  Menu = new cMenuMain(osRecordings, true);
1457  break;
1458  case osReplay: DELETE_MENU;
1459  Control = NULL;
1462  break;
1463  case osStopReplay:
1464  DELETE_MENU;
1465  Control = NULL;
1467  break;
1468  case osPlugin: DELETE_MENU;
1469  Menu = cMenuMain::PluginOsdObject();
1470  if (Menu)
1471  Menu->Show();
1472  break;
1473  case osBack:
1474  case osEnd: if (Interact == Menu)
1475  DELETE_MENU;
1476  else {
1477  Control = NULL;
1479  }
1480  break;
1481  default: ;
1482  }
1483  }
1484  else {
1485  // Key functions in "normal" viewing mode:
1486  if (key != kNone && KeyMacros.Get(key)) {
1487  cRemote::PutMacro(key);
1488  key = kNone;
1489  }
1490  switch (int(key)) {
1491  // Toggle channels:
1492  case kChanPrev:
1493  case k0: {
1494  if (PreviousChannel[PreviousChannelIndex ^ 1] == LastChannel || LastChannel != PreviousChannel[0] && LastChannel != PreviousChannel[1])
1495  PreviousChannelIndex ^= 1;
1497  Channels->SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]);
1498  break;
1499  }
1500  // Direct Channel Select:
1501  case k1 ... k9:
1502  // Left/Right rotates through channel groups:
1503  case kLeft|k_Repeat:
1504  case kLeft:
1505  case kRight|k_Repeat:
1506  case kRight:
1507  // Previous/Next rotates through channel groups:
1508  case kPrev|k_Repeat:
1509  case kPrev:
1510  case kNext|k_Repeat:
1511  case kNext:
1512  // Up/Down Channel Select:
1513  case kUp|k_Repeat:
1514  case kUp:
1515  case kDown|k_Repeat:
1516  case kDown:
1517  Menu = new cDisplayChannel(NORMALKEY(key));
1518  break;
1519  // Viewing Control:
1520  case kOk: LastChannel = -1; break; // forces channel display
1521  // Instant resume of the last viewed recording:
1522  case kPlay:
1524  Control = NULL;
1527  }
1528  else
1529  DirectMainFunction(osRecordings); // no last viewed recording, so enter the Recordings menu
1530  break;
1531  default: break;
1532  }
1533  }
1534  if (!Menu) {
1535  EITScanner.Process();
1536  bool Error = false;
1537  if (RecordingsHandler.Finished(Error)) {
1538  if (Error)
1539  Skins.Message(mtError, tr("Editing process failed!"));
1540  else
1541  Skins.Message(mtInfo, tr("Editing process finished"));
1542  }
1543  }
1544 
1545  // Change primary device:
1546  int NewPrimaryDVB = Setup.PrimaryDVB;
1547  if (NewPrimaryDVB != OldPrimaryDVB) {
1548  DELETE_MENU;
1549  Control = NULL;
1551  Skins.QueueMessage(mtInfo, tr("Switching primary DVB..."));
1553  cDevice::SetPrimaryDevice(NewPrimaryDVB);
1554  OldPrimaryDVB = NewPrimaryDVB;
1555  }
1556 
1557  // SIGHUP shall cause a restart:
1558  if (LastSignal == SIGHUP) {
1559  if (ShutdownHandler.ConfirmRestart(true) && Interface->Confirm(tr("Press any key to cancel restart"), RESTARTCANCELPROMPT, true))
1560  EXIT(1);
1561  LastSignal = 0;
1562  }
1563 
1564  // Update the shutdown countdown:
1566  if (!ShutdownHandler.ConfirmShutdown(false))
1568  }
1569 
1570  if (!Control && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
1571  // Shutdown:
1572  // Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
1573  time_t Soon = Now + SHUTDOWNWAIT;
1575  if (ShutdownHandler.ConfirmShutdown(false))
1576  // Time to shut down - start final countdown:
1577  ShutdownHandler.countdown.Start(tr("VDR will shut down in %s minutes"), SHUTDOWNWAIT); // the placeholder is really %s!
1578  // Dont try to shut down again for a while:
1580  }
1581  // Countdown run down to 0?
1582  if (ShutdownHandler.countdown.Done()) {
1583  // Timed out, now do a final check:
1585  ShutdownHandler.DoShutdown(false);
1586  // Do this again a bit later:
1588  }
1589  // Handle housekeeping tasks
1590  if ((Now - LastInteract) > ACTIVITYTIMEOUT) {
1591  // Disk housekeeping:
1595  // Plugins housekeeping:
1596  PluginManager.Housekeeping();
1597  // Memory cleanup:
1598  static time_t LastMemoryCleanup = 0;
1599  if ((Now - LastMemoryCleanup) > MEMCLEANUPDELTA) {
1600  malloc_trim(0);
1601  LastMemoryCleanup = Now;
1602  }
1603  }
1604  }
1605 
1607 
1608  // Main thread hooks of plugins:
1609  PluginManager.MainThreadHook();
1610  }
1611 
1613  esyslog("emergency exit requested - shutting down");
1614 
1615 Exit:
1616 
1617  // Reset all signal handlers to default before Interface gets deleted:
1618  signal(SIGHUP, SIG_DFL);
1619  signal(SIGINT, SIG_DFL);
1620  signal(SIGTERM, SIG_DFL);
1621  signal(SIGPIPE, SIG_DFL);
1622  signal(SIGALRM, SIG_DFL);
1623 
1624  StopSVDRPHandler();
1627  PluginManager.StopPlugins();
1629  delete Menu;
1631  delete Interface;
1633  Remotes.Clear();
1634  Audios.Clear();
1635  Skins.Clear();
1636  SourceParams.Clear();
1637  if (ShutdownHandler.GetExitCode() != 2) {
1640  Setup.Save();
1641  }
1645  EpgHandlers.Clear();
1646  cSchedules::Cleanup(true);
1649  PluginManager.Shutdown(true);
1650  ReportEpgBugFixStats(true);
1651  if (WatchdogTimeout > 0)
1652  dsyslog("max. latency time %d seconds", MaxLatencyTime);
1653  if (LastSignal)
1654  isyslog("caught signal %d", LastSignal);
1656  esyslog("emergency exit!");
1657  isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
1658  if (SysLogLevel > 0)
1659  closelog();
1660  if (HasStdin)
1661  tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
1662 #ifdef SDNOTIFY
1663  if (ShutdownHandler.GetExitCode() == 2)
1664  sd_notify(0, "STOPPING=1\nSTATUS=Startup failed, exiting");
1665  else
1666  sd_notify(0, "STOPPING=1\nSTATUS=Exiting");
1667 #endif
1668  return ShutdownHandler.GetExitCode();
1669 }
cAudios Audios
Definition: audio.c:27
#define CHANNELMOD_ALL
Definition: channels.h:21
#define CHANNELMOD_RETUNE
Definition: channels.h:29
#define CHANNELMOD_TRANSP
Definition: channels.h:27
#define LOCK_CHANNELS_READ
Definition: channels.h:273
#define LOCK_CHANNELS_WRITE
Definition: channels.h:274
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2947
cCamSlots CamSlots
Definition: ci.c:2838
cCiResourceHandlers CiResourceHandlers
Definition: ci.c:1777
bool CamResponsesLoad(const char *FileName, bool AllowComments, bool MustExist)
Definition: ci.c:481
Definition: args.h:17
int GetArgc(void) const
Definition: args.h:30
char ** GetArgv(void) const
Definition: args.h:31
bool ReadDirectory(const char *Directory)
Definition: args.c:39
bool WaitForAllCamSlotsReady(int Timeout=0)
Waits until all CAM slots have become ready, or the given Timeout (seconds) has expired.
Definition: ci.c:2850
void Load(const char *FileName)
Definition: ci.c:3043
void Save(void)
Definition: ci.c:3077
int Vpid(void) const
Definition: channels.h:156
int Number(void) const
Definition: channels.h:181
int Dpid(int i) const
Definition: channels.h:163
int Apid(int i) const
Definition: channels.h:162
bool ModifiedByUser(int &State) const
Returns true if the channels have been modified by the user since the last call to this function with...
Definition: channels.c:1132
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition: channels.c:857
bool SwitchTo(int Number) const
Definition: channels.c:1096
static bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: channels.c:886
static void SetSystemCharacterTable(const char *CharacterTable)
Definition: tools.c:991
bool Save(void) const
Definition: config.h:174
bool Load(const char *FileName=NULL, bool AllowComments=false, bool MustExist=false)
Definition: config.h:127
static void Shutdown(void)
Definition: player.c:108
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition: player.c:58
static void Attach(void)
Definition: player.c:95
static cControl * Control(bool Hidden=false)
Old version of this function, for backwards compatibility with plugins.
Definition: player.c:74
static void Launch(cControl *Control)
Definition: player.c:87
virtual void Hide(void)=0
bool Update(void)
Update status display of the countdown.
Definition: shutdown.c:64
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition: shutdown.c:37
void Cancel(void)
Cancel the 5 minute shutdown warning countdown.
Definition: shutdown.c:46
bool Done(void)
Check if countdown timer has run out without canceling.
Definition: shutdown.c:55
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition: device.c:133
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition: device.c:222
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition: device.c:149
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:230
static void Shutdown(void)
Closes down all devices.
Definition: device.c:465
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:825
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:167
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:371
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition: device.h:223
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition: device.c:194
void StopReplay(void)
Stops the current replay session (if any).
Definition: device.c:1421
void SetVolume(int Volume, bool Absolute=false)
Sets the volume to the given value, either absolutely or relative to the current volume.
Definition: device.c:1076
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:129
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: device.c:212
virtual bool HasProgramme(void) const
Returns true if the device is currently showing any programme to the user, either through replaying o...
Definition: device.c:1016
static int CurrentVolume(void)
Definition: device.h:652
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: device.c:805
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:148
static cDevice * GetDeviceForTransponder(const cChannel *Channel, int Priority)
Returns a device that is not currently "occupied" and can be tuned to the transponder of the given Ch...
Definition: device.c:427
void SetOccupied(int Seconds, int Priority=MINPRIORITY, time_t From=0)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition: device.c:991
bool ToggleMute(void)
Turns the volume off or on and returns the new mute state.
Definition: device.c:1047
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: diseqc.c:441
static bool IsOpen(void)
Definition: menu.h:145
static void Process(eKeys Key)
Definition: menu.c:5354
static bool IsOpen(void)
Definition: menu.h:192
static cDisplaySubtitleTracks * Create(void)
Definition: menu.c:5343
static cDisplayTracks * Create(void)
Definition: menu.c:5225
static void Process(eKeys Key)
Definition: menu.c:5236
static bool IsOpen(void)
Definition: menu.h:174
static cDisplayVolume * Create(void)
Definition: menu.c:5135
static void Process(eKeys Key)
Definition: menu.c:5142
bool Load(const char *FileName)
Definition: recording.c:3245
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:2045
static bool useDvbDevices
Definition: dvbdevice.h:178
static bool Initialize(void)
Initializes the DVB devices.
Definition: dvbdevice.c:1982
bool Active(void)
Definition: eitscan.h:34
void Process(void)
Definition: eitscan.c:144
void Activity(void)
Definition: eitscan.c:134
static cString GetFontFileName(const char *FontName)
Returns the actual font file name for the given FontName.
Definition: font.c:482
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition: interface.c:59
void Interrupt(void)
Definition: interface.h:24
eKeys GetKey(bool Wait=true)
Definition: interface.c:31
void LearnKeys(void)
Definition: interface.c:147
const cKeyMacro * Get(eKeys Key)
Definition: keys.c:269
static void NewLircRemote(const char *Name)
Definition: lirc.c:64
virtual void Clear(void)
Definition: tools.c:2296
void SetSyncStateKey(cStateKey &StateKey)
When making changes to this list (while holding a write lock) that shall not affect some other code t...
Definition: tools.h:612
void Purge(bool Force=false)
Definition: tools.c:2178
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:663
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:656
static cOsdObject * PluginOsdObject(void)
Definition: menu.c:4561
bool Load(const char *FileName)
Definition: config.c:234
virtual bool NeedsFastResponse(void)
Definition: osdbase.h:79
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.h:82
bool IsMenu(void) const
Definition: osdbase.h:80
virtual void Show(void)
Definition: osdbase.c:70
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition: osd.c:2337
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition: osd.c:2397
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition: osd.c:2310
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:837
void StopPlugins(void)
Definition: plugin.c:512
void MainThreadHook(void)
Definition: plugin.c:418
bool StartPlugins(void)
Definition: plugin.c:388
void SetDirectory(const char *Directory)
Definition: plugin.c:324
bool InitializePlugins(void)
Definition: plugin.c:375
void AddPlugin(const char *Args)
Definition: plugin.c:330
static bool HasPlugins(void)
Definition: plugin.c:464
bool LoadPlugins(bool Log=false)
Definition: plugin.c:366
void Shutdown(bool Log=false)
Definition: plugin.c:524
void Housekeeping(void)
Definition: plugin.c:402
static cPlugin * GetPlugin(int Index)
Definition: plugin.c:469
Definition: plugin.h:22
virtual const char * CommandLineHelp(void)
Definition: plugin.c:48
virtual const char * Description(void)=0
const char * Name(void)
Definition: plugin.h:36
static void SetCacheDirectory(const char *Dir)
Definition: plugin.c:149
virtual const char * Version(void)=0
virtual cOsdObject * MainMenuAction(void)
Definition: plugin.c:95
static void SetConfigDirectory(const char *Dir)
Definition: plugin.c:135
static void SetResourceDirectory(const char *Dir)
Definition: plugin.c:163
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition: positioner.c:133
static void DestroyPositioner(void)
Destroys a previously created positioner.
Definition: positioner.c:138
static void ChannelDataModified(const cChannel *Channel)
Definition: menu.c:5707
static bool Process(cTimers *Timers, time_t t)
Definition: menu.c:5692
static bool PauseLiveVideo(void)
Definition: menu.c:5644
static void Shutdown(void)
Definition: menu.c:5733
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition: menu.c:5549
static bool Active(void)
Definition: menu.c:5724
static void SetCommand(const char *Command)
Definition: recording.h:464
void DelAll(void)
Deletes/terminates all operations.
Definition: recording.c:2192
bool Finished(bool &Error)
Returns true if all operations in the list have been finished.
Definition: recording.c:2225
static void Update(bool Wait=false)
Triggers an update of the list of recordings, which will run as a separate thread if Wait is false.
Definition: recording.c:1647
static bool NeedsUpdate(void)
Definition: recording.c:1639
static const char * GetPlugin(void)
Returns the name of the plugin that was set with a previous call to PutMacro() or CallPlugin().
Definition: remote.c:162
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition: remote.c:124
static bool PutMacro(eKeys Key)
Definition: remote.c:110
static time_t LastActivity(void)
Absolute time when last key was delivered by Get().
Definition: remote.h:68
static const char * LastReplayed(void)
Definition: menu.c:5886
Definition: epg.h:152
bool PresentSeenWithin(int Seconds) const
Definition: epg.h:170
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition: epg.c:1286
static void SetEpgDataFileName(const char *FileName)
Definition: epg.c:1296
static void Cleanup(bool Force=false)
Definition: epg.c:1303
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: diseqc.c:184
int SplitEditedFiles
Definition: config.h:347
int CurrentVolume
Definition: config.h:367
int CurrentChannel
Definition: config.h:366
bool Save(void)
Definition: config.c:738
char OSDTheme[MaxThemeName]
Definition: config.h:267
char OSDSkin[MaxSkinName]
Definition: config.h:266
int VpsMargin
Definition: config.h:317
int ZapTimeout
Definition: config.h:307
int RecordKeyHandling
Definition: config.h:312
int PauseKeyHandling
Definition: config.h:313
bool Load(const char *FileName)
Definition: config.c:544
int MenuKeyCloses
Definition: config.h:273
int DiSEqC
Definition: config.h:280
char FontOsd[MAXFONTNAME]
Definition: config.h:337
int MaxVideoFileSize
Definition: config.h:346
cString DeviceBondings
Definition: config.h:377
int PrimaryDVB
Definition: config.h:268
cString InitialChannel
Definition: config.h:376
int InitialVolume
Definition: config.h:371
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition: shutdown.c:104
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition: shutdown.c:121
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition: shutdown.c:157
bool EmergencyExitRequested(void)
Returns true if an emergency exit was requested.
Definition: shutdown.h:61
void SetRetry(int Seconds)
Set shutdown retry so that VDR will not try to automatically shut down within Seconds.
Definition: shutdown.h:93
bool Retry(time_t AtTime=0)
Check whether its time to re-try the shutdown.
Definition: shutdown.h:88
bool IsUserInactive(time_t AtTime=0)
Check whether VDR is in interactive mode or non-interactive mode (waiting for shutdown).
Definition: shutdown.h:72
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition: shutdown.c:233
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition: shutdown.c:209
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition: shutdown.h:54
void SetUserInactiveTimeout(int Seconds=-1, bool Force=false)
Set the time in the future when VDR will switch into non-interactive mode or power down.
Definition: shutdown.c:141
bool DoExit(void)
Check if an exit code was set, and VDR should exit.
Definition: shutdown.h:57
cCountdown countdown
Definition: shutdown.h:51
void SetUserInactive(void)
Set VDR manually into non-interactive mode from now on.
Definition: shutdown.h:86
int GetExitCode(void)
Get the currently set exit code of VDR.
Definition: shutdown.h:59
Definition: skins.h:401
cTheme * Theme(void)
Definition: skins.h:421
const char * Name(void)
Definition: skins.h:420
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition: skins.c:231
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:250
cSkin * Current(void)
Returns a pointer to the current skin.
Definition: skins.h:467
virtual void Clear(void)
Free up all registered skins.
Definition: skins.c:408
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition: skins.c:352
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition: skins.c:296
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:867
void Reset(void)
Resets the state of this key, so that the next call to a lock's Lock() function with this key will re...
Definition: thread.c:862
bool StateChanged(void)
Returns true if this key is used for obtaining a write lock, and the lock's state differs from that o...
Definition: thread.c:877
static void MsgChannelChange(const cChannel *Channel)
Definition: status.c:26
static void SetThemesDirectory(const char *ThemesDirectory)
Definition: themes.c:295
bool Load(const char *SkinName)
Definition: themes.c:239
static void SetMainThreadId(void)
Definition: thread.c:377
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition: thread.c:304
bool Active(void)
Checks whether the thread is still alive.
Definition: thread.c:329
static tThreadId ThreadId(void)
Definition: thread.c:372
Definition: timers.h:31
static bool Load(const char *FileName)
Definition: timers.c:1083
int GetMaxPriority(void) const
Returns the maximum priority of all local timers that are currently recording.
Definition: timers.c:1177
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition: timers.c:1205
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition: timers.c:1200
const cTimer * GetMatch(time_t t) const
Definition: timers.c:1127
bool SpawnPatternTimers(const cSchedules *Schedules)
Definition: timers.c:1249
bool DeleteExpired(bool Force)
Definition: timers.c:1275
bool SetEvents(const cSchedules *Schedules)
Definition: timers.c:1239
bool AdjustSpawnedTimers(void)
Definition: timers.c:1261
static void Destroy(void)
Definition: videodir.c:50
static void SetName(const char *Name)
Definition: videodir.c:65
cNestedItemList Commands
Definition: config.c:275
cSetup Setup
Definition: config.c:372
cSVDRPhosts SVDRPhosts
Definition: config.c:280
cNestedItemList Folders
Definition: config.c:274
cNestedItemList RecordingCommands
Definition: config.c:276
#define MINPRIORITY
Definition: config.h:44
#define VDRVERSION
Definition: config.h:25
#define APIVERSION
Definition: config.h:30
#define LIVEPRIORITY
Definition: config.h:45
bool CutRecording(const char *FileName)
Definition: cutter.c:728
#define MAXDEVICES
Definition: device.h:29
#define VOLUMEDELTA
Definition: device.h:33
cDiseqcs Diseqcs
Definition: diseqc.c:439
cScrs Scrs
Definition: diseqc.c:182
cEITScanner EITScanner
Definition: eitscan.c:104
cEpgHandlers EpgHandlers
Definition: epg.c:1446
void ReportEpgBugFixStats(bool Force)
Definition: epg.c:611
#define LOCK_SCHEDULES_READ
Definition: epg.h:233
void I18nInitialize(const char *LocaleDir)
Detects all available locales and loads the language names and codes.
Definition: i18n.c:142
#define tr(s)
Definition: i18n.h:85
cInterface * Interface
Definition: interface.c:20
cKeyMacros KeyMacros
Definition: keys.c:267
cKeys Keys
Definition: keys.c:156
#define ISMODELESSKEY(k)
Definition: keys.h:80
#define ISREALKEY(k)
Definition: keys.h:81
#define NORMALKEY(k)
Definition: keys.h:79
eKeys
Definition: keys.h:16
@ kPower
Definition: keys.h:39
@ kRecord
Definition: keys.h:34
@ kSchedule
Definition: keys.h:48
@ kUser9
Definition: keys.h:54
@ kPlayPause
Definition: keys.h:30
@ kCommands
Definition: keys.h:53
@ kRight
Definition: keys.h:23
@ kRecordings
Definition: keys.h:51
@ kPause
Definition: keys.h:32
@ k9
Definition: keys.h:28
@ kSetup
Definition: keys.h:52
@ kUp
Definition: keys.h:17
@ kChanUp
Definition: keys.h:40
@ kNone
Definition: keys.h:55
@ kPlay
Definition: keys.h:31
@ kChanPrev
Definition: keys.h:42
@ kDown
Definition: keys.h:18
@ k1
Definition: keys.h:28
@ kSubtitles
Definition: keys.h:47
@ kLeft
Definition: keys.h:22
@ k_Plugin
Definition: keys.h:58
@ kAudio
Definition: keys.h:46
@ kMute
Definition: keys.h:45
@ kPrev
Definition: keys.h:38
@ k0
Definition: keys.h:28
@ kChannels
Definition: keys.h:49
@ kTimers
Definition: keys.h:50
@ kMenu
Definition: keys.h:19
@ k_Repeat
Definition: keys.h:61
@ kChanDn
Definition: keys.h:41
@ kVolDn
Definition: keys.h:44
@ kNext
Definition: keys.h:37
@ kOk
Definition: keys.h:20
@ kVolUp
Definition: keys.h:43
@ kInfo
Definition: keys.h:29
@ kUser0
Definition: keys.h:54
bool CamMenuActive(void)
Definition: menu.c:2499
cOsdObject * CamControl(void)
Definition: menu.c:2490
bool SetSystemCharacterTable(const char *CharacterTable)
Definition: si.c:339
static char * OverrideCharacterTable
Definition: si.c:322
bool SetOverrideCharacterTable(const char *CharacterTable)
Definition: si.c:324
eOSState
Definition: osdbase.h:18
@ osRecordings
Definition: osdbase.h:23
@ osPause
Definition: osdbase.h:27
@ osPlugin
Definition: osdbase.h:24
@ osChannels
Definition: osdbase.h:21
@ osStopReplay
Definition: osdbase.h:31
@ osRecord
Definition: osdbase.h:28
@ osEnd
Definition: osdbase.h:34
@ osSetup
Definition: osdbase.h:25
@ osTimers
Definition: osdbase.h:22
@ osReplay
Definition: osdbase.h:29
@ osUnknown
Definition: osdbase.h:18
@ osSchedule
Definition: osdbase.h:20
@ osCommands
Definition: osdbase.h:26
@ osBack
Definition: osdbase.h:33
int DirectoryNameMax
Definition: recording.c:75
bool GenerateIndex(const char *FileName, bool Update)
Generates the index of the existing recording with the given FileName.
Definition: recording.c:3049
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition: recording.c:152
int DirectoryPathMax
Definition: recording.c:74
int InstanceId
Definition: recording.c:77
bool DirectoryEncoding
Definition: recording.c:76
cDoneRecordings DoneRecordingsPattern
Definition: recording.c:3243
cRecordingsHandler RecordingsHandler
Definition: recording.c:2102
void RemoveDeletedRecordings(void)
Definition: recording.c:135
#define MAXVIDEOFILESIZEDEFAULT
Definition: recording.h:479
#define MAXVIDEOFILESIZETS
Definition: recording.h:476
#define MINVIDEOFILESIZE
Definition: recording.h:478
cRemotes Remotes
Definition: remote.c:211
cShutdownHandler ShutdownHandler
Definition: shutdown.c:27
cSkins Skins
Definition: skins.c:219
@ mtWarning
Definition: skins.h:37
@ mtInfo
Definition: skins.h:37
@ mtError
Definition: skins.h:37
cSourceParams SourceParams
Definition: sourceparams.c:34
cSources Sources
Definition: sources.c:117
static tChannelID FromString(const char *s)
Definition: channels.c:24
void StopSVDRPHandler(void)
Definition: svdrp.c:2839
void SetSVDRPGrabImageDir(const char *GrabImageDir)
Definition: svdrp.c:2741
void StartSVDRPHandler(void)
Definition: svdrp.c:2823
void SetSVDRPPorts(int TcpPort, int UdpPort)
Definition: svdrp.c:2735
cStateKey StateKeySVDRPRemoteTimersPoll
Controls whether a change to the local list of timers needs to result in sending a POLL to the remote...
@ tfActive
Definition: timers.h:19
@ tfVps
Definition: timers.h:21
int SysLogLevel
Definition: tools.c:31
bool DirectoryOk(const char *DirName, bool LogErrors)
Definition: tools.c:486
bool isnumber(const char *s)
Definition: tools.c:369
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:407
cListGarbageCollector ListGarbageCollector
Definition: tools.c:2155
int64_t StrToNum(const char *s)
Converts the given string to a number.
Definition: tools.c:380
#define MEGABYTE(n)
Definition: tools.h:45
#define dsyslog(a...)
Definition: tools.h:37
#define esyslog(a...)
Definition: tools.h:35
#define isyslog(a...)
Definition: tools.h:36
static bool SetUser(const char *User, bool UserDump)
Definition: vdr.c:98
#define SHUTDOWNFORCEPROMPT
Definition: vdr.c:81
static int LastSignal
Definition: vdr.c:96
int main(int argc, char *argv[])
Definition: vdr.c:198
#define DEFAULTRESDIR
#define DEFAULTWATCHDOG
#define DEFAULTARGSDIR
#define MEMCLEANUPDELTA
Definition: vdr.c:78
#define MANUALSTART
Definition: vdr.c:84
#define DEFAULTLOCDIR
#define TIMERLOOKAHEADTIME
Definition: vdr.c:90
#define DEFAULTPLUGINDIR
#define CHANNELSAVEDELTA
Definition: vdr.c:85
#define SHUTDOWNCANCELPROMPT
Definition: vdr.c:82
#define SHUTDOWNWAIT
Definition: vdr.c:79
#define DEFAULTEPGDATAFILENAME
static void SignalHandler(int signum)
Definition: vdr.c:171
#define DEFAULTCONFDIR
static bool SetKeepCaps(bool On)
Definition: vdr.c:161
#define DEFAULTVIDEODIR
#define VPSLOOKAHEADTIME
Definition: vdr.c:91
#define DirectMainFunction(function)
#define MINCHANNELWAIT
Definition: vdr.c:76
#define TIMERDEVICETIMEOUT
Definition: vdr.c:89
static bool DropCaps(void)
Definition: vdr.c:128
#define MENUTIMEOUT
Definition: vdr.c:87
static void Watchdog(int signum)
Definition: vdr.c:187
#define RESTARTCANCELPROMPT
Definition: vdr.c:83
#define EXIT(v)
Definition: vdr.c:94
#define DEFAULTCACHEDIR
#define DEVICEREADYTIMEOUT
Definition: vdr.c:86
#define TIMERCHECKDELTA
Definition: vdr.c:88
#define ACTIVITYTIMEOUT
Definition: vdr.c:77
#define VPSUPTODATETIME
Definition: vdr.c:92
#define DELETE_MENU
#define SHUTDOWNRETRY
Definition: vdr.c:80
#define DEFAULTSVDRPPORT