35 #include <sys/capability.h>
36 #include <sys/prctl.h>
38 #include <systemd/sd-daemon.h>
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
92 #define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
96 static bool SetUser(
const char *User,
bool UserDump)
99 struct passwd *user =
isnumber(User) ? getpwuid(atoi(User)) : getpwnam(User);
101 fprintf(stderr,
"vdr: unknown user: '%s'\n", User);
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));
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));
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));
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);
129 cap_t caps_all = cap_get_proc();
131 fprintf(stderr,
"vdr: cap_get_proc failed: %s\n", strerror(errno));
134 char *caps_text = cap_to_text(caps_all, NULL);
136 fprintf(stderr,
"vdr: cap_to_text failed: %s\n", strerror(errno));
139 if (cap_free(caps_all)) {
140 fprintf(stderr,
"vdr: cap_free failed: %s\n", strerror(errno));
144 if (strstr(caps_text,
"cap_sys_time"))
145 caps = cap_from_text(
"= cap_sys_nice,cap_sys_time,cap_net_raw=ep");
147 caps = cap_from_text(
"= cap_sys_nice,cap_net_raw=ep");
149 fprintf(stderr,
"vdr: cap_from_text failed: %s\n", strerror(errno));
152 if (cap_set_proc(caps) == -1) {
153 fprintf(stderr,
"vdr: cap_set_proc failed: %s\n", strerror(errno));
164 if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
165 fprintf(stderr,
"vdr: prctl failed\n");
191 esyslog(
"PANIC: watchdog timer expired - exiting!");
193 sd_notify(0,
"STOPPING=1\nSTATUS=PANIC");
198 int main(
int argc,
char *argv[])
202 struct termios savedTm;
203 bool HasStdin = (tcgetpgrp(STDIN_FILENO) == getpid() || getppid() != (pid_t)1) && tcgetattr(STDIN_FILENO, &savedTm) == 0;
207 setlocale(LC_ALL,
"");
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"
223 bool StartedAsRoot =
false;
224 const char *VdrUser = NULL;
225 bool UserDump =
false;
227 const char *AudioCommand = NULL;
229 const char *ConfigDirectory = NULL;
230 const char *CacheDirectory = NULL;
231 const char *ResourceDirectory = NULL;
234 bool DisplayHelp =
false;
235 bool DisplayVersion =
false;
236 bool DaemonMode =
false;
237 int SysLogTarget = LOG_USER;
238 bool MuteAudio =
false;
240 const char *Terminal = NULL;
242 #ifndef DEPRECATED_VDR_CHARSET_OVERRIDE
243 #define DEPRECATED_VDR_CHARSET_OVERRIDE 0
245 #if DEPRECATED_VDR_CHARSET_OVERRIDE
251 const char *LircDevice = NULL;
252 #if !defined(REMOTE_KBD)
255 #if defined(REMOTE_LIRC)
256 LircDevice = LIRC_DEVICE;
258 #if defined(VDR_USER)
262 time_t SdWatchdog = 0;
263 int SdWatchdogTimeout = 0;
268 Args =
new cArgs(argv[0]);
278 static struct option long_options[] = {
279 {
"audio", required_argument, NULL,
'a' },
280 {
"cachedir", required_argument, NULL,
'c' | 0x100 },
281 {
"chartab", required_argument, NULL,
'c' | 0x200 },
282 {
"config", required_argument, NULL,
'c' },
283 {
"daemon", no_argument, NULL,
'd' },
284 {
"device", required_argument, NULL,
'D' },
285 {
"dirnames", required_argument, NULL,
'd' | 0x100 },
286 {
"edit", required_argument, NULL,
'e' | 0x100 },
287 {
"epgfile", required_argument, NULL,
'E' },
288 {
"filesize", required_argument, NULL,
'f' | 0x100 },
289 {
"genindex", required_argument, NULL,
'g' | 0x100 },
290 {
"grab", required_argument, NULL,
'g' },
291 {
"help", no_argument, NULL,
'h' },
292 {
"instance", required_argument, NULL,
'i' },
293 {
"lib", required_argument, NULL,
'L' },
294 {
"lirc", optional_argument, NULL,
'l' | 0x100 },
295 {
"localedir",required_argument, NULL,
'l' | 0x200 },
296 {
"log", required_argument, NULL,
'l' },
297 {
"mute", no_argument, NULL,
'm' },
298 {
"no-kbd", no_argument, NULL,
'n' | 0x100 },
299 {
"plugin", required_argument, NULL,
'P' },
300 {
"port", required_argument, NULL,
'p' },
301 {
"record", required_argument, NULL,
'r' },
302 {
"resdir", required_argument, NULL,
'r' | 0x100 },
303 {
"showargs", optional_argument, NULL,
's' | 0x200 },
304 {
"shutdown", required_argument, NULL,
's' },
305 {
"split", no_argument, NULL,
's' | 0x100 },
306 {
"terminal", required_argument, NULL,
't' },
307 {
"updindex", required_argument, NULL,
'u' | 0x200 },
308 {
"user", required_argument, NULL,
'u' },
309 {
"userdump", no_argument, NULL,
'u' | 0x100 },
310 {
"version", no_argument, NULL,
'V' },
311 {
"vfat", no_argument, NULL,
'v' | 0x100 },
312 {
"video", required_argument, NULL,
'v' },
313 {
"watchdog", required_argument, NULL,
'w' },
314 { NULL, no_argument, NULL, 0 }
318 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) {
320 case 'a': AudioCommand = optarg;
323 CacheDirectory = optarg;
328 case 'c': ConfigDirectory = optarg;
330 case 'd': DaemonMode =
true;
332 case 'D':
if (*optarg ==
'-') {
337 int n = atoi(optarg);
343 fprintf(stderr,
"vdr: invalid DVB device number: %s\n", optarg);
348 int n = strtol(s, &s, 10);
349 if (n <= 0 || n >= PATH_MAX) {
350 fprintf(stderr,
"vdr: invalid directory path length: %s\n", optarg);
357 fprintf(stderr,
"vdr: invalid delimiter: %s\n", optarg);
365 int n = strtol(s, &s, 10);
366 if (n <= 0 || n > NAME_MAX) {
367 fprintf(stderr,
"vdr: invalid directory name length: %s\n", optarg);
374 fprintf(stderr,
"vdr: invalid delimiter: %s\n", optarg);
381 int n = strtol(s, &s, 10);
382 if (n != 0 && n != 1) {
383 fprintf(stderr,
"vdr: invalid directory encoding: %s\n", optarg);
388 fprintf(stderr,
"vdr: unexpected data: %s\n", optarg);
395 case 'E': EpgDataFileName = (*optarg !=
'-' ? optarg : NULL);
408 case 'h': DisplayHelp =
true;
415 fprintf(stderr,
"vdr: invalid instance id: %s\n", optarg);
418 char *p = strchr(optarg,
'.');
422 int l = atoi(optarg);
423 if (0 <= l && l <= 3) {
429 if (0 <= l && l <= 7) {
430 int targets[] = { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
431 SysLogTarget = targets[l];
439 fprintf(stderr,
"vdr: invalid log level: %s\n", optarg);
442 case 'L':
if (access(optarg, R_OK | X_OK) == 0)
445 fprintf(stderr,
"vdr: can't access plugin directory: %s\n", optarg);
450 LircDevice = optarg ? optarg : LIRC_DEVICE;
453 if (access(optarg, R_OK | X_OK) == 0)
454 LocaleDirectory = optarg;
456 fprintf(stderr,
"vdr: can't access locale directory: %s\n", optarg);
460 case 'm': MuteAudio =
true;
466 SVDRPport = atoi(optarg);
468 fprintf(stderr,
"vdr: invalid port number: %s\n", optarg);
472 case 'P': PluginManager.
AddPlugin(optarg);
477 ResourceDirectory = optarg;
488 fprintf(stderr,
"vdr: can't read arguments from directory: %s\n", ArgsDir);
493 for (
int i = 1; i < c; i++)
494 printf(
"%s\n", v[i]);
497 case 't': Terminal = optarg;
498 if (access(Terminal, R_OK | W_OK) < 0) {
499 fprintf(stderr,
"vdr: can't access terminal: %s\n", Terminal);
503 case 'u':
if (*optarg)
511 case 'V': DisplayVersion =
true;
518 case 'v': VideoDirectory = optarg;
519 while (optarg && *optarg && optarg[strlen(optarg) - 1] ==
'/')
520 optarg[strlen(optarg) - 1] = 0;
524 int t = atoi(optarg);
530 fprintf(stderr,
"vdr: invalid watchdog timeout: %s\n", optarg);
538 if (VdrUser && geteuid() == 0) {
539 StartedAsRoot =
true;
540 if (strcmp(VdrUser,
"root") && strcmp(VdrUser,
"0")) {
543 if (!
SetUser(VdrUser, UserDump))
554 if (DisplayHelp || DisplayVersion) {
559 printf(
"Usage: vdr [OPTIONS]\n\n"
560 " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
561 " --cachedir=DIR save cache files in DIR (default: %s)\n"
562 " --chartab=CHARACTER_TABLE\n"
563 " set the character table to use for strings in the\n"
564 " DVB data stream that don't begin with a character\n"
565 " table indicator, but don't use the standard default\n"
566 " character table (for instance ISO-8859-9)\n"
567 " -c DIR, --config=DIR read config files from DIR (default: %s)\n"
568 " -d, --daemon run in daemon mode\n"
569 " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
570 " there may be several -D options (default: all DVB\n"
571 " devices will be used); if -D- is given, no DVB\n"
572 " devices will be used at all, independent of any\n"
573 " other -D options\n"
574 " --dirnames=PATH[,NAME[,ENC]]\n"
575 " set the maximum directory path length to PATH\n"
576 " (default: %d); if NAME is also given, it defines\n"
577 " the maximum directory name length (default: %d);\n"
578 " the optional ENC can be 0 or 1, and controls whether\n"
579 " special characters in directory names are encoded as\n"
580 " hex values (default: 0); if PATH or NAME are left\n"
581 " empty (as in \",,1\" to only set ENC), the defaults\n"
583 " --edit=REC cut recording REC and exit\n"
584 " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
585 " '%s' in the cache directory)\n"
586 " '-E-' disables this\n"
587 " if FILE is a directory, the default EPG file will be\n"
588 " created in that directory\n"
589 " --filesize=SIZE limit video files to SIZE bytes (default is %dM)\n"
590 " only useful in conjunction with --edit\n"
591 " --genindex=REC generate index for recording REC and exit\n"
592 " -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
593 " given DIR; DIR must be the full path name of an\n"
594 " existing directory, without any \"..\", double '/'\n"
595 " or symlinks (default: none, same as -g-)\n"
596 " -h, --help print this help and exit\n"
597 " -i ID, --instance=ID use ID as the id of this VDR instance (default: 0)\n"
598 " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
599 " 0 = no logging, 1 = errors only,\n"
600 " 2 = errors and info, 3 = errors, info and debug\n"
601 " if logging should be done to LOG_LOCALn instead of\n"
602 " LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7)\n"
603 " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n"
604 " --lirc[=PATH] use a LIRC remote control device, attached to PATH\n"
606 " --localedir=DIR search for locale files in DIR (default is\n"
608 " -m, --mute mute audio of the primary DVB device at startup\n"
609 " --no-kbd don't use the keyboard as an input device\n"
610 " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
611 " 0 turns off SVDRP\n"
612 " -P OPT, --plugin=OPT load a plugin defined by the given options\n"
613 " -r CMD, --record=CMD call CMD before and after a recording, and after\n"
614 " a recording has been edited or deleted\n"
615 " --resdir=DIR read resource files from DIR (default: %s)\n"
616 " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
617 " --split split edited files at the editing marks (only\n"
618 " useful in conjunction with --edit)\n"
619 " --showargs[=DIR] print the arguments read from DIR and exit\n"
621 " -t TTY, --terminal=TTY controlling tty\n"
622 " -u USER, --user=USER run as user USER; only applicable if started as\n"
623 " root; USER can be a user name or a numerical id\n"
624 " --updindex=REC update index for recording REC and exit\n"
625 " --userdump allow coredumps if -u is given (debugging)\n"
626 " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
627 " -V, --version print version information and exit\n"
628 " --vfat for backwards compatibility (same as\n"
629 " --dirnames=250,40,1)\n"
630 " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
631 " seconds (default: %d); '0' disables the watchdog\n"
653 printf(
"Plugins: vdr -P\"name [OPTIONS]\"\n\n");
654 for (
int i = 0; ; i++) {
659 if (DisplayHelp && help) {
674 openlog(
"vdr", LOG_CONS, SysLogTarget);
679 fprintf(stderr,
"vdr: can't access video directory %s\n", VideoDirectory);
686 if (daemon(1, 0) == -1) {
687 fprintf(stderr,
"vdr: %m\n");
694 stdin = freopen(Terminal,
"r", stdin);
695 stdout = freopen(Terminal,
"w", stdout);
696 stderr = freopen(Terminal,
"w", stderr);
698 tcgetattr(STDIN_FILENO, &savedTm);
702 if (StartedAsRoot && VdrUser)
703 isyslog(
"switched to user '%s'", VdrUser);
710 char *CodeSet = NULL;
711 if (setlocale(LC_CTYPE,
""))
712 CodeSet = nl_langinfo(CODESET);
714 char *LangEnv = getenv(
"LANG");
716 CodeSet = strchr(LangEnv,
'.');
723 isyslog(
"codeset is '%s' - %s", CodeSet, known ?
"known" :
"unknown");
726 #if DEPRECATED_VDR_CHARSET_OVERRIDE
727 if (DeprecatedVdrCharsetOverride)
728 isyslog(
"use of environment variable VDR_CHARSET_OVERRIDE (%s) is deprecated!", DeprecatedVdrCharsetOverride);
744 int LastTimerChannel = -1;
745 int PreviousChannel[2] = { 1, 1 };
746 int PreviousChannelIndex = 0;
747 time_t LastChannelChanged = time(NULL);
748 time_t LastInteract = 0;
749 int MaxLatencyTime = 0;
750 bool InhibitEpgScan =
false;
751 bool IsInfoMenu =
false;
752 cSkin *CurrentSkin = NULL;
753 int OldPrimaryDVB = 0;
762 if (!ConfigDirectory)
768 if (!ResourceDirectory)
790 const char *msg =
"no fonts available - OSD will not show any text!";
791 fprintf(stderr,
"vdr: %s\n", msg);
801 if (EpgDataFileName) {
802 const char *EpgDirectory = NULL;
804 EpgDirectory = EpgDataFileName;
807 else if (*EpgDataFileName !=
'/' && *EpgDataFileName !=
'.')
808 EpgDirectory = CacheDirectory;
813 EpgDataReader.
Start();
829 if (!cDevice::PrimaryDevice() || !cDevice::PrimaryDevice()->HasDecoder()) {
830 if (cDevice::PrimaryDevice() && !cDevice::PrimaryDevice()->HasDecoder())
831 isyslog(
"device %d has no MPEG decoder", cDevice::PrimaryDevice()->DeviceNumber() + 1);
832 for (
int i = 0; i < cDevice::NumDevices(); i++) {
835 isyslog(
"trying device number %d instead", i + 1);
842 if (!cDevice::PrimaryDevice()) {
843 const char *msg =
"no primary device found - using first device!";
844 fprintf(stderr,
"vdr: %s\n", msg);
848 if (!cDevice::PrimaryDevice()) {
849 const char *msg =
"no primary device found - giving up!";
850 fprintf(stderr,
"vdr: %s\n", msg);
873 CurrentSkin =
Skins.Current();
882 if (!CurrentSkin || CurrentSkin ==
Skins.Current() && strcmp(
Skins.Current()->Name(),
Setup.
OSDSkin) != 0) {
890 if (!DaemonMode && HasStdin && UseKbd)
930 cDevice::PrimaryDevice()->ToggleMute();
936 if (signal(SIGHUP,
SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
937 if (signal(SIGINT,
SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
938 if (signal(SIGTERM,
SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
939 if (signal(SIGPIPE,
SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
940 if (WatchdogTimeout > 0)
941 if (signal(SIGALRM,
Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN);
945 if (WatchdogTimeout > 0) {
946 dsyslog(
"setting watchdog timer to %d seconds", WatchdogTimeout);
947 alarm(WatchdogTimeout);
951 if (sd_watchdog_enabled(0, NULL) > 0) {
953 SdWatchdog = time(NULL);
954 sd_watchdog_enabled(0, &timeout);
955 SdWatchdogTimeout = (int)timeout/1000000;
956 dsyslog(
"SD_WATCHDOG enabled with timeout set to %d seconds", SdWatchdogTimeout);
961 sd_notify(0,
"READY=1\nSTATUS=Ready");
971 #define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
974 #ifdef DEBUGRINGBUFFERS
975 cRingBufferLinear::PrintDebugRBL();
980 time_t Now = time(NULL);
984 static time_t lastTime = 0;
985 if (!cDevice::PrimaryDevice()->HasProgramme()) {
988 const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel());
989 if (Channel && (Channel->
Vpid() || Channel->
Apid(0) || Channel->
Dpid(0))) {
992 else if (LastTimerChannel > 0) {
993 Channel = Channels->GetByNumber(LastTimerChannel);
999 LastTimerChannel = -1;
1007 static time_t lastOsdSizeUpdate = 0;
1008 if (Now != lastOsdSizeUpdate) {
1010 static int OsdState = 0;
1015 lastOsdSizeUpdate = Now;
1019 if (WatchdogTimeout > 0) {
1020 int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
1021 if (LatencyTime > MaxLatencyTime) {
1022 MaxLatencyTime = LatencyTime;
1023 dsyslog(
"max. latency time %d seconds", MaxLatencyTime);
1028 if (SdWatchdogTimeout && (Now - SdWatchdog) * 2 > SdWatchdogTimeout) {
1029 sd_notify(0,
"WATCHDOG=1");
1035 static bool ChannelsRenumber =
false;
1039 static time_t ChannelSaveTimeout = 0;
1041 static cStateKey ChannelsStateKey(
true);
1042 static int ChannelsModifiedByUser = 0;
1045 if (ChannelSaveTimeout != 1) {
1048 ChannelSaveTimeout = 1;
1049 else if (!ChannelSaveTimeout)
1053 ChannelSaveTimeout = 1;
1056 ChannelSaveTimeout = 1;
1057 if (Timers && Channels) {
1060 ChannelSaveTimeout = 0;
1063 for (
const cChannel *Channel = Channels->First(); Channel; Channel = Channels->
Next(Channel)) {
1066 ChannelsRenumber =
true;
1069 if (Channel->Number() == cDevice::CurrentChannel() && cDevice::PrimaryDevice()->HasDecoder()) {
1070 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) {
1072 isyslog(
"retuning due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
1073 Channels->
SwitchTo(Channel->Number());
1083 ChannelsStateKey.
Remove();
1086 if (ChannelSaveTimeout == 1) {
1088 ChannelsStateKey.
Reset();
1089 TimersStateKey.
Reset();
1095 Menu =
new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0);
1096 LastChannel = cDevice::CurrentChannel();
1097 LastChannelChanged = Now;
1099 if (Now - LastChannelChanged >=
Setup.
ZapTimeout && LastChannel != PreviousChannel[PreviousChannelIndex])
1100 PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
1109 SchedulesStateKey.
Reset();
1110 bool TimersModified =
false;
1114 TimersModified =
true;
1115 SchedulesStateKey.
Remove();
1117 TimersStateKey.
Remove(TimersModified);
1122 bool TimersModified =
false;
1124 TimersModified =
true;
1128 Timer->SetPending(
true);
1130 LastTimerChannel = Timer->Channel()->Number();
1131 TimersModified =
true;
1134 static time_t LastTimerCheck = 0;
1136 InhibitEpgScan =
false;
1137 for (
cTimer *Timer = Timers->First(); Timer; Timer = Timers->
Next(Timer)) {
1138 if (Timer->Remote())
1140 bool InVpsMargin =
false;
1141 bool NeedsTransponder =
false;
1142 if (Timer->HasFlags(
tfActive) && !Timer->Recording()) {
1143 if (Timer->HasFlags(
tfVps)) {
1146 Timer->SetInVpsMargin(InVpsMargin);
1148 else if (Timer->Event()) {
1149 InVpsMargin = Timer->Event()->StartTime() <= Now && Now < Timer->Event()->EndTime();
1154 const cSchedule *Schedule = Schedules->GetSchedule(Timer->Channel());
1155 InVpsMargin = !Schedule;
1158 InhibitEpgScan |= InVpsMargin | NeedsTransponder;
1163 if (NeedsTransponder || InVpsMargin) {
1166 if (!Device && InVpsMargin)
1170 bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
1173 cDevice::PrimaryDevice()->StopReplay();
1174 dsyslog(
"switching device %d to channel %d %s (%s)", Device->
DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
1178 if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme())
1183 LastTimerCheck = Now;
1187 TimersModified =
true;
1190 if (MaxPriority >= 0)
1192 TimersStateKey.
Remove(TimersModified);
1195 if (ChannelsRenumber) {
1197 Channels->ReNumber();
1198 ChannelsRenumber =
false;
1206 if (!Menu && !cOsd::IsOpen())
1226 bool WasOpen = Interact != NULL;
1227 bool WasMenu = Interact && Interact->
IsMenu();
1265 #define DirectMainFunction(function)\
1267 if (cControl::Control())\
1268 cControl::Control()->Hide();\
1269 Menu = new cMenuMain(function);\
1270 key = kNone; } // nobody else needs to see this key
1291 esyslog(
"ERROR: unknown plugin '%s'", PluginName);
1319 if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu) {
1326 if (!Menu && !cOsd::IsOpen())
1383 isyslog(
"Power button pressed");
1417 if (state ==
osEnd) {
1423 else if (Now - cRemote::LastActivity() >
MENUTIMEOUT)
1454 case osEnd:
if (Interact == Menu)
1472 if (PreviousChannel[PreviousChannelIndex ^ 1] == LastChannel || LastChannel != PreviousChannel[0] && LastChannel != PreviousChannel[1])
1473 PreviousChannelIndex ^= 1;
1475 Channels->SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]);
1498 case kOk: LastChannel = -1;
break;
1512 if (!InhibitEpgScan)
1525 if (NewPrimaryDVB != OldPrimaryDVB) {
1531 OldPrimaryDVB = NewPrimaryDVB;
1584 esyslog(
"emergency exit requested - shutting down");
1589 signal(SIGHUP, SIG_DFL);
1590 signal(SIGINT, SIG_DFL);
1591 signal(SIGTERM, SIG_DFL);
1592 signal(SIGPIPE, SIG_DFL);
1593 signal(SIGALRM, SIG_DFL);
1622 if (WatchdogTimeout > 0)
1623 dsyslog(
"max. latency time %d seconds", MaxLatencyTime);
1632 tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
1635 sd_notify(0,
"STOPPING=1\nSTATUS=Startup failed, exiting");
1637 sd_notify(0,
"STOPPING=1\nSTATUS=Exiting");