2000-02-19 13:36:48 +01:00
/*
2000-04-24 09:46:05 +02:00
* vdr . c : Video Disk Recorder main program
2000-02-19 13:36:48 +01:00
*
2013-03-11 11:51:27 +01:00
* Copyright ( C ) 2000 , 2003 , 2006 , 2008 , 2013 Klaus Schmidinger
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2006-04-21 14:53:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2007-08-12 11:25:05 +02:00
* Or , point your browser to http : //www.gnu.org/licenses/old-licenses/gpl-2.0.html
2001-08-03 14:18:08 +02:00
*
2013-03-11 11:25:01 +01:00
* The author can be reached at vdr @ tvdr . de
2000-02-19 13:36:48 +01:00
*
2009-10-18 14:18:22 +02:00
* The project ' s page is at http : //www.tvdr.de
2000-02-19 13:36:48 +01:00
*
2017-04-03 12:49:56 +02:00
* $ Id : vdr . c 4.12 2017 / 04 / 03 12 : 35 : 37 kls Exp $
2000-02-19 13:36:48 +01:00
*/
2000-07-23 15:01:31 +02:00
# include <getopt.h>
2005-12-31 13:30:11 +01:00
# include <grp.h>
2007-06-15 13:25:35 +02:00
# include <langinfo.h>
2001-10-07 11:00:35 +02:00
# include <locale.h>
2005-12-31 13:30:11 +01:00
# include <pwd.h>
2000-04-15 17:38:11 +02:00
# include <signal.h>
2000-07-23 15:01:31 +02:00
# include <stdlib.h>
2005-12-31 13:30:11 +01:00
# include <sys/capability.h>
# include <sys/prctl.h>
2014-03-16 12:53:47 +01:00
# ifdef SDNOTIFY
# include <systemd/sd-daemon.h>
# endif
2002-12-08 14:30:32 +01:00
# include <termios.h>
2000-07-23 15:36:43 +02:00
# include <unistd.h>
2014-04-14 13:15:34 +02:00
# include "args.h"
2002-11-03 11:53:58 +01:00
# include "audio.h"
2002-10-06 10:25:42 +02:00
# include "channels.h"
2000-02-19 13:36:48 +01:00
# include "config.h"
2002-06-22 10:11:59 +02:00
# include "cutter.h"
2002-06-16 12:57:31 +02:00
# include "device.h"
2002-10-06 10:25:42 +02:00
# include "diseqc.h"
2002-08-04 14:57:29 +02:00
# include "dvbdevice.h"
2002-05-20 11:18:09 +02:00
# include "eitscan.h"
2003-12-22 13:29:24 +01:00
# include "epg.h"
2000-11-11 10:39:27 +01:00
# include "i18n.h"
2000-02-19 13:36:48 +01:00
# include "interface.h"
2002-09-29 13:40:45 +02:00
# include "keys.h"
2006-06-16 09:22:20 +02:00
# include "libsi/si.h"
2002-09-29 13:40:45 +02:00
# include "lirc.h"
2000-02-19 13:36:48 +01:00
# include "menu.h"
2004-05-16 10:35:36 +02:00
# include "osdbase.h"
2002-05-09 16:26:56 +02:00
# include "plugin.h"
2000-03-11 11:22:37 +01:00
# include "recording.h"
2007-02-25 10:56:29 +01:00
# include "shutdown.h"
2004-05-16 10:35:36 +02:00
# include "skinclassic.h"
2012-06-02 13:17:16 +02:00
# include "skinlcars.h"
2004-05-16 10:35:36 +02:00
# include "skinsttng.h"
2010-02-28 12:19:50 +01:00
# include "sourceparams.h"
2002-10-06 10:25:42 +02:00
# include "sources.h"
2014-01-25 10:54:51 +01:00
# include "status.h"
2015-04-29 13:10:06 +02:00
# include "svdrp.h"
2004-05-16 10:35:36 +02:00
# include "themes.h"
2002-10-20 12:28:55 +02:00
# include "timers.h"
2000-02-19 13:36:48 +01:00
# include "tools.h"
2004-01-17 17:19:34 +01:00
# include "transfer.h"
2000-07-29 15:21:42 +02:00
# include "videodir.h"
2000-02-19 13:36:48 +01:00
2007-07-22 11:40:01 +02:00
# define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
# define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
# define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
# define SHUTDOWNRETRY 360 // seconds before trying again to shut down
# define SHUTDOWNFORCEPROMPT 5 // seconds to wait in user prompt to allow forcing shutdown
# define SHUTDOWNCANCELPROMPT 5 // seconds to wait in user prompt to allow canceling shutdown
# define RESTARTCANCELPROMPT 5 // seconds to wait in user prompt before restarting on SIGHUP
# define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
# define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
# define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
# define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
# define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
# define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
# define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
# define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
# define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
2001-02-11 14:53:44 +01:00
2007-02-25 10:56:29 +01:00
# define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
2004-10-23 15:17:03 +02:00
2007-02-25 10:56:29 +01:00
static int LastSignal = 0 ;
2000-04-15 17:38:11 +02:00
2015-04-19 12:50:26 +02:00
static bool SetUser ( const char * User , bool UserDump )
2005-12-31 13:30:11 +01:00
{
2015-04-19 12:50:26 +02:00
if ( User ) {
struct passwd * user = isnumber ( User ) ? getpwuid ( atoi ( User ) ) : getpwnam ( User ) ;
2005-12-31 13:30:11 +01:00
if ( ! user ) {
2015-04-19 12:50:26 +02:00
fprintf ( stderr , " vdr: unknown user: '%s' \n " , User ) ;
2005-12-31 13:30:11 +01:00
return false ;
}
if ( setgid ( user - > pw_gid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set group id %u: %s \n " , ( unsigned int ) user - > pw_gid , strerror ( errno ) ) ;
return false ;
}
if ( initgroups ( user - > pw_name , user - > pw_gid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set supplemental group ids for user %s: %s \n " , user - > pw_name , strerror ( errno ) ) ;
return false ;
}
if ( setuid ( user - > pw_uid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set user id %u: %s \n " , ( unsigned int ) user - > pw_uid , strerror ( errno ) ) ;
return false ;
}
2008-02-08 15:55:30 +01:00
if ( UserDump & & prctl ( PR_SET_DUMPABLE , 1 , 0 , 0 , 0 ) < 0 )
2006-02-05 12:58:59 +01:00
fprintf ( stderr , " vdr: warning - cannot set dumpable: %s \n " , strerror ( errno ) ) ;
2013-03-14 09:38:06 +01:00
setenv ( " HOME " , user - > pw_dir , 1 ) ;
setenv ( " USER " , user - > pw_name , 1 ) ;
setenv ( " LOGNAME " , user - > pw_name , 1 ) ;
setenv ( " SHELL " , user - > pw_shell , 1 ) ;
2005-12-31 13:30:11 +01:00
}
return true ;
}
2009-02-01 10:15:47 +01:00
static bool DropCaps ( void )
2005-12-31 13:30:11 +01:00
{
2009-02-01 10:15:47 +01:00
// drop all capabilities except selected ones
2011-09-23 13:11:36 +02:00
cap_t caps = cap_from_text ( " = cap_sys_nice,cap_sys_time,cap_net_raw=ep " ) ;
2005-12-31 13:30:11 +01:00
if ( ! caps ) {
fprintf ( stderr , " vdr: cap_from_text failed: %s \n " , strerror ( errno ) ) ;
return false ;
}
if ( cap_set_proc ( caps ) = = - 1 ) {
fprintf ( stderr , " vdr: cap_set_proc failed: %s \n " , strerror ( errno ) ) ;
cap_free ( caps ) ;
return false ;
}
cap_free ( caps ) ;
return true ;
}
static bool SetKeepCaps ( bool On )
{
// set keeping capabilities during setuid() on/off
if ( prctl ( PR_SET_KEEPCAPS , On ? 1 : 0 , 0 , 0 , 0 ) ! = 0 ) {
fprintf ( stderr , " vdr: prctl failed \n " ) ;
return false ;
}
return true ;
}
2000-09-15 13:58:36 +02:00
static void SignalHandler ( int signum )
2000-04-15 17:38:11 +02:00
{
2007-02-25 10:56:29 +01:00
switch ( signum ) {
case SIGPIPE :
break ;
case SIGHUP :
LastSignal = signum ;
break ;
default :
LastSignal = signum ;
Interface - > Interrupt ( ) ;
ShutdownHandler . Exit ( 0 ) ;
}
2000-09-15 13:58:36 +02:00
signal ( signum , SignalHandler ) ;
2000-04-15 17:38:11 +02:00
}
2001-02-24 16:18:43 +01:00
static void Watchdog ( int signum )
{
// Something terrible must have happened that prevented the 'alarm()' from
// being called in time, so let's get out of here:
2002-05-13 16:35:49 +02:00
esyslog ( " PANIC: watchdog timer expired - exiting! " ) ;
2016-12-23 14:36:24 +01:00
# ifdef SDNOTIFY
sd_notify ( 0 , " STOPPING=1 \n STATUS=PANIC " ) ;
# endif
2001-02-24 16:18:43 +01:00
exit ( 1 ) ;
}
2000-02-19 13:36:48 +01:00
int main ( int argc , char * argv [ ] )
{
2002-12-08 14:30:32 +01:00
// Save terminal settings:
struct termios savedTm ;
2003-02-15 15:46:19 +01:00
bool HasStdin = ( tcgetpgrp ( STDIN_FILENO ) = = getpid ( ) | | getppid ( ) ! = ( pid_t ) 1 ) & & tcgetattr ( STDIN_FILENO , & savedTm ) = = 0 ;
2002-12-08 14:30:32 +01:00
2001-10-07 11:00:35 +02:00
// Initiate locale:
setlocale ( LC_ALL , " " ) ;
2000-07-23 15:01:31 +02:00
// Command line options:
2012-09-01 14:03:45 +02:00
# define dd(a, b) (*a ? a : b)
2010-04-02 12:25:50 +02:00
# define DEFAULTSVDRPPORT 6419
2001-02-24 16:18:43 +01:00
# define DEFAULTWATCHDOG 0 // seconds
2012-09-01 14:03:45 +02:00
# define DEFAULTVIDEODIR VIDEODIR
# define DEFAULTCONFDIR dd(CONFDIR, VideoDirectory)
2014-04-14 13:15:34 +02:00
# define DEFAULTARGSDIR dd(ARGSDIR, " / etc / vdr / conf.d")
2012-09-01 14:03:45 +02:00
# define DEFAULTCACHEDIR dd(CACHEDIR, VideoDirectory)
# define DEFAULTRESDIR dd(RESDIR, ConfigDirectory)
2003-08-02 14:32:53 +02:00
# define DEFAULTPLUGINDIR PLUGINDIR
2012-09-01 14:03:45 +02:00
# define DEFAULTLOCDIR LOCDIR
2003-12-22 13:29:24 +01:00
# define DEFAULTEPGDATAFILENAME "epg.data"
2000-07-23 15:01:31 +02:00
2005-12-31 13:30:11 +01:00
bool StartedAsRoot = false ;
2006-01-13 16:16:32 +01:00
const char * VdrUser = NULL ;
2008-02-08 15:55:30 +01:00
bool UserDump = false ;
2000-07-23 15:01:31 +02:00
int SVDRPport = DEFAULTSVDRPPORT ;
2002-11-03 11:53:58 +01:00
const char * AudioCommand = NULL ;
2012-09-01 14:03:45 +02:00
const char * VideoDirectory = DEFAULTVIDEODIR ;
2000-09-15 15:09:15 +02:00
const char * ConfigDirectory = NULL ;
2012-09-01 14:03:45 +02:00
const char * CacheDirectory = NULL ;
const char * ResourceDirectory = NULL ;
const char * LocaleDirectory = DEFAULTLOCDIR ;
2003-12-22 13:29:24 +01:00
const char * EpgDataFileName = DEFAULTEPGDATAFILENAME ;
2002-05-09 16:26:56 +02:00
bool DisplayHelp = false ;
bool DisplayVersion = false ;
2000-07-23 15:36:43 +02:00
bool DaemonMode = false ;
2002-11-24 15:56:24 +01:00
int SysLogTarget = LOG_USER ;
2002-03-08 16:37:42 +01:00
bool MuteAudio = false ;
2001-02-24 16:18:43 +01:00
int WatchdogTimeout = DEFAULTWATCHDOG ;
2001-09-01 09:04:37 +02:00
const char * Terminal = NULL ;
2015-02-10 14:29:27 +01:00
const char * OverrideCharacterTable = NULL ;
# define DEPRECATED_VDR_CHARSET_OVERRIDE
# ifdef DEPRECATED_VDR_CHARSET_OVERRIDE
OverrideCharacterTable = getenv ( " VDR_CHARSET_OVERRIDE " ) ;
const char * DeprecatedVdrCharsetOverride = OverrideCharacterTable ;
# endif
2005-07-31 11:38:40 +02:00
bool UseKbd = true ;
const char * LircDevice = NULL ;
# if !defined(REMOTE_KBD)
UseKbd = false ;
# endif
# if defined(REMOTE_LIRC)
LircDevice = LIRC_DEVICE ;
# endif
2006-01-13 16:16:32 +01:00
# if defined(VDR_USER)
VdrUser = VDR_USER ;
# endif
2016-12-23 14:36:24 +01:00
# ifdef SDNOTIFY
time_t SdWatchdog ;
int SdWatchdogTimeout = 0 ;
# endif
2005-07-31 11:38:40 +02:00
2014-04-14 13:15:34 +02:00
cArgs * Args = NULL ;
if ( argc = = 1 ) {
Args = new cArgs ( argv [ 0 ] ) ;
if ( Args - > ReadDirectory ( DEFAULTARGSDIR ) ) {
argc = Args - > GetArgc ( ) ;
argv = Args - > GetArgv ( ) ;
}
}
2013-12-25 11:36:44 +01:00
cVideoDirectory : : SetName ( VideoDirectory ) ;
2002-05-09 16:26:56 +02:00
cPluginManager PluginManager ( DEFAULTPLUGINDIR ) ;
2000-07-23 15:01:31 +02:00
static struct option long_options [ ] = {
2001-06-24 17:42:19 +02:00
{ " audio " , required_argument , NULL , ' a ' } ,
2012-09-01 14:03:45 +02:00
{ " cachedir " , required_argument , NULL , ' c ' | 0x100 } ,
2015-02-10 14:29:27 +01:00
{ " chartab " , required_argument , NULL , ' c ' | 0x200 } ,
2001-02-24 16:18:43 +01:00
{ " config " , required_argument , NULL , ' c ' } ,
{ " daemon " , no_argument , NULL , ' d ' } ,
{ " device " , required_argument , NULL , ' D ' } ,
2013-02-08 09:24:55 +01:00
{ " dirnames " , required_argument , NULL , ' d ' | 0x100 } ,
2010-01-02 14:02:48 +01:00
{ " edit " , required_argument , NULL , ' e ' | 0x100 } ,
2001-08-11 09:38:12 +02:00
{ " epgfile " , required_argument , NULL , ' E ' } ,
2011-08-15 12:45:40 +02:00
{ " filesize " , required_argument , NULL , ' f ' | 0x100 } ,
2010-01-02 14:02:48 +01:00
{ " genindex " , required_argument , NULL , ' g ' | 0x100 } ,
2005-12-30 15:11:16 +01:00
{ " grab " , required_argument , NULL , ' g ' } ,
2001-02-24 16:18:43 +01:00
{ " help " , no_argument , NULL , ' h ' } ,
2009-01-18 11:10:29 +01:00
{ " instance " , required_argument , NULL , ' i ' } ,
2002-05-09 16:26:56 +02:00
{ " lib " , required_argument , NULL , ' L ' } ,
2005-07-31 11:38:40 +02:00
{ " lirc " , optional_argument , NULL , ' l ' | 0x100 } ,
2008-01-19 12:25:54 +01:00
{ " localedir " , required_argument , NULL , ' l ' | 0x200 } ,
2001-02-24 16:18:43 +01:00
{ " log " , required_argument , NULL , ' l ' } ,
2002-03-08 16:37:42 +01:00
{ " mute " , no_argument , NULL , ' m ' } ,
2005-07-31 11:38:40 +02:00
{ " no-kbd " , no_argument , NULL , ' n ' | 0x100 } ,
2002-05-09 16:26:56 +02:00
{ " plugin " , required_argument , NULL , ' P ' } ,
2001-02-24 16:18:43 +01:00
{ " port " , required_argument , NULL , ' p ' } ,
2001-09-22 14:23:55 +02:00
{ " record " , required_argument , NULL , ' r ' } ,
2012-09-01 14:03:45 +02:00
{ " resdir " , required_argument , NULL , ' r ' | 0x100 } ,
2014-04-14 13:15:34 +02:00
{ " showargs " , optional_argument , NULL , ' s ' | 0x200 } ,
2001-09-01 09:04:37 +02:00
{ " shutdown " , required_argument , NULL , ' s ' } ,
2011-08-15 12:45:40 +02:00
{ " split " , no_argument , NULL , ' s ' | 0x100 } ,
2001-09-01 09:04:37 +02:00
{ " terminal " , required_argument , NULL , ' t ' } ,
2015-01-17 15:03:01 +01:00
{ " updindex " , required_argument , NULL , ' u ' | 0x200 } ,
2005-12-31 13:30:11 +01:00
{ " user " , required_argument , NULL , ' u ' } ,
2008-02-08 15:55:30 +01:00
{ " userdump " , no_argument , NULL , ' u ' | 0x100 } ,
2002-03-29 10:10:04 +01:00
{ " version " , no_argument , NULL , ' V ' } ,
2005-09-03 13:35:55 +02:00
{ " vfat " , no_argument , NULL , ' v ' | 0x100 } ,
2001-02-24 16:18:43 +01:00
{ " video " , required_argument , NULL , ' v ' } ,
{ " watchdog " , required_argument , NULL , ' w ' } ,
2009-12-06 12:57:45 +01:00
{ NULL , no_argument , NULL , 0 }
2000-07-23 15:01:31 +02:00
} ;
2001-08-03 14:18:08 +02:00
2000-07-23 15:01:31 +02:00
int c ;
2010-01-02 14:02:48 +01:00
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 ) {
2000-07-23 15:01:31 +02:00
switch ( c ) {
2002-11-03 11:53:58 +01:00
case ' a ' : AudioCommand = optarg ;
2001-06-24 17:42:19 +02:00
break ;
2012-09-01 14:03:45 +02:00
case ' c ' | 0x100 :
CacheDirectory = optarg ;
break ;
2015-02-10 14:29:27 +01:00
case ' c ' | 0x200 :
OverrideCharacterTable = optarg ;
break ;
2000-09-15 15:09:15 +02:00
case ' c ' : ConfigDirectory = optarg ;
break ;
2013-02-08 10:48:43 +01:00
case ' d ' : DaemonMode = true ;
break ;
2015-04-18 14:30:47 +02:00
case ' D ' : if ( * optarg = = ' - ' ) {
cDvbDevice : : useDvbDevices = false ;
break ;
}
if ( isnumber ( optarg ) ) {
2001-02-02 15:49:46 +01:00
int n = atoi ( optarg ) ;
2002-06-16 12:57:31 +02:00
if ( 0 < = n & & n < MAXDEVICES ) {
cDevice : : SetUseDevice ( n ) ;
2001-02-02 15:49:46 +01:00
break ;
}
}
fprintf ( stderr , " vdr: invalid DVB device number: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2013-02-08 09:24:55 +01:00
case ' d ' | 0x100 : {
char * s = optarg ;
2013-03-12 09:44:46 +01:00
if ( * s ! = ' , ' ) {
int n = strtol ( s , & s , 10 ) ;
if ( n < = 0 | | n > = PATH_MAX ) { // PATH_MAX includes the terminating 0
fprintf ( stderr , " vdr: invalid directory path length: %s \n " , optarg ) ;
return 2 ;
}
DirectoryPathMax = n ;
2013-03-12 13:27:40 +01:00
if ( ! * s )
break ;
if ( * s ! = ' , ' ) {
fprintf ( stderr , " vdr: invalid delimiter: %s \n " , optarg ) ;
return 2 ;
}
2013-02-08 09:24:55 +01:00
}
2013-03-12 13:27:40 +01:00
s + + ;
2013-02-08 09:24:55 +01:00
if ( ! * s )
break ;
2013-03-12 09:44:46 +01:00
if ( * s ! = ' , ' ) {
int n = strtol ( s , & s , 10 ) ;
if ( n < = 0 | | n > NAME_MAX ) { // NAME_MAX excludes the terminating 0
fprintf ( stderr , " vdr: invalid directory name length: %s \n " , optarg ) ;
return 2 ;
}
DirectoryNameMax = n ;
2013-03-12 13:27:40 +01:00
if ( ! * s )
break ;
if ( * s ! = ' , ' ) {
fprintf ( stderr , " vdr: invalid delimiter: %s \n " , optarg ) ;
return 2 ;
}
2013-02-08 09:24:55 +01:00
}
2013-03-12 13:27:40 +01:00
s + + ;
2013-02-08 09:24:55 +01:00
if ( ! * s )
break ;
2013-03-12 09:44:46 +01:00
int n = strtol ( s , & s , 10 ) ;
2013-02-08 09:24:55 +01:00
if ( n ! = 0 & & n ! = 1 ) {
fprintf ( stderr , " vdr: invalid directory encoding: %s \n " , optarg ) ;
return 2 ;
}
DirectoryEncoding = n ;
if ( * s ) {
fprintf ( stderr , " vdr: unexpected data: %s \n " , optarg ) ;
return 2 ;
}
}
break ;
2010-01-02 14:02:48 +01:00
case ' e ' | 0x100 :
return CutRecording ( optarg ) ? 0 : 2 ;
2003-12-22 13:29:24 +01:00
case ' E ' : EpgDataFileName = ( * optarg ! = ' - ' ? optarg : NULL ) ;
2001-08-11 09:38:12 +02:00
break ;
2011-08-15 12:45:40 +02:00
case ' f ' | 0x100 :
Setup . MaxVideoFileSize = StrToNum ( optarg ) / MEGABYTE ( 1 ) ;
if ( Setup . MaxVideoFileSize < MINVIDEOFILESIZE )
Setup . MaxVideoFileSize = MINVIDEOFILESIZE ;
if ( Setup . MaxVideoFileSize > MAXVIDEOFILESIZETS )
Setup . MaxVideoFileSize = MAXVIDEOFILESIZETS ;
break ;
2010-01-02 14:02:48 +01:00
case ' g ' | 0x100 :
return GenerateIndex ( optarg ) ? 0 : 2 ;
2015-04-29 13:10:06 +02:00
case ' g ' : SetSVDRPGrabImageDir ( * optarg ! = ' - ' ? optarg : NULL ) ;
2005-12-30 15:11:16 +01:00
break ;
2002-05-09 16:26:56 +02:00
case ' h ' : DisplayHelp = true ;
2000-07-23 15:01:31 +02:00
break ;
2009-01-18 11:10:29 +01:00
case ' i ' : if ( isnumber ( optarg ) ) {
InstanceId = atoi ( optarg ) ;
if ( InstanceId > = 0 )
break ;
}
fprintf ( stderr , " vdr: invalid instance id: %s \n " , optarg ) ;
return 2 ;
2002-11-24 15:56:24 +01:00
case ' l ' : {
2013-02-08 10:48:43 +01:00
char * p = strchr ( optarg , ' . ' ) ;
if ( p )
* p = 0 ;
if ( isnumber ( optarg ) ) {
int l = atoi ( optarg ) ;
if ( 0 < = l & & l < = 3 ) {
SysLogLevel = l ;
if ( ! p )
break ;
if ( isnumber ( p + 1 ) ) {
int l = atoi ( p + 1 ) ;
if ( 0 < = l & & l < = 7 ) {
int targets [ ] = { LOG_LOCAL0 , LOG_LOCAL1 , LOG_LOCAL2 , LOG_LOCAL3 , LOG_LOCAL4 , LOG_LOCAL5 , LOG_LOCAL6 , LOG_LOCAL7 } ;
SysLogTarget = targets [ l ] ;
break ;
}
}
}
}
2002-11-24 15:56:24 +01:00
if ( p )
* p = ' . ' ;
2000-07-29 19:03:09 +02:00
fprintf ( stderr , " vdr: invalid log level: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2002-11-24 15:56:24 +01:00
}
2002-05-18 10:36:35 +02:00
case ' L ' : if ( access ( optarg , R_OK | X_OK ) = = 0 )
PluginManager . SetDirectory ( optarg ) ;
else {
fprintf ( stderr , " vdr: can't access plugin directory: %s \n " , optarg ) ;
return 2 ;
}
2002-05-09 16:26:56 +02:00
break ;
2005-07-31 11:38:40 +02:00
case ' l ' | 0x100 :
2008-01-13 11:52:22 +01:00
LircDevice = optarg ? optarg : LIRC_DEVICE ;
2005-07-31 11:38:40 +02:00
break ;
2008-01-19 12:25:54 +01:00
case ' l ' | 0x200 :
if ( access ( optarg , R_OK | X_OK ) = = 0 )
2012-09-01 14:03:45 +02:00
LocaleDirectory = optarg ;
2008-01-19 12:25:54 +01:00
else {
fprintf ( stderr , " vdr: can't access locale directory: %s \n " , optarg ) ;
return 2 ;
}
break ;
2002-03-08 16:37:42 +01:00
case ' m ' : MuteAudio = true ;
break ;
2005-07-31 11:38:40 +02:00
case ' n ' | 0x100 :
UseKbd = false ;
break ;
2000-07-23 15:01:31 +02:00
case ' p ' : if ( isnumber ( optarg ) )
2000-07-29 19:03:09 +02:00
SVDRPport = atoi ( optarg ) ;
2000-07-23 15:01:31 +02:00
else {
fprintf ( stderr , " vdr: invalid port number: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-23 15:01:31 +02:00
}
break ;
2002-05-09 16:26:56 +02:00
case ' P ' : PluginManager . AddPlugin ( optarg ) ;
break ;
2001-09-23 14:02:11 +02:00
case ' r ' : cRecordingUserCommand : : SetCommand ( optarg ) ;
2001-09-22 14:23:55 +02:00
break ;
2012-09-01 14:03:45 +02:00
case ' r ' | 0x100 :
ResourceDirectory = optarg ;
break ;
2007-02-25 10:56:29 +01:00
case ' s ' : ShutdownHandler . SetShutdownCommand ( optarg ) ;
2001-09-01 09:04:37 +02:00
break ;
2011-08-15 12:45:40 +02:00
case ' s ' | 0x100 :
Setup . SplitEditedFiles = 1 ;
break ;
2014-04-14 13:15:34 +02:00
case ' s ' | 0x200 : {
const char * ArgsDir = optarg ? optarg : DEFAULTARGSDIR ;
cArgs Args ( argv [ 0 ] ) ;
if ( ! Args . ReadDirectory ( ArgsDir ) ) {
fprintf ( stderr , " vdr: can't read arguments from directory: %s \n " , ArgsDir ) ;
return 2 ;
}
int c = Args . GetArgc ( ) ;
char * * v = Args . GetArgv ( ) ;
for ( int i = 1 ; i < c ; i + + )
printf ( " %s \n " , v [ i ] ) ;
return 0 ;
}
2001-03-31 10:32:58 +02:00
case ' t ' : Terminal = optarg ;
2003-09-05 13:02:15 +02:00
if ( access ( Terminal , R_OK | W_OK ) < 0 ) {
fprintf ( stderr , " vdr: can't access terminal: %s \n " , Terminal ) ;
return 2 ;
}
2001-03-31 10:32:58 +02:00
break ;
2005-12-31 13:30:11 +01:00
case ' u ' : if ( * optarg )
VdrUser = optarg ;
break ;
2008-02-08 15:55:30 +01:00
case ' u ' | 0x100 :
UserDump = true ;
break ;
2015-01-17 15:03:01 +01:00
case ' u ' | 0x200 :
return GenerateIndex ( optarg , true ) ? 0 : 2 ;
2002-05-09 16:26:56 +02:00
case ' V ' : DisplayVersion = true ;
2002-03-29 10:10:04 +01:00
break ;
2005-09-03 13:35:55 +02:00
case ' v ' | 0x100 :
2013-02-08 09:24:55 +01:00
DirectoryPathMax = 250 ;
DirectoryNameMax = 40 ;
DirectoryEncoding = true ;
2005-09-03 13:35:55 +02:00
break ;
2000-07-28 13:44:31 +02:00
case ' v ' : VideoDirectory = optarg ;
2000-09-17 14:18:14 +02:00
while ( optarg & & * optarg & & optarg [ strlen ( optarg ) - 1 ] = = ' / ' )
optarg [ strlen ( optarg ) - 1 ] = 0 ;
2013-12-25 11:36:44 +01:00
cVideoDirectory : : SetName ( VideoDirectory ) ;
2000-07-28 13:44:31 +02:00
break ;
2008-01-06 11:48:14 +01:00
case ' w ' : if ( isnumber ( optarg ) ) {
int t = atoi ( optarg ) ;
2001-02-24 16:18:43 +01:00
if ( t > = 0 ) {
WatchdogTimeout = t ;
break ;
}
}
fprintf ( stderr , " vdr: invalid watchdog timeout: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
default : return 2 ;
2000-07-23 15:01:31 +02:00
}
}
2005-12-31 13:30:11 +01:00
// Set user id in case we were started as root:
2006-04-14 11:04:20 +02:00
if ( VdrUser & & geteuid ( ) = = 0 ) {
2005-12-31 13:30:11 +01:00
StartedAsRoot = true ;
2015-04-19 12:50:26 +02:00
if ( strcmp ( VdrUser , " root " ) & & strcmp ( VdrUser , " 0 " ) ) {
2006-01-09 16:54:35 +01:00
if ( ! SetKeepCaps ( true ) )
return 2 ;
2008-02-08 15:55:30 +01:00
if ( ! SetUser ( VdrUser , UserDump ) )
2006-01-09 16:54:35 +01:00
return 2 ;
if ( ! SetKeepCaps ( false ) )
return 2 ;
2009-02-01 10:15:47 +01:00
if ( ! DropCaps ( ) )
2006-01-09 16:54:35 +01:00
return 2 ;
}
2005-12-31 13:30:11 +01:00
}
2002-05-09 16:26:56 +02:00
// Help and version info:
if ( DisplayHelp | | DisplayVersion ) {
if ( ! PluginManager . HasPlugins ( ) )
PluginManager . AddPlugin ( " * " ) ; // adds all available plugins
PluginManager . LoadPlugins ( ) ;
if ( DisplayHelp ) {
printf ( " Usage: vdr [OPTIONS] \n \n " // for easier orientation, this is column 80|
" -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD \n "
2012-09-01 14:03:45 +02:00
" --cachedir=DIR save cache files in DIR (default: %s) \n "
2015-02-10 14:29:27 +01:00
" --chartab=CHARACTER_TABLE \n "
" set the character table to use for strings in the \n "
" DVB data stream that don't begin with a character \n "
" table indicator, but don't use the standard default \n "
" character table (for instance ISO-8859-9) \n "
2007-11-03 14:48:07 +01:00
" -c DIR, --config=DIR read config files from DIR (default: %s) \n "
2002-05-09 16:26:56 +02:00
" -d, --daemon run in daemon mode \n "
" -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...) \n "
" there may be several -D options (default: all DVB \n "
2015-04-18 14:30:47 +02:00
" devices will be used); if -D- is given, no DVB \n "
" devices will be used at all, independent of any \n "
" other -D options \n "
2013-02-08 09:24:55 +01:00
" --dirnames=PATH[,NAME[,ENC]] \n "
" set the maximum directory path length to PATH \n "
" (default: %d); if NAME is also given, it defines \n "
" the maximum directory name length (default: %d); \n "
" the optional ENC can be 0 or 1, and controls whether \n "
" special characters in directory names are encoded as \n "
2013-03-12 09:44:46 +01:00
" hex values (default: 0); if PATH or NAME are left \n "
" empty (as in \" ,,1 \" to only set ENC), the defaults \n "
" apply \n "
2010-01-02 14:02:48 +01:00
" --edit=REC cut recording REC and exit \n "
2005-12-31 13:30:11 +01:00
" -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is \n "
2013-03-15 10:47:35 +01:00
" '%s' in the cache directory) \n "
2003-12-22 13:29:24 +01:00
" '-E-' disables this \n "
2002-05-09 16:26:56 +02:00
" if FILE is a directory, the default EPG file will be \n "
" created in that directory \n "
2011-08-15 12:45:40 +02:00
" --filesize=SIZE limit video files to SIZE bytes (default is %dM) \n "
" only useful in conjunction with --edit \n "
2010-01-02 14:02:48 +01:00
" --genindex=REC generate index for recording REC and exit \n "
2005-12-31 13:30:11 +01:00
" -g DIR, --grab=DIR write images from the SVDRP command GRAB into the \n "
2005-12-30 15:11:16 +01:00
" given DIR; DIR must be the full path name of an \n "
" existing directory, without any \" .. \" , double '/' \n "
" or symlinks (default: none, same as -g-) \n "
2002-05-09 16:26:56 +02:00
" -h, --help print this help and exit \n "
2009-03-27 15:54:42 +01:00
" -i ID, --instance=ID use ID as the id of this VDR instance (default: 0) \n "
2002-05-09 16:26:56 +02:00
" -l LEVEL, --log=LEVEL set log level (default: 3) \n "
" 0 = no logging, 1 = errors only, \n "
" 2 = errors and info, 3 = errors, info and debug \n "
2002-11-24 15:56:24 +01:00
" if logging should be done to LOG_LOCALn instead of \n "
" LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7) \n "
2002-05-09 16:26:56 +02:00
" -L DIR, --lib=DIR search for plugins in DIR (default is %s) \n "
2005-07-31 11:38:40 +02:00
" --lirc[=PATH] use a LIRC remote control device, attached to PATH \n "
" (default: %s) \n "
2008-01-19 12:25:54 +01:00
" --localedir=DIR search for locale files in DIR (default is \n "
" %s) \n "
2002-05-09 16:26:56 +02:00
" -m, --mute mute audio of the primary DVB device at startup \n "
2005-07-31 11:38:40 +02:00
" --no-kbd don't use the keyboard as an input device \n "
2002-05-09 16:26:56 +02:00
" -p PORT, --port=PORT use PORT for SVDRP (default: %d) \n "
" 0 turns off SVDRP \n "
" -P OPT, --plugin=OPT load a plugin defined by the given options \n "
2012-09-17 09:03:01 +02:00
" -r CMD, --record=CMD call CMD before and after a recording, and after \n "
" a recording has been edited or deleted \n "
2012-09-01 14:03:45 +02:00
" --resdir=DIR read resource files from DIR (default: %s) \n "
2002-05-09 16:26:56 +02:00
" -s CMD, --shutdown=CMD call CMD to shutdown the computer \n "
2011-08-15 12:45:40 +02:00
" --split split edited files at the editing marks (only \n "
" useful in conjunction with --edit) \n "
2014-04-14 13:15:34 +02:00
" --showargs[=DIR] print the arguments read from DIR and exit \n "
" (default: %s) \n "
2002-05-09 16:26:56 +02:00
" -t TTY, --terminal=TTY controlling tty \n "
2006-01-13 16:16:32 +01:00
" -u USER, --user=USER run as user USER; only applicable if started as \n "
2015-04-19 12:50:26 +02:00
" root; USER can be a user name or a numerical id \n "
2015-01-17 15:03:01 +01:00
" --updindex=REC update index for recording REC and exit \n "
2008-02-08 15:55:30 +01:00
" --userdump allow coredumps if -u is given (debugging) \n "
2002-05-09 16:26:56 +02:00
" -v DIR, --video=DIR use DIR as video directory (default: %s) \n "
" -V, --version print version information and exit \n "
2013-02-08 09:24:55 +01:00
" --vfat for backwards compatibility (same as \n "
2013-12-25 11:04:25 +01:00
" --dirnames=250,40,1) \n "
2002-05-09 16:26:56 +02:00
" -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC \n "
" seconds (default: %d); '0' disables the watchdog \n "
" \n " ,
2012-09-01 14:03:45 +02:00
DEFAULTCACHEDIR ,
2007-11-03 14:48:07 +01:00
DEFAULTCONFDIR ,
2013-03-11 11:07:59 +01:00
PATH_MAX - 1 ,
2013-02-08 09:24:55 +01:00
NAME_MAX ,
2003-12-22 13:29:24 +01:00
DEFAULTEPGDATAFILENAME ,
2011-08-15 12:45:40 +02:00
MAXVIDEOFILESIZEDEFAULT ,
2002-05-09 16:26:56 +02:00
DEFAULTPLUGINDIR ,
2005-07-31 11:38:40 +02:00
LIRC_DEVICE ,
2012-09-01 14:03:45 +02:00
DEFAULTLOCDIR ,
2002-05-09 16:26:56 +02:00
DEFAULTSVDRPPORT ,
2012-09-01 14:03:45 +02:00
DEFAULTRESDIR ,
2014-04-14 13:15:34 +02:00
DEFAULTARGSDIR ,
2012-09-01 14:03:45 +02:00
DEFAULTVIDEODIR ,
2002-05-09 16:26:56 +02:00
DEFAULTWATCHDOG
) ;
}
if ( DisplayVersion )
2006-04-22 11:28:37 +02:00
printf ( " vdr (%s/%s) - The Video Disk Recorder \n " , VDRVERSION , APIVERSION ) ;
2002-05-09 16:26:56 +02:00
if ( PluginManager . HasPlugins ( ) ) {
if ( DisplayHelp )
printf ( " Plugins: vdr -P \" name [OPTIONS] \" \n \n " ) ;
for ( int i = 0 ; ; i + + ) {
cPlugin * p = PluginManager . GetPlugin ( i ) ;
if ( p ) {
const char * help = p - > CommandLineHelp ( ) ;
printf ( " %s (%s) - %s \n " , p - > Name ( ) , p - > Version ( ) , p - > Description ( ) ) ;
if ( DisplayHelp & & help ) {
printf ( " \n " ) ;
puts ( help ) ;
}
}
else
break ;
}
}
return 0 ;
}
2000-07-23 15:01:31 +02:00
// Log file:
2001-08-03 14:18:08 +02:00
2000-07-29 19:03:09 +02:00
if ( SysLogLevel > 0 )
2006-01-15 16:42:37 +01:00
openlog ( " vdr " , LOG_CONS , SysLogTarget ) ; // LOG_PID doesn't work as expected under NPTL
2000-07-23 15:36:43 +02:00
2000-07-28 13:44:31 +02:00
// Check the video directory:
2000-07-29 15:21:42 +02:00
if ( ! DirectoryOk ( VideoDirectory , true ) ) {
2000-07-28 13:44:31 +02:00
fprintf ( stderr , " vdr: can't access video directory %s \n " , VideoDirectory ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-28 13:44:31 +02:00
}
2000-07-23 15:36:43 +02:00
// Daemon mode:
if ( DaemonMode ) {
2005-10-09 10:05:21 +02:00
if ( daemon ( 1 , 0 ) = = - 1 ) {
2005-12-31 13:30:11 +01:00
fprintf ( stderr , " vdr: %m \n " ) ;
2002-05-13 16:35:49 +02:00
esyslog ( " ERROR: %m " ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-23 15:36:43 +02:00
}
}
2001-03-31 10:32:58 +02:00
else if ( Terminal ) {
// Claim new controlling terminal
stdin = freopen ( Terminal , " r " , stdin ) ;
stdout = freopen ( Terminal , " w " , stdout ) ;
stderr = freopen ( Terminal , " w " , stderr ) ;
2003-05-24 11:08:47 +02:00
HasStdin = true ;
2009-10-25 14:49:19 +01:00
tcgetattr ( STDIN_FILENO , & savedTm ) ;
2001-03-31 10:32:58 +02:00
}
2002-05-13 16:35:49 +02:00
isyslog ( " VDR version %s started " , VDRVERSION ) ;
2006-01-13 16:16:32 +01:00
if ( StartedAsRoot & & VdrUser )
2005-12-31 13:30:11 +01:00
isyslog ( " switched to user '%s' " , VdrUser ) ;
2006-01-03 10:20:41 +01:00
if ( DaemonMode )
dsyslog ( " running as daemon (tid=%d) " , cThread : : ThreadId ( ) ) ;
cThread : : SetMainThreadId ( ) ;
2000-02-19 13:36:48 +01:00
2007-04-22 14:49:26 +02:00
// Set the system character table:
2007-06-15 13:25:35 +02:00
char * CodeSet = NULL ;
if ( setlocale ( LC_CTYPE , " " ) )
CodeSet = nl_langinfo ( CODESET ) ;
else {
char * LangEnv = getenv ( " LANG " ) ; // last resort in case locale stuff isn't installed
if ( LangEnv ) {
CodeSet = strchr ( LangEnv , ' . ' ) ;
if ( CodeSet )
CodeSet + + ; // skip the dot
2007-04-22 14:49:26 +02:00
}
}
2007-06-15 13:25:35 +02:00
if ( CodeSet ) {
bool known = SI : : SetSystemCharacterTable ( CodeSet ) ;
isyslog ( " codeset is '%s' - %s " , CodeSet , known ? " known " : " unknown " ) ;
cCharSetConv : : SetSystemCharacterTable ( CodeSet ) ;
}
2015-02-10 14:29:27 +01:00
# ifdef DEPRECATED_VDR_CHARSET_OVERRIDE
if ( DeprecatedVdrCharsetOverride )
isyslog ( " use of environment variable VDR_CHARSET_OVERRIDE (%s) is deprecated! " , DeprecatedVdrCharsetOverride ) ;
# endif
if ( OverrideCharacterTable ) {
isyslog ( " override character table is '%s' " , OverrideCharacterTable ) ;
SI : : SetOverrideCharacterTable ( OverrideCharacterTable ) ;
}
2007-04-22 14:49:26 +02:00
2007-08-11 12:39:06 +02:00
// Initialize internationalization:
2012-09-01 14:03:45 +02:00
I18nInitialize ( LocaleDirectory ) ;
2007-08-11 12:39:06 +02:00
2004-10-31 09:37:56 +01:00
// Main program loop variables - need to be here to have them initialized before any EXIT():
2012-02-11 13:41:29 +01:00
cEpgDataReader EpgDataReader ;
2004-10-31 09:37:56 +01:00
cOsdObject * Menu = NULL ;
2006-01-05 13:54:04 +01:00
int LastChannel = 0 ;
2004-10-31 09:37:56 +01:00
int LastTimerChannel = - 1 ;
int PreviousChannel [ 2 ] = { 1 , 1 } ;
int PreviousChannelIndex = 0 ;
time_t LastChannelChanged = time ( NULL ) ;
2007-10-19 14:46:23 +02:00
time_t LastInteract = 0 ;
2004-10-31 09:37:56 +01:00
int MaxLatencyTime = 0 ;
2006-06-04 09:10:59 +02:00
bool InhibitEpgScan = false ;
2006-01-06 12:53:28 +01:00
bool IsInfoMenu = false ;
2006-06-03 14:46:36 +02:00
cSkin * CurrentSkin = NULL ;
2004-10-31 09:37:56 +01:00
2002-05-09 16:26:56 +02:00
// Load plugins:
if ( ! PluginManager . LoadPlugins ( true ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2002-05-09 16:26:56 +02:00
2012-09-01 14:03:45 +02:00
// Directories:
2000-07-23 15:01:31 +02:00
2000-09-15 15:09:15 +02:00
if ( ! ConfigDirectory )
2007-11-03 14:48:07 +01:00
ConfigDirectory = DEFAULTCONFDIR ;
2002-05-13 16:11:19 +02:00
cPlugin : : SetConfigDirectory ( ConfigDirectory ) ;
2012-09-01 14:03:45 +02:00
if ( ! CacheDirectory )
CacheDirectory = DEFAULTCACHEDIR ;
cPlugin : : SetCacheDirectory ( CacheDirectory ) ;
if ( ! ResourceDirectory )
ResourceDirectory = DEFAULTRESDIR ;
cPlugin : : SetResourceDirectory ( ResourceDirectory ) ;
2004-12-26 12:45:22 +01:00
cThemes : : SetThemesDirectory ( AddDirectory ( ConfigDirectory , " themes " ) ) ;
2012-09-01 14:03:45 +02:00
// Configuration data:
2004-12-26 12:45:22 +01:00
Setup . Load ( AddDirectory ( ConfigDirectory , " setup.conf " ) ) ;
2008-09-06 14:20:20 +02:00
Sources . Load ( AddDirectory ( ConfigDirectory , " sources.conf " ) , true , true ) ;
Diseqcs . Load ( AddDirectory ( ConfigDirectory , " diseqc.conf " ) , true , Setup . DiSEqC ) ;
2011-09-11 14:09:03 +02:00
Scrs . Load ( AddDirectory ( ConfigDirectory , " scr.conf " ) , true ) ;
2015-09-01 11:14:27 +02:00
cChannels : : Load ( AddDirectory ( ConfigDirectory , " channels.conf " ) , false , true ) ;
cTimers : : Load ( AddDirectory ( ConfigDirectory , " timers.conf " ) ) ;
2010-01-31 12:59:50 +01:00
Commands . Load ( AddDirectory ( ConfigDirectory , " commands.conf " ) ) ;
RecordingCommands . Load ( AddDirectory ( ConfigDirectory , " reccmds.conf " ) ) ;
2008-09-06 14:20:20 +02:00
SVDRPhosts . Load ( AddDirectory ( ConfigDirectory , " svdrphosts.conf " ) , true ) ;
Keys . Load ( AddDirectory ( ConfigDirectory , " remote.conf " ) ) ;
KeyMacros . Load ( AddDirectory ( ConfigDirectory , " keymacros.conf " ) , true ) ;
2010-01-17 12:08:03 +01:00
Folders . Load ( AddDirectory ( ConfigDirectory , " folders.conf " ) ) ;
2000-02-19 13:36:48 +01:00
2007-06-17 11:47:18 +02:00
if ( ! * cFont : : GetFontFileName ( Setup . FontOsd ) ) {
const char * msg = " no fonts available - OSD will not show any text! " ;
fprintf ( stderr , " vdr: %s \n " , msg ) ;
esyslog ( " ERROR: %s " , msg ) ;
}
2005-09-25 11:00:57 +02:00
// Recordings:
2015-09-01 11:14:27 +02:00
cRecordings : : Update ( ) ;
2005-09-25 11:00:57 +02:00
2003-12-22 13:29:24 +01:00
// EPG data:
if ( EpgDataFileName ) {
2004-12-19 16:33:34 +01:00
const char * EpgDirectory = NULL ;
if ( DirectoryOk ( EpgDataFileName ) ) {
EpgDirectory = EpgDataFileName ;
EpgDataFileName = DEFAULTEPGDATAFILENAME ;
}
2003-12-22 13:29:24 +01:00
else if ( * EpgDataFileName ! = ' / ' & & * EpgDataFileName ! = ' . ' )
2012-09-01 14:03:45 +02:00
EpgDirectory = CacheDirectory ;
2005-01-14 16:55:28 +01:00
if ( EpgDirectory )
cSchedules : : SetEpgDataFileName ( AddDirectory ( EpgDirectory , EpgDataFileName ) ) ;
else
cSchedules : : SetEpgDataFileName ( EpgDataFileName ) ;
2012-02-11 13:41:29 +01:00
EpgDataReader . Start ( ) ;
2003-12-22 13:29:24 +01:00
}
2000-11-03 15:31:03 +01:00
// DVB interfaces:
2002-08-16 09:57:10 +02:00
cDvbDevice : : Initialize ( ) ;
2011-12-04 12:45:26 +01:00
cDvbDevice : : BondDevices ( Setup . DeviceBondings ) ;
2000-11-03 15:31:03 +01:00
2003-05-09 15:27:46 +02:00
// Initialize plugins:
2002-05-09 16:26:56 +02:00
2003-05-09 15:27:46 +02:00
if ( ! PluginManager . InitializePlugins ( ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2002-05-09 16:26:56 +02:00
2002-08-04 14:57:29 +02:00
// Primary device:
cDevice : : SetPrimaryDevice ( Setup . PrimaryDVB ) ;
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) | | ! cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) ) {
if ( cDevice : : PrimaryDevice ( ) & & ! cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) )
isyslog ( " device %d has no MPEG decoder " , cDevice : : PrimaryDevice ( ) - > DeviceNumber ( ) + 1 ) ;
2003-03-09 14:10:12 +01:00
for ( int i = 0 ; i < cDevice : : NumDevices ( ) ; i + + ) {
cDevice * d = cDevice : : GetDevice ( i ) ;
if ( d & & d - > HasDecoder ( ) ) {
isyslog ( " trying device number %d instead " , i + 1 ) ;
2003-04-12 12:20:07 +02:00
if ( cDevice : : SetPrimaryDevice ( i + 1 ) ) {
2003-03-09 14:10:12 +01:00
Setup . PrimaryDVB = i + 1 ;
2003-04-12 12:20:07 +02:00
break ;
}
2003-03-09 14:10:12 +01:00
}
}
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) ) {
const char * msg = " no primary device found - using first device! " ;
fprintf ( stderr , " vdr: %s \n " , msg ) ;
esyslog ( " ERROR: %s " , msg ) ;
2003-09-05 13:15:51 +02:00
if ( ! cDevice : : SetPrimaryDevice ( 1 ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) ) {
const char * msg = " no primary device found - giving up! " ;
fprintf ( stderr , " vdr: %s \n " , msg ) ;
esyslog ( " ERROR: %s " , msg ) ;
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-04-12 12:20:07 +02:00
}
}
2002-08-16 09:57:10 +02:00
}
2002-08-04 14:57:29 +02:00
2007-02-25 10:56:29 +01:00
// Check for timers in automatic start time window:
ShutdownHandler . CheckManualStart ( MANUALSTART ) ;
2002-09-29 13:40:45 +02:00
// User interface:
2015-04-29 13:10:06 +02:00
Interface = new cInterface ;
2002-09-29 13:40:45 +02:00
2005-01-14 13:10:32 +01:00
// Default skins:
2012-06-02 13:17:16 +02:00
new cSkinLCARS ;
2005-01-14 13:10:32 +01:00
new cSkinSTTNG ;
2012-03-05 10:46:26 +01:00
new cSkinClassic ;
2005-01-14 13:10:32 +01:00
Skins . SetCurrent ( Setup . OSDSkin ) ;
cThemes : : Load ( Skins . Current ( ) - > Name ( ) , Setup . OSDTheme , Skins . Current ( ) - > Theme ( ) ) ;
2006-06-03 14:46:36 +02:00
CurrentSkin = Skins . Current ( ) ;
2005-01-14 13:10:32 +01:00
2003-05-16 12:27:58 +02:00
// Start plugins:
if ( ! PluginManager . StartPlugins ( ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-05-16 12:27:58 +02:00
2005-01-14 13:10:32 +01:00
// Set skin and theme in case they're implemented by a plugin:
2004-05-16 10:35:36 +02:00
2006-06-03 14:46:36 +02:00
if ( ! CurrentSkin | | CurrentSkin = = Skins . Current ( ) & & strcmp ( Skins . Current ( ) - > Name ( ) , Setup . OSDSkin ) ! = 0 ) {
Skins . SetCurrent ( Setup . OSDSkin ) ;
cThemes : : Load ( Skins . Current ( ) - > Name ( ) , Setup . OSDTheme , Skins . Current ( ) - > Theme ( ) ) ;
}
2004-05-16 10:35:36 +02:00
2002-09-29 13:40:45 +02:00
// Remote Controls:
2005-07-31 11:38:40 +02:00
if ( LircDevice )
new cLircRemote ( LircDevice ) ;
if ( ! DaemonMode & & HasStdin & & UseKbd )
2002-12-08 14:30:32 +01:00
new cKbdRemote ;
2002-09-29 13:40:45 +02:00
Interface - > LearnKeys ( ) ;
2002-11-03 11:53:58 +01:00
// External audio:
if ( AudioCommand )
new cExternalAudio ( AudioCommand ) ;
2013-08-21 11:02:52 +02:00
// Positioner:
if ( ! cPositioner : : GetPositioner ( ) ) // no plugin has created a positioner
new cDiseqcPositioner ;
2017-01-09 13:42:41 +01:00
// CAM data:
ChannelCamRelations . Load ( AddDirectory ( CacheDirectory , " cam.data " ) ) ;
2002-05-09 16:26:56 +02:00
// Channel:
2005-08-21 08:56:49 +02:00
if ( ! cDevice : : WaitForAllDevicesReady ( DEVICEREADYTIMEOUT ) )
dsyslog ( " not all devices ready after %d seconds " , DEVICEREADYTIMEOUT ) ;
2014-01-16 11:57:54 +01:00
if ( ! CamSlots . WaitForAllCamSlotsReady ( DEVICEREADYTIMEOUT ) )
dsyslog ( " not all CAM slots ready after %d seconds " , DEVICEREADYTIMEOUT ) ;
2011-07-31 13:48:49 +02:00
if ( * Setup . InitialChannel ) {
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
2011-07-31 13:48:49 +02:00
if ( isnumber ( Setup . InitialChannel ) ) { // for compatibility with old setup.conf files
2015-09-01 11:14:27 +02:00
if ( const cChannel * Channel = Channels - > GetByNumber ( atoi ( Setup . InitialChannel ) ) )
2011-07-31 13:48:49 +02:00
Setup . InitialChannel = Channel - > GetChannelID ( ) . ToString ( ) ;
}
2015-09-01 11:14:27 +02:00
if ( const cChannel * Channel = Channels - > GetByChannelID ( tChannelID : : FromString ( Setup . InitialChannel ) ) )
2011-07-31 13:48:49 +02:00
Setup . CurrentChannel = Channel - > Number ( ) ;
2011-06-13 14:48:41 +02:00
}
2006-04-09 13:26:56 +02:00
if ( Setup . InitialVolume > = 0 )
Setup . CurrentVolume = Setup . InitialVolume ;
2015-09-01 11:14:27 +02:00
{
LOCK_CHANNELS_READ ;
Channels - > SwitchTo ( Setup . CurrentChannel ) ;
}
2002-03-08 16:37:42 +01:00
if ( MuteAudio )
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > ToggleMute ( ) ;
2002-03-08 16:37:42 +01:00
else
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > SetVolume ( Setup . CurrentVolume , true ) ;
2000-02-19 13:36:48 +01:00
2000-07-23 15:01:31 +02:00
// Signal handlers:
2000-04-15 17:38:11 +02:00
if ( signal ( SIGHUP , SignalHandler ) = = SIG_IGN ) signal ( SIGHUP , SIG_IGN ) ;
if ( signal ( SIGINT , SignalHandler ) = = SIG_IGN ) signal ( SIGINT , SIG_IGN ) ;
if ( signal ( SIGTERM , SignalHandler ) = = SIG_IGN ) signal ( SIGTERM , SIG_IGN ) ;
2000-09-15 13:58:36 +02:00
if ( signal ( SIGPIPE , SignalHandler ) = = SIG_IGN ) signal ( SIGPIPE , SIG_IGN ) ;
2001-02-24 16:18:43 +01:00
if ( WatchdogTimeout > 0 )
if ( signal ( SIGALRM , Watchdog ) = = SIG_IGN ) signal ( SIGALRM , SIG_IGN ) ;
2000-04-15 17:38:11 +02:00
2003-05-09 15:27:46 +02:00
// Watchdog:
if ( WatchdogTimeout > 0 ) {
dsyslog ( " setting watchdog timer to %d seconds " , WatchdogTimeout ) ;
alarm ( WatchdogTimeout ) ; // Initial watchdog timer start
}
2014-03-16 12:53:47 +01:00
# ifdef SDNOTIFY
2016-12-23 14:36:24 +01:00
if ( sd_watchdog_enabled ( 0 , NULL ) > 0 ) {
uint64_t timeout ;
SdWatchdog = time ( NULL ) ;
sd_watchdog_enabled ( 0 , & timeout ) ;
SdWatchdogTimeout = ( int ) timeout / 1000000 ;
dsyslog ( " SD_WATCHDOG enabled with timeout set to %d seconds " , SdWatchdogTimeout ) ;
}
// Startup notification:
2015-01-11 13:42:26 +01:00
sd_notify ( 0 , " READY=1 \n STATUS=Ready " ) ;
2014-03-16 12:53:47 +01:00
# endif
2015-04-29 13:10:06 +02:00
// SVDRP:
2015-09-08 11:08:06 +02:00
SetSVDRPPorts ( SVDRPport , DEFAULTSVDRPPORT ) ;
StartSVDRPServerHandler ( ) ;
if ( Setup . SVDRPPeering )
StartSVDRPClientHandler ( ) ;
2015-04-29 13:10:06 +02:00
2000-07-23 15:01:31 +02:00
// Main program loop:
2006-01-06 12:53:28 +01:00
# define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
2007-02-25 10:56:29 +01:00
while ( ! ShutdownHandler . DoExit ( ) ) {
2004-10-16 09:36:28 +02:00
# ifdef DEBUGRINGBUFFERS
cRingBufferLinear : : PrintDebugRBL ( ) ;
# endif
2002-06-23 11:23:34 +02:00
// Attach launched player control:
cControl : : Attach ( ) ;
2007-08-17 14:36:45 +02:00
2007-08-18 13:03:46 +02:00
time_t Now = time ( NULL ) ;
2007-08-17 14:36:45 +02:00
2003-05-03 13:42:37 +02:00
// Make sure we have a visible programme in case device usage has changed:
2013-02-14 11:02:14 +01:00
if ( ! EITScanner . Active ( ) & & cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) ) {
2003-05-03 13:42:37 +02:00
static time_t lastTime = 0 ;
2013-02-14 11:02:14 +01:00
if ( ! cDevice : : PrimaryDevice ( ) - > HasProgramme ( ) ) {
if ( ! CamMenuActive ( ) & & Now - lastTime > MINCHANNELWAIT ) { // !CamMenuActive() to avoid interfering with the CAM if a CAM menu is open
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
const cChannel * Channel = Channels - > GetByNumber ( cDevice : : CurrentChannel ( ) ) ;
2013-02-14 11:02:14 +01:00
if ( Channel & & ( Channel - > Vpid ( ) | | Channel - > Apid ( 0 ) | | Channel - > Dpid ( 0 ) ) ) {
2015-09-01 11:14:27 +02:00
if ( cDevice : : GetDeviceForTransponder ( Channel , LIVEPRIORITY ) & & Channels - > SwitchTo ( Channel - > Number ( ) ) ) // try to switch to the original channel...
2012-03-06 12:32:38 +01:00
;
2013-02-14 11:02:14 +01:00
else if ( LastTimerChannel > 0 ) {
2015-09-01 11:14:27 +02:00
Channel = Channels - > GetByNumber ( LastTimerChannel ) ;
if ( Channel & & cDevice : : GetDeviceForTransponder ( Channel , LIVEPRIORITY ) & & Channels - > SwitchTo ( LastTimerChannel ) ) // ...or the one used by the last timer
2013-02-14 11:02:14 +01:00
;
}
2012-03-06 12:32:38 +01:00
}
2013-02-14 11:02:14 +01:00
lastTime = Now ; // don't do this too often
LastTimerChannel = - 1 ;
2006-01-08 11:44:37 +01:00
}
2003-05-03 13:42:37 +02:00
}
2013-02-14 11:02:14 +01:00
else
lastTime = 0 ; // makes sure we immediately try again next time
2003-05-03 13:42:37 +02:00
}
2009-05-03 14:15:21 +02:00
// Update the OSD size:
{
static time_t lastOsdSizeUpdate = 0 ;
2009-05-12 21:08:23 +02:00
if ( Now ! = lastOsdSizeUpdate ) { // once per second
2009-05-03 14:15:21 +02:00
cOsdProvider : : UpdateOsdSize ( ) ;
2017-04-03 12:49:56 +02:00
static int OsdState = 0 ;
if ( cOsdProvider : : OsdSizeChanged ( OsdState ) ) {
if ( cOsdMenu * OsdMenu = dynamic_cast < cOsdMenu * > ( Menu ) )
OsdMenu - > Display ( ) ;
}
2009-05-12 21:08:23 +02:00
lastOsdSizeUpdate = Now ;
}
2009-05-03 14:15:21 +02:00
}
2001-02-24 16:18:43 +01:00
// Restart the Watchdog timer:
if ( WatchdogTimeout > 0 ) {
int LatencyTime = WatchdogTimeout - alarm ( WatchdogTimeout ) ;
if ( LatencyTime > MaxLatencyTime ) {
MaxLatencyTime = LatencyTime ;
2002-05-13 16:35:49 +02:00
dsyslog ( " max. latency time %d seconds " , MaxLatencyTime ) ;
2001-02-24 16:18:43 +01:00
}
}
2016-12-23 14:36:24 +01:00
# ifdef SDNOTIFY
// Ping systemd watchdog when half the timeout is elapsed:
if ( SdWatchdogTimeout & & ( Now - SdWatchdog ) * 2 > SdWatchdogTimeout ) {
sd_notify ( 0 , " WATCHDOG=1 " ) ;
SdWatchdog = Now ;
dsyslog ( " SD_WATCHDOG ping " ) ;
}
# endif
2004-10-31 10:22:32 +01:00
// Handle channel and timer modifications:
2015-09-01 11:14:27 +02:00
{
// Channels and timers need to be stored in a consistent manner,
// therefore if one of them is changed, we save both.
static time_t ChannelSaveTimeout = 0 ;
static cStateKey TimersStateKey ( true ) ;
static cStateKey ChannelsStateKey ( true ) ;
static int ChannelsModifiedByUser = 0 ;
const cTimers * Timers = cTimers : : GetTimersRead ( TimersStateKey ) ;
const cChannels * Channels = cChannels : : GetChannelsRead ( ChannelsStateKey ) ;
if ( ChannelSaveTimeout ! = 1 ) {
if ( Channels ) {
if ( Channels - > ModifiedByUser ( ChannelsModifiedByUser ) )
ChannelSaveTimeout = 1 ; // triggers an immediate save
else if ( ! ChannelSaveTimeout )
ChannelSaveTimeout = Now + CHANNELSAVEDELTA ;
}
if ( Timers )
ChannelSaveTimeout = 1 ; // triggers an immediate save
}
if ( ChannelSaveTimeout & & Now > ChannelSaveTimeout & & ! cRecordControls : : Active ( ) )
ChannelSaveTimeout = 1 ; // triggers an immediate save
if ( Timers & & Channels ) {
Channels - > Save ( ) ;
Timers - > Save ( ) ;
ChannelSaveTimeout = 0 ;
}
if ( Channels ) {
for ( const cChannel * Channel = Channels - > First ( ) ; Channel ; Channel = Channels - > Next ( Channel ) ) {
if ( Channel - > Modification ( CHANNELMOD_RETUNE ) ) {
cRecordControls : : ChannelDataModified ( Channel ) ;
if ( Channel - > Number ( ) = = cDevice : : CurrentChannel ( ) & & cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) ) {
if ( ! cDevice : : PrimaryDevice ( ) - > Replaying ( ) | | cDevice : : PrimaryDevice ( ) - > Transferring ( ) ) {
if ( cDevice : : ActualDevice ( ) - > ProvidesTransponder ( Channel ) ) { // avoids retune on devices that don't really access the transponder
isyslog ( " retuning due to modification of channel %d (%s) " , Channel - > Number ( ) , Channel - > Name ( ) ) ;
Channels - > SwitchTo ( Channel - > Number ( ) ) ;
}
}
}
cStatus : : MsgChannelChange ( Channel ) ;
}
2004-10-17 11:50:21 +02:00
}
2015-09-01 11:14:27 +02:00
}
// State keys are removed in reverse order!
if ( Channels )
ChannelsStateKey . Remove ( ) ;
if ( Timers )
TimersStateKey . Remove ( ) ;
if ( ChannelSaveTimeout = = 1 ) {
// Only one of them was modified, so we reset the state keys to handle them both in the next turn:
ChannelsStateKey . Reset ( ) ;
TimersStateKey . Reset ( ) ;
}
}
2000-04-22 13:51:48 +02:00
// Channel display:
2002-06-16 12:57:31 +02:00
if ( ! EITScanner . Active ( ) & & cDevice : : CurrentChannel ( ) ! = LastChannel ) {
2000-09-09 14:57:43 +02:00
if ( ! Menu )
2006-01-05 13:54:04 +01:00
Menu = new cDisplayChannel ( cDevice : : CurrentChannel ( ) , LastChannel > = 0 ) ;
2002-06-16 12:57:31 +02:00
LastChannel = cDevice : : CurrentChannel ( ) ;
2007-08-17 14:36:45 +02:00
LastChannelChanged = Now ;
2003-06-19 10:06:07 +02:00
}
2007-08-17 14:36:45 +02:00
if ( Now - LastChannelChanged > = Setup . ZapTimeout & & LastChannel ! = PreviousChannel [ PreviousChannelIndex ] )
2003-08-16 15:27:26 +02:00
PreviousChannel [ PreviousChannelIndex ^ = 1 ] = LastChannel ;
2015-09-01 11:14:27 +02:00
{
// Timers and Recordings:
bool TimersModified = false ;
bool TriggerRemoteTimerPoll = false ;
static cStateKey TimersStateKey ( true ) ;
if ( cTimers : : GetTimersRead ( TimersStateKey ) ) {
TriggerRemoteTimerPoll = true ;
TimersStateKey . Remove ( ) ;
}
cTimers * Timers = cTimers : : GetTimersWrite ( TimersStateKey ) ;
// Get remote timers:
TimersModified | = Timers - > GetRemoteTimers ( ) ;
// Assign events to timers:
static cStateKey SchedulesStateKey ;
if ( const cSchedules * Schedules = cSchedules : : GetSchedulesRead ( SchedulesStateKey ) )
TimersModified | = Timers - > SetEvents ( Schedules ) ;
// Must do all following calls with the exact same time!
// Process ongoing recordings:
if ( cRecordControls : : Process ( Timers , Now ) ) {
TimersModified = true ;
TriggerRemoteTimerPoll = true ;
}
// Must keep the lock on the schedules until after processing the record
// controls, in order to avoid short interrupts in case the current event
// is replaced by a new one (which some broadcasters do, instead of just
// modifying the current event's data):
if ( SchedulesStateKey . InLock ( ) )
SchedulesStateKey . Remove ( ) ;
// Start new recordings:
if ( cTimer * Timer = Timers - > GetMatch ( Now ) ) {
if ( ! cRecordControls : : Start ( Timers , Timer ) )
Timer - > SetPending ( true ) ;
else
LastTimerChannel = Timer - > Channel ( ) - > Number ( ) ;
TimersModified = true ;
TriggerRemoteTimerPoll = true ;
}
// Make sure timers "see" their channel early enough:
static time_t LastTimerCheck = 0 ;
if ( Now - LastTimerCheck > TIMERCHECKDELTA ) { // don't do this too often
InhibitEpgScan = false ;
for ( cTimer * Timer = Timers - > First ( ) ; Timer ; Timer = Timers - > Next ( Timer ) ) {
if ( Timer - > Remote ( ) )
continue ;
bool InVpsMargin = false ;
bool NeedsTransponder = false ;
if ( Timer - > HasFlags ( tfActive ) & & ! Timer - > Recording ( ) ) {
if ( Timer - > HasFlags ( tfVps ) ) {
if ( Timer - > Matches ( Now , true , Setup . VpsMargin ) ) {
InVpsMargin = true ;
Timer - > SetInVpsMargin ( InVpsMargin ) ;
}
else if ( Timer - > Event ( ) ) {
InVpsMargin = Timer - > Event ( ) - > StartTime ( ) < = Now & & Now < Timer - > Event ( ) - > EndTime ( ) ;
NeedsTransponder = Timer - > Event ( ) - > StartTime ( ) - Now < VPSLOOKAHEADTIME * 3600 & & ! Timer - > Event ( ) - > SeenWithin ( VPSUPTODATETIME ) ;
}
else {
LOCK_SCHEDULES_READ ;
const cSchedule * Schedule = Schedules - > GetSchedule ( Timer - > Channel ( ) ) ;
InVpsMargin = ! Schedule ; // we must make sure we have the schedule
NeedsTransponder = Schedule & & ! Schedule - > PresentSeenWithin ( VPSUPTODATETIME ) ;
}
InhibitEpgScan | = InVpsMargin | NeedsTransponder ;
}
else
NeedsTransponder = Timer - > Matches ( Now , true , TIMERLOOKAHEADTIME ) ;
}
if ( NeedsTransponder | | InVpsMargin ) {
// Find a device that provides the required transponder:
cDevice * Device = cDevice : : GetDeviceForTransponder ( Timer - > Channel ( ) , MINPRIORITY ) ;
if ( ! Device & & InVpsMargin )
Device = cDevice : : GetDeviceForTransponder ( Timer - > Channel ( ) , LIVEPRIORITY ) ;
// Switch the device to the transponder:
if ( Device ) {
bool HadProgramme = cDevice : : PrimaryDevice ( ) - > HasProgramme ( ) ;
if ( ! Device - > IsTunedToTransponder ( Timer - > Channel ( ) ) ) {
if ( Device = = cDevice : : ActualDevice ( ) & & ! Device - > IsPrimaryDevice ( ) )
cDevice : : PrimaryDevice ( ) - > StopReplay ( ) ; // stop transfer mode
dsyslog ( " switching device %d to channel %d (%s) " , Device - > DeviceNumber ( ) + 1 , Timer - > Channel ( ) - > Number ( ) , Timer - > Channel ( ) - > Name ( ) ) ;
if ( Device - > SwitchChannel ( Timer - > Channel ( ) , false ) )
Device - > SetOccupied ( TIMERDEVICETIMEOUT ) ;
}
if ( cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) & & HadProgramme & & ! cDevice : : PrimaryDevice ( ) - > HasProgramme ( ) )
Skins . QueueMessage ( mtInfo , tr ( " Upcoming recording! " ) ) ; // the previous SwitchChannel() has switched away the current live channel
}
}
}
LastTimerCheck = Now ;
}
// Delete expired timers:
if ( Timers - > DeleteExpired ( ) ) {
TimersModified = true ;
TriggerRemoteTimerPoll = true ;
}
// Trigger remote timer polls:
if ( TriggerRemoteTimerPoll )
Timers - > TriggerRemoteTimerPoll ( ) ;
TimersStateKey . Remove ( TimersModified ) ;
}
// Recordings:
if ( ! Menu ) {
if ( cRecordings : : NeedsUpdate ( ) )
cRecordings : : Update ( ) ;
2005-12-18 10:41:26 +01:00
}
2003-01-06 14:44:27 +01:00
// CAM control:
2007-01-07 14:46:14 +01:00
if ( ! Menu & & ! cOsd : : IsOpen ( ) )
2003-01-06 14:44:27 +01:00
Menu = CamControl ( ) ;
2005-11-27 15:57:03 +01:00
// Queued messages:
if ( ! Skins . IsOpen ( ) )
Skins . ProcessQueuedMessages ( ) ;
2000-04-16 15:50:21 +02:00
// User Input:
2002-06-23 11:23:34 +02:00
cOsdObject * Interact = Menu ? Menu : cControl : : Control ( ) ;
2007-01-07 14:46:14 +01:00
eKeys key = Interface - > GetKey ( ! Interact | | ! Interact - > NeedsFastResponse ( ) ) ;
2007-02-25 10:56:29 +01:00
if ( ISREALKEY ( key ) ) {
2000-11-18 13:57:32 +01:00
EITScanner . Activity ( ) ;
2007-02-25 10:56:29 +01:00
// Cancel shutdown countdown:
if ( ShutdownHandler . countdown )
ShutdownHandler . countdown . Cancel ( ) ;
// Set user active for MinUserInactivity time in the future:
ShutdownHandler . SetUserInactiveTimeout ( ) ;
2001-09-01 09:04:37 +02:00
}
2001-09-23 14:36:38 +02:00
// Keys that must work independent of any interactive mode:
2010-12-12 13:42:00 +01:00
switch ( int ( key ) ) {
2002-06-23 09:44:00 +02:00
// Menu control:
2006-01-13 15:45:02 +01:00
case kMenu : {
2003-05-02 10:59:07 +02:00
key = kNone ; // nobody else needs to see this key
2006-01-13 15:45:02 +01:00
bool WasOpen = Interact ! = NULL ;
bool WasMenu = Interact & & Interact - > IsMenu ( ) ;
2006-01-04 13:22:53 +01:00
if ( Menu )
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2006-02-04 13:03:03 +01:00
else if ( cControl : : Control ( ) ) {
if ( cOsd : : IsOpen ( ) )
cControl : : Control ( ) - > Hide ( ) ;
else
WasOpen = false ;
}
2007-02-25 11:39:40 +01:00
if ( ! WasOpen | | ! WasMenu & & ! Setup . MenuKeyCloses )
2006-01-04 13:22:53 +01:00
Menu = new cMenuMain ;
2006-01-13 15:45:02 +01:00
}
2002-06-23 09:44:00 +02:00
break ;
2006-01-06 12:53:28 +01:00
// Info:
case kInfo : {
2007-11-25 15:27:10 +01:00
if ( IsInfoMenu ) {
key = kNone ; // nobody else needs to see this key
DELETE_MENU ;
}
else if ( ! Menu ) {
2006-01-06 12:53:28 +01:00
IsInfoMenu = true ;
if ( cControl : : Control ( ) ) {
cControl : : Control ( ) - > Hide ( ) ;
Menu = cControl : : Control ( ) - > GetInfo ( ) ;
if ( Menu )
Menu - > Show ( ) ;
else
IsInfoMenu = false ;
}
else {
cRemote : : Put ( kOk , true ) ;
cRemote : : Put ( kSchedule , true ) ;
}
2007-11-25 15:27:10 +01:00
key = kNone ; // nobody else needs to see this key
2006-01-06 12:53:28 +01:00
}
}
break ;
2006-01-22 14:27:53 +01:00
// Direct main menu functions:
2005-09-03 11:33:43 +02:00
# define DirectMainFunction(function)\
2012-12-03 13:27:07 +01:00
{ DELETE_MENU ; \
2002-10-27 14:32:06 +01:00
if ( cControl : : Control ( ) ) \
cControl : : Control ( ) - > Hide ( ) ; \
2005-12-24 15:53:53 +01:00
Menu = new cMenuMain ( function ) ; \
2012-12-03 13:27:07 +01:00
key = kNone ; } // nobody else needs to see this key
2002-10-27 14:32:06 +01:00
case kSchedule : DirectMainFunction ( osSchedule ) ; break ;
case kChannels : DirectMainFunction ( osChannels ) ; break ;
case kTimers : DirectMainFunction ( osTimers ) ; break ;
case kRecordings : DirectMainFunction ( osRecordings ) ; break ;
case kSetup : DirectMainFunction ( osSetup ) ; break ;
case kCommands : DirectMainFunction ( osCommands ) ; break ;
2010-04-05 10:14:19 +02:00
case kUser0 . . . kUser9 : cRemote : : PutMacro ( key ) ; key = kNone ; break ;
2005-09-03 11:33:43 +02:00
case k_Plugin : {
2006-10-14 10:06:16 +02:00
const char * PluginName = cRemote : : GetPlugin ( ) ;
if ( PluginName ) {
DELETE_MENU ;
if ( cControl : : Control ( ) )
cControl : : Control ( ) - > Hide ( ) ;
cPlugin * plugin = cPluginManager : : GetPlugin ( PluginName ) ;
if ( plugin ) {
Menu = plugin - > MainMenuAction ( ) ;
if ( Menu )
Menu - > Show ( ) ;
}
else
esyslog ( " ERROR: unknown plugin '%s' " , PluginName ) ;
2005-09-03 11:33:43 +02:00
}
key = kNone ; // nobody else needs to see these keys
}
break ;
2002-10-27 14:32:06 +01:00
// Channel up/down:
case kChanUp | k_Repeat :
case kChanUp :
case kChanDn | k_Repeat :
case kChanDn :
2006-01-22 14:27:53 +01:00
if ( ! Interact )
Menu = new cDisplayChannel ( NORMALKEY ( key ) ) ;
2007-04-30 09:53:34 +02:00
else if ( cDisplayChannel : : IsOpen ( ) | | cControl : : Control ( ) ) {
2006-01-22 14:27:53 +01:00
Interact - > ProcessKey ( key ) ;
continue ;
}
else
cDevice : : SwitchChannel ( NORMALKEY ( key ) = = kChanUp ? 1 : - 1 ) ;
key = kNone ; // nobody else needs to see these keys
2002-10-27 14:32:06 +01:00
break ;
2005-01-02 15:11:44 +01:00
// Volume control:
2001-09-23 14:36:38 +02:00
case kVolUp | k_Repeat :
case kVolUp :
case kVolDn | k_Repeat :
case kVolDn :
case kMute :
2002-03-09 17:11:49 +01:00
if ( key = = kMute ) {
2003-03-30 10:53:22 +02:00
if ( ! cDevice : : PrimaryDevice ( ) - > ToggleMute ( ) & & ! Menu ) {
key = kNone ; // nobody else needs to see these keys
2002-03-09 17:11:49 +01:00
break ; // no need to display "mute off"
2003-03-30 10:53:22 +02:00
}
2002-03-09 17:11:49 +01:00
}
else
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > SetVolume ( NORMALKEY ( key ) = = kVolDn ? - VOLUMEDELTA : VOLUMEDELTA ) ;
2004-05-16 10:35:36 +02:00
if ( ! Menu & & ! cOsd : : IsOpen ( ) )
2006-01-04 13:22:53 +01:00
Menu = cDisplayVolume : : Create ( ) ;
2002-03-09 17:11:49 +01:00
cDisplayVolume : : Process ( key ) ;
2003-03-30 10:53:22 +02:00
key = kNone ; // nobody else needs to see these keys
2001-09-23 14:36:38 +02:00
break ;
2005-01-02 15:11:44 +01:00
// Audio track control:
case kAudio :
2005-01-06 14:36:40 +01:00
if ( cControl : : Control ( ) )
cControl : : Control ( ) - > Hide ( ) ;
2006-01-04 13:22:53 +01:00
if ( ! cDisplayTracks : : IsOpen ( ) ) {
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2006-01-04 13:22:53 +01:00
Menu = cDisplayTracks : : Create ( ) ;
2005-01-06 14:36:40 +01:00
}
2005-01-02 15:11:44 +01:00
else
cDisplayTracks : : Process ( key ) ;
key = kNone ;
break ;
2007-10-12 14:52:30 +02:00
// Subtitle track control:
case kSubtitles :
if ( cControl : : Control ( ) )
cControl : : Control ( ) - > Hide ( ) ;
if ( ! cDisplaySubtitleTracks : : IsOpen ( ) ) {
DELETE_MENU ;
Menu = cDisplaySubtitleTracks : : Create ( ) ;
}
else
cDisplaySubtitleTracks : : Process ( key ) ;
key = kNone ;
break ;
2003-04-21 14:57:13 +02:00
// Pausing live video:
2012-12-04 13:37:59 +01:00
case kPlayPause :
2003-04-21 14:57:13 +02:00
case kPause :
if ( ! cControl : : Control ( ) ) {
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2009-05-21 11:35:37 +02:00
if ( Setup . PauseKeyHandling ) {
if ( Setup . PauseKeyHandling > 1 | | Interface - > Confirm ( tr ( " Pause live video? " ) ) ) {
if ( ! cRecordControls : : PauseLiveVideo ( ) )
2013-01-29 11:31:12 +01:00
Skins . QueueMessage ( mtError , tr ( " No free DVB device to record! " ) ) ;
2009-05-21 11:35:37 +02:00
}
}
2003-04-21 14:57:13 +02:00
key = kNone ; // nobody else needs to see this key
}
break ;
// Instant recording:
case kRecord :
if ( ! cControl : : Control ( ) ) {
2015-09-11 08:29:41 +02:00
if ( Setup . RecordKeyHandling ) {
if ( Setup . RecordKeyHandling > 1 | | Interface - > Confirm ( tr ( " Start recording? " ) ) ) {
if ( cRecordControls : : Start ( ) )
Skins . QueueMessage ( mtInfo , tr ( " Recording started " ) ) ;
}
}
2003-04-21 14:57:13 +02:00
key = kNone ; // nobody else needs to see this key
}
break ;
2001-09-23 14:36:38 +02:00
// Power off:
2007-02-25 10:56:29 +01:00
case kPower :
2006-04-29 09:24:07 +02:00
isyslog ( " Power button pressed " ) ;
DELETE_MENU ;
2007-02-25 10:56:29 +01:00
// Check for activity, request power button again if active:
if ( ! ShutdownHandler . ConfirmShutdown ( false ) & & Skins . Message ( mtWarning , tr ( " VDR will shut down later - press Power to force " ) , SHUTDOWNFORCEPROMPT ) ! = kPower ) {
// Not pressed power - set VDR to be non-interactive and power down later:
ShutdownHandler . SetUserInactive ( ) ;
2006-04-29 09:24:07 +02:00
break ;
}
2007-02-25 10:56:29 +01:00
// No activity or power button pressed twice - ask for confirmation:
if ( ! ShutdownHandler . ConfirmShutdown ( true ) ) {
// Non-confirmed background activity - set VDR to be non-interactive and power down later:
ShutdownHandler . SetUserInactive ( ) ;
2006-04-29 09:24:07 +02:00
break ;
2006-05-05 13:45:42 +02:00
}
2007-02-25 10:56:29 +01:00
// Ask the final question:
2007-07-22 11:40:01 +02:00
if ( ! Interface - > Confirm ( tr ( " Press any key to cancel shutdown " ) , SHUTDOWNCANCELPROMPT , true ) )
2007-02-25 10:56:29 +01:00
// If final question was canceled, continue to be active:
break ;
// Ok, now call the shutdown script:
ShutdownHandler . DoShutdown ( true ) ;
// Set VDR to be non-interactive and power down again later:
ShutdownHandler . SetUserInactive ( ) ;
// Do not attempt to automatically shut down for a while:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
2006-04-29 09:24:07 +02:00
break ;
2002-10-27 14:32:06 +01:00
default : break ;
2001-09-23 14:36:38 +02:00
}
2002-10-27 14:32:06 +01:00
Interact = Menu ? Menu : cControl : : Control ( ) ; // might have been closed in the mean time
if ( Interact ) {
2007-10-19 14:46:23 +02:00
LastInteract = Now ;
2002-10-27 14:32:06 +01:00
eOSState state = Interact - > ProcessKey ( key ) ;
2005-09-04 08:57:15 +02:00
if ( state = = osUnknown & & Interact ! = cControl : : Control ( ) ) {
2005-11-04 13:52:31 +01:00
if ( ISMODELESSKEY ( key ) & & cControl : : Control ( ) ) {
2005-09-03 11:51:54 +02:00
state = cControl : : Control ( ) - > ProcessKey ( key ) ;
2005-11-04 13:52:31 +01:00
if ( state = = osEnd ) {
// let's not close a menu when replay ends:
cControl : : Shutdown ( ) ;
continue ;
}
}
2007-08-17 14:36:45 +02:00
else if ( Now - cRemote : : LastActivity ( ) > MENUTIMEOUT )
2005-09-03 11:51:54 +02:00
state = osEnd ;
}
2002-10-27 14:32:06 +01:00
switch ( state ) {
2006-01-06 12:53:28 +01:00
case osPause : DELETE_MENU ;
2003-04-21 14:57:13 +02:00
if ( ! cRecordControls : : PauseLiveVideo ( ) )
2013-01-29 11:31:12 +01:00
Skins . QueueMessage ( mtError , tr ( " No free DVB device to record! " ) ) ;
2003-04-21 14:57:13 +02:00
break ;
2006-01-06 12:53:28 +01:00
case osRecord : DELETE_MENU ;
2002-10-27 14:32:06 +01:00
if ( cRecordControls : : Start ( ) )
2013-01-29 11:31:12 +01:00
Skins . QueueMessage ( mtInfo , tr ( " Recording started " ) ) ;
2002-10-27 14:32:06 +01:00
break ;
case osRecordings :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
2013-10-16 09:43:47 +02:00
Menu = new cMenuMain ( osRecordings , true ) ;
2002-10-27 14:32:06 +01:00
break ;
2006-01-06 12:53:28 +01:00
case osReplay : DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
cControl : : Launch ( new cReplayControl ) ;
break ;
case osStopReplay :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
break ;
case osSwitchDvb :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
2013-01-29 11:31:12 +01:00
Skins . QueueMessage ( mtInfo , tr ( " Switching primary DVB... " ) ) ;
2002-10-27 14:32:06 +01:00
cDevice : : SetPrimaryDevice ( Setup . PrimaryDVB ) ;
break ;
2006-01-06 12:53:28 +01:00
case osPlugin : DELETE_MENU ;
2006-01-04 13:22:53 +01:00
Menu = cMenuMain : : PluginOsdObject ( ) ;
2002-11-24 10:45:39 +01:00
if ( Menu )
Menu - > Show ( ) ;
break ;
2002-10-27 14:32:06 +01:00
case osBack :
case osEnd : if ( Interact = = Menu )
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
else
cControl : : Shutdown ( ) ;
break ;
default : ;
}
}
else {
// Key functions in "normal" viewing mode:
2006-01-20 13:19:35 +01:00
if ( key ! = kNone & & KeyMacros . Get ( key ) ) {
2006-01-14 10:54:13 +01:00
cRemote : : PutMacro ( key ) ;
key = kNone ;
}
2010-12-12 13:42:00 +01:00
switch ( int ( key ) ) {
2002-10-27 14:32:06 +01:00
// Toggle channels:
2006-04-15 13:56:03 +02:00
case kChanPrev :
2002-10-27 14:32:06 +01:00
case k0 : {
2003-08-16 15:27:26 +02:00
if ( PreviousChannel [ PreviousChannelIndex ^ 1 ] = = LastChannel | | LastChannel ! = PreviousChannel [ 0 ] & & LastChannel ! = PreviousChannel [ 1 ] )
PreviousChannelIndex ^ = 1 ;
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
Channels - > SwitchTo ( PreviousChannel [ PreviousChannelIndex ^ = 1 ] ) ;
2002-10-27 14:32:06 +01:00
break ;
}
// Direct Channel Select:
case k1 . . . k9 :
2006-04-15 13:46:55 +02:00
// Left/Right rotates through channel groups:
2002-10-27 14:32:06 +01:00
case kLeft | k_Repeat :
case kLeft :
case kRight | k_Repeat :
case kRight :
2006-04-15 13:46:55 +02:00
// Previous/Next rotates through channel groups:
case kPrev | k_Repeat :
case kPrev :
case kNext | k_Repeat :
case kNext :
2002-10-27 14:32:06 +01:00
// Up/Down Channel Select:
case kUp | k_Repeat :
case kUp :
case kDown | k_Repeat :
case kDown :
2006-01-22 14:27:53 +01:00
Menu = new cDisplayChannel ( NORMALKEY ( key ) ) ;
2002-10-27 14:32:06 +01:00
break ;
// Viewing Control:
case kOk : LastChannel = - 1 ; break ; // forces channel display
2005-05-26 10:20:31 +02:00
// Instant resume of the last viewed recording:
case kPlay :
if ( cReplayControl : : LastReplayed ( ) ) {
cControl : : Shutdown ( ) ;
cControl : : Launch ( new cReplayControl ) ;
}
2012-10-03 10:11:15 +02:00
else
DirectMainFunction ( osRecordings ) ; // no last viewed recording, so enter the Recordings menu
2005-05-26 10:20:31 +02:00
break ;
2002-10-27 14:32:06 +01:00
default : break ;
}
}
2000-12-28 12:57:16 +01:00
if ( ! Menu ) {
2006-06-04 09:10:59 +02:00
if ( ! InhibitEpgScan )
2004-02-29 14:21:22 +01:00
EITScanner . Process ( ) ;
2013-10-10 13:13:30 +02:00
bool Error = false ;
if ( RecordingsHandler . Finished ( Error ) ) {
if ( Error )
2013-03-03 10:27:23 +01:00
Skins . Message ( mtError , tr ( " Editing process failed! " ) ) ;
2002-01-26 13:42:15 +01:00
else
2013-03-03 10:27:23 +01:00
Skins . Message ( mtInfo , tr ( " Editing process finished " ) ) ;
2002-01-26 13:42:15 +01:00
}
2000-12-28 12:57:16 +01:00
}
2007-02-25 10:56:29 +01:00
// SIGHUP shall cause a restart:
if ( LastSignal = = SIGHUP ) {
if ( ShutdownHandler . ConfirmRestart ( true ) & & Interface - > Confirm ( tr ( " Press any key to cancel restart " ) , RESTARTCANCELPROMPT , true ) )
EXIT ( 1 ) ;
LastSignal = 0 ;
}
// Update the shutdown countdown:
if ( ShutdownHandler . countdown & & ShutdownHandler . countdown . Update ( ) ) {
if ( ! ShutdownHandler . ConfirmShutdown ( false ) )
ShutdownHandler . countdown . Cancel ( ) ;
}
2015-04-29 13:10:06 +02:00
if ( ( Now - LastInteract ) > ACTIVITYTIMEOUT & & ! cRecordControls : : Active ( ) & & ! RecordingsHandler . Active ( ) & & ( Now - cRemote : : LastActivity ( ) ) > ACTIVITYTIMEOUT ) {
2007-02-25 10:56:29 +01:00
// Handle housekeeping tasks
// Shutdown:
// Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
2007-08-17 14:36:45 +02:00
time_t Soon = Now + SHUTDOWNWAIT ;
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . IsUserInactive ( Soon ) & & ShutdownHandler . Retry ( Soon ) & & ! ShutdownHandler . countdown ) {
if ( ShutdownHandler . ConfirmShutdown ( false ) )
// Time to shut down - start final countdown:
ShutdownHandler . countdown . Start ( tr ( " VDR will shut down in %s minutes " ) , SHUTDOWNWAIT ) ; // the placeholder is really %s!
// Dont try to shut down again for a while:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
2001-02-11 14:53:44 +01:00
}
2007-02-25 10:56:29 +01:00
// Countdown run down to 0?
if ( ShutdownHandler . countdown . Done ( ) ) {
// Timed out, now do a final check:
if ( ShutdownHandler . IsUserInactive ( ) & & ShutdownHandler . ConfirmShutdown ( false ) )
ShutdownHandler . DoShutdown ( false ) ;
// Do this again a bit later:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
}
// Disk housekeeping:
RemoveDeletedRecordings ( ) ;
2015-09-01 11:14:27 +02:00
ListGarbageCollector . Purge ( ) ;
2007-02-25 10:56:29 +01:00
cSchedules : : Cleanup ( ) ;
// Plugins housekeeping:
PluginManager . Housekeeping ( ) ;
2001-02-11 14:53:44 +01:00
}
2007-02-25 10:56:29 +01:00
2012-09-24 13:41:54 +02:00
ReportEpgBugFixStats ( ) ;
2006-04-17 10:30:00 +02:00
// Main thread hooks of plugins:
PluginManager . MainThreadHook ( ) ;
2000-04-15 17:38:11 +02:00
}
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . EmergencyExitRequested ( ) )
esyslog ( " emergency exit requested - shutting down " ) ;
2004-10-23 15:17:03 +02:00
Exit :
2007-04-30 09:24:30 +02:00
// Reset all signal handlers to default before Interface gets deleted:
signal ( SIGHUP , SIG_DFL ) ;
signal ( SIGINT , SIG_DFL ) ;
signal ( SIGTERM , SIG_DFL ) ;
signal ( SIGPIPE , SIG_DFL ) ;
signal ( SIGALRM , SIG_DFL ) ;
2015-09-08 11:08:06 +02:00
StopSVDRPClientHandler ( ) ;
StopSVDRPServerHandler ( ) ;
2017-01-09 13:42:41 +01:00
ChannelCamRelations . Save ( ) ;
2002-06-16 12:57:31 +02:00
cRecordControls : : Shutdown ( ) ;
2017-03-25 14:32:37 +01:00
PluginManager . StopPlugins ( ) ;
2013-10-10 13:13:30 +02:00
RecordingsHandler . DelAll ( ) ;
2000-04-30 10:22:13 +02:00
delete Menu ;
2002-06-23 11:23:34 +02:00
cControl : : Shutdown ( ) ;
2000-10-08 12:24:30 +02:00
delete Interface ;
2004-05-16 10:35:36 +02:00
cOsdProvider : : Shutdown ( ) ;
2002-10-12 15:22:29 +02:00
Remotes . Clear ( ) ;
2002-11-03 11:53:58 +01:00
Audios . Clear ( ) ;
2004-05-16 10:35:36 +02:00
Skins . Clear ( ) ;
2010-02-28 12:19:50 +01:00
SourceParams . Clear ( ) ;
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . GetExitCode ( ) ! = 2 ) {
2005-05-22 11:23:22 +02:00
Setup . CurrentChannel = cDevice : : CurrentChannel ( ) ;
Setup . CurrentVolume = cDevice : : CurrentVolume ( ) ;
Setup . Save ( ) ;
}
2002-06-16 12:57:31 +02:00
cDevice : : Shutdown ( ) ;
2013-08-21 11:02:52 +02:00
cPositioner : : DestroyPositioner ( ) ;
2013-09-11 12:20:37 +02:00
cVideoDirectory : : Destroy ( ) ;
2012-03-10 15:10:43 +01:00
EpgHandlers . Clear ( ) ;
2006-01-28 14:44:32 +01:00
cSchedules : : Cleanup ( true ) ;
2015-09-01 11:14:27 +02:00
ListGarbageCollector . Purge ( true ) ;
PluginManager . Shutdown ( true ) ;
2012-09-24 13:41:54 +02:00
ReportEpgBugFixStats ( true ) ;
2001-02-24 16:18:43 +01:00
if ( WatchdogTimeout > 0 )
2002-05-13 16:35:49 +02:00
dsyslog ( " max. latency time %d seconds " , MaxLatencyTime ) ;
2008-09-06 11:26:01 +02:00
if ( LastSignal )
isyslog ( " caught signal %d " , LastSignal ) ;
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . EmergencyExitRequested ( ) )
esyslog ( " emergency exit! " ) ;
2008-09-06 11:26:01 +02:00
isyslog ( " exiting, exit code %d " , ShutdownHandler . GetExitCode ( ) ) ;
2000-07-29 19:03:09 +02:00
if ( SysLogLevel > 0 )
closelog ( ) ;
2002-12-13 13:41:55 +01:00
if ( HasStdin )
tcsetattr ( STDIN_FILENO , TCSANOW , & savedTm ) ;
2016-12-23 14:36:24 +01:00
# ifdef SDNOTIFY
if ( ShutdownHandler . GetExitCode ( ) = = 2 )
sd_notify ( 0 , " STOPPING=1 \n STATUS=Startup failed, exiting " ) ;
else
sd_notify ( 0 , " STOPPING=1 \n STATUS=Exiting " ) ;
# endif
2007-02-25 10:56:29 +01:00
return ShutdownHandler . GetExitCode ( ) ;
2000-02-19 13:36:48 +01:00
}