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