mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Rewrite of shutdown handling; implemented cPlugin::WakeupTime(); SIGHUP forces reload; cThread::EmergencyExit() replaced by ShutdownHandler.RequestEmergencyExit()
This commit is contained in:
parent
50b14be807
commit
ddb7f33567
@ -1485,6 +1485,10 @@ Udo Richter <udo_richter@gmx.de>
|
|||||||
for some hints on how to improve handling cPluginManager::Active()
|
for some hints on how to improve handling cPluginManager::Active()
|
||||||
for fixing a possible segfault if VDR gets terminated while a message is displayed
|
for fixing a possible segfault if VDR gets terminated while a message is displayed
|
||||||
for reporting an error in the INSTALL section on retrying shutdown later
|
for reporting an error in the INSTALL section on retrying shutdown later
|
||||||
|
for rewriting shutdown handling
|
||||||
|
for implementing cPlugin::WakeupTime() to allow plugins to request VDR to wake
|
||||||
|
up at a particular time
|
||||||
|
for making the HUP signal force a restart of VDR
|
||||||
|
|
||||||
Sven Kreiensen <svenk@kammer.uni-hannover.de>
|
Sven Kreiensen <svenk@kammer.uni-hannover.de>
|
||||||
for his help in keeping 'channels.conf.terr' up to date
|
for his help in keeping 'channels.conf.terr' up to date
|
||||||
|
7
HISTORY
7
HISTORY
@ -5099,7 +5099,7 @@ Video Disk Recorder Revision History
|
|||||||
- Fixed handling error status in cDvbTuner::GetFrontendStatus() (thanks to
|
- Fixed handling error status in cDvbTuner::GetFrontendStatus() (thanks to
|
||||||
Reinhard Nissl).
|
Reinhard Nissl).
|
||||||
|
|
||||||
2007-02-03: Version 1.5.1
|
2007-02-25: Version 1.5.1
|
||||||
|
|
||||||
- Added cDevice::HasCi() so that devices with Common Interface can be avoided
|
- Added cDevice::HasCi() so that devices with Common Interface can be avoided
|
||||||
when tuning to an FTA channel, thus preserving the CAM resources even on budget
|
when tuning to an FTA channel, thus preserving the CAM resources even on budget
|
||||||
@ -5110,3 +5110,8 @@ Video Disk Recorder Revision History
|
|||||||
Nissl).
|
Nissl).
|
||||||
- Removed 'assert(0)' from cDvbSpuDecoder::setTime() (thanks to Marco Schlüßler).
|
- Removed 'assert(0)' from cDvbSpuDecoder::setTime() (thanks to Marco Schlüßler).
|
||||||
- Adapted 'libsi' to DVB-S2 (thanks to Marco Schlüßler).
|
- Adapted 'libsi' to DVB-S2 (thanks to Marco Schlüßler).
|
||||||
|
- Shutdown handling has been rewritten (thanks to Udo Richter).
|
||||||
|
- Plugins can now implement the new function WakeupTime() to request VDR to wake
|
||||||
|
up at a particular time (thanks to Udo Richter).
|
||||||
|
- The HUP signal now forces a restart of VDR (thanks to Udo Richter).
|
||||||
|
- cThread::EmergencyExit() has been replaced by ShutdownHandler.RequestEmergencyExit().
|
||||||
|
47
INSTALL
47
INSTALL
@ -160,30 +160,33 @@ and the next timer event is at least MinEventTimeout minutes in the future
|
|||||||
(see the Setup parameters in MANUAL).
|
(see the Setup parameters in MANUAL).
|
||||||
|
|
||||||
The command given in the '-s' option will be called with five parameters.
|
The command given in the '-s' option will be called with five parameters.
|
||||||
The first one is the time (in UTC) of the next timer event (as a time_t
|
|
||||||
type number), and the second one is the number of seconds from the current
|
|
||||||
time until the next timer event. Your program can choose which one to use
|
|
||||||
for programming some sort of hardware device that makes sure the computer
|
|
||||||
will be restarted in time before the next timer event. Your program must
|
|
||||||
also initiate the actual shutdown procedure of the computer. After this
|
|
||||||
your program should return to VDR. VDR will not automatically exit after
|
|
||||||
calling the shutdown program, but will rather continue normally until it
|
|
||||||
receives a SIGTERM when the computer is actually shut down. So in case
|
|
||||||
the shutdown fails, or the shutdown program for some reason decides not to
|
|
||||||
perform a shutdown, VDR will stay up and running and will call the shutdown
|
|
||||||
program again after another five minutes.
|
|
||||||
|
|
||||||
If there are currently no timers active, both parameters will be '0'.
|
The first one is the time (in UTC) of the next timer event or plugin wakeup
|
||||||
In that case the program shall not set the hardware for automatic restart
|
time (as a time_t type number), and the second one is the number of
|
||||||
and only perform the system shutdown. A program that uses the second parameter
|
seconds from the current time until the next timer event. Your program can
|
||||||
to set the hardware for restart must therefore also check whether the first
|
choose which one to use for programming some sort of hardware device that
|
||||||
parameter is '0'.
|
makes sure the computer will be restarted in time before the next timer
|
||||||
|
event. Your program must also initiate the actual shutdown procedure of the
|
||||||
|
computer. VDR will not automatically exit after calling the shutdown
|
||||||
|
program, but will rather continue normally until it receives a SIGTERM when
|
||||||
|
the computer is actually shut down. So in case the shutdown fails, or the
|
||||||
|
shutdown program for some reason decides not to perform a shutdown, VDR
|
||||||
|
will stay up and running and will call the shutdown program again after a
|
||||||
|
while. The command will be started in a separate background session, so it
|
||||||
|
can continue to run even after VDR has terminated.
|
||||||
|
|
||||||
The third parameter contains the number of the channel that will be recorded
|
If there are currently no timers active and there is no plugin wakeup
|
||||||
by the next timer (or 0 if no timer is present), and the fourth parameter
|
time, both parameters will be '0'. In that case the program shall not set
|
||||||
contains the file name of the recording as defined in the timer (or an empty
|
the hardware for automatic restart and only perform the system shutdown.
|
||||||
string if no timer is present). These can be used by the shutdown program to
|
A program that uses the second parameter to set the hardware for restart
|
||||||
show that information on some display interface etc.
|
must therefore also check whether the first parameter is '0'.
|
||||||
|
|
||||||
|
If the wakeup time is given by a timer, the third parameter will be the
|
||||||
|
number of the channel that will be recorded, otherwise it will be 0. The
|
||||||
|
fourth parameter contains the file name of the recording as defined in the
|
||||||
|
timer, the name of the plugin that requested the wakeup time, or an empty
|
||||||
|
string if no wakeup time is present. These can be used by the shutdown
|
||||||
|
program to show that information on some display interface etc.
|
||||||
|
|
||||||
The fifth parameter indicates the reason why the shutdown was requested.
|
The fifth parameter indicates the reason why the shutdown was requested.
|
||||||
'0' means this is an automatic shutdown due to some timeout, while '1' means
|
'0' means this is an automatic shutdown due to some timeout, while '1' means
|
||||||
|
4
Makefile
4
Makefile
@ -4,7 +4,7 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# how to reach the author.
|
||||||
#
|
#
|
||||||
# $Id: Makefile 1.96 2007/01/07 14:38:00 kls Exp $
|
# $Id: Makefile 1.97 2007/02/24 13:23:12 kls Exp $
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ SILIB = $(LSIDIR)/libsi.a
|
|||||||
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\
|
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\
|
||||||
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
|
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
|
||||||
lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
|
lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
|
||||||
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o\
|
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\
|
||||||
skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
|
skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
|
||||||
timers.o tools.o transfer.o vdr.o videodir.o
|
timers.o tools.o transfer.o vdr.o videodir.o
|
||||||
|
|
||||||
|
49
PLUGINS.html
49
PLUGINS.html
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<center><h1>The VDR Plugin System</h1></center>
|
<center><h1>The VDR Plugin System</h1></center>
|
||||||
|
|
||||||
<center><b>Version 1.5.0</b></center>
|
<center><b>Version 1.5.1</b></center>
|
||||||
<p>
|
<p>
|
||||||
<center>
|
<center>
|
||||||
Copyright © 2006 Klaus Schmidinger<br>
|
Copyright © 2006 Klaus Schmidinger<br>
|
||||||
@ -14,9 +14,12 @@ Copyright © 2006 Klaus Schmidinger<br>
|
|||||||
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
|
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
|
||||||
</center>
|
</center>
|
||||||
<p>
|
<p>
|
||||||
<!--X1.5.0--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||||
Important modifications introduced in version 1.5.0 are marked like this.
|
Important modifications introduced in version 1.5.0 are marked like this.
|
||||||
<!--X1.5.0--></td></tr></table>
|
<!--X1.5.0--></td></tr></table>
|
||||||
|
<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||||
|
Important modifications introduced in version 1.5.1 are marked like this.
|
||||||
|
<!--X1.5.1--></td></tr></table>
|
||||||
<p>
|
<p>
|
||||||
VDR provides an easy to use plugin interface that allows additional functionality
|
VDR provides an easy to use plugin interface that allows additional functionality
|
||||||
to be added to the program by implementing a dynamically loadable library file.
|
to be added to the program by implementing a dynamically loadable library file.
|
||||||
@ -55,6 +58,9 @@ structures and allows it to hook itself into specific areas to perform special a
|
|||||||
<li><a href="#Housekeeping">Housekeeping</a>
|
<li><a href="#Housekeeping">Housekeeping</a>
|
||||||
<li><a href="#Main thread hook">Main thread hook</a>
|
<li><a href="#Main thread hook">Main thread hook</a>
|
||||||
<li><a href="#Activity">Activity</a>
|
<li><a href="#Activity">Activity</a>
|
||||||
|
<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||||
|
<li><a href="#Wakeup">Wakeup</a>
|
||||||
|
<!--X1.5.1--></td></tr></table>
|
||||||
<li><a href="#Setup parameters">Setup parameters</a>
|
<li><a href="#Setup parameters">Setup parameters</a>
|
||||||
<li><a href="#The Setup menu">The Setup menu</a>
|
<li><a href="#The Setup menu">The Setup menu</a>
|
||||||
<li><a href="#Configuration files">Configuration files</a>
|
<li><a href="#Configuration files">Configuration files</a>
|
||||||
@ -76,7 +82,7 @@ structures and allows it to hook itself into specific areas to perform special a
|
|||||||
<li><a href="#Devices">Devices</a>
|
<li><a href="#Devices">Devices</a>
|
||||||
<li><a href="#Audio">Audio</a>
|
<li><a href="#Audio">Audio</a>
|
||||||
<li><a href="#Remote Control">Remote Control</a>
|
<li><a href="#Remote Control">Remote Control</a>
|
||||||
<!--X1.5.0--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||||
<li><a href="#Conditional Access">Conditional Access</a>
|
<li><a href="#Conditional Access">Conditional Access</a>
|
||||||
<!--X1.5.0--></td></tr></table>
|
<!--X1.5.0--></td></tr></table>
|
||||||
</ul>
|
</ul>
|
||||||
@ -675,6 +681,41 @@ be queried, and further prompts may show up. If all prompts have been confirmed,
|
|||||||
the shutdown will take place. As soon as one prompt is not confirmed, no
|
the shutdown will take place. As soon as one prompt is not confirmed, no
|
||||||
further plugins will be queried and no shutdown will be done.
|
further plugins will be queried and no shutdown will be done.
|
||||||
|
|
||||||
|
<!--X1.5.1--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||||
|
<a name="Wakeup"><hr><h2>Wakeup</h2>
|
||||||
|
|
||||||
|
<center><i><b>Wake me up before you go-go</b></i></center><p>
|
||||||
|
|
||||||
|
If a plugin wants to schedule activity for a later time, or wants to perform
|
||||||
|
periodic activity at a certain time at night, and if VDR shall wake up from
|
||||||
|
shutdown at that time, the plugin can implement the function
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=#F0F0F0><pre>
|
||||||
|
virtual time_t WakeupTime(void);
|
||||||
|
</pre></td></tr></table><p>
|
||||||
|
|
||||||
|
which shall return the time of the next custom wakeup time, or 0 if no wakeup
|
||||||
|
is planned. VDR will pass the most recent wakeup time of all plugins, or the next
|
||||||
|
timer time, whichever comes first, to the shutdown script. The following sample
|
||||||
|
will wake up VDR every night at 1:00:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=#F0F0F0><pre>
|
||||||
|
time_t MyPlugin::WakeupTime(void)
|
||||||
|
{
|
||||||
|
time_t Now = time(NULL);
|
||||||
|
time_t Time = cTimer::SetTime(Now, cTimer::TimeToInt(100));
|
||||||
|
if (Time <= Now)
|
||||||
|
Time = cTimer::IncDay(Time, 1);
|
||||||
|
return Time;
|
||||||
|
}
|
||||||
|
</pre></td></tr></table><p>
|
||||||
|
|
||||||
|
After wakeup, the plugin shall continue to return the wakeup time and shall
|
||||||
|
return a string when <tt>Active()</tt> is called at that time, otherwise VDR may shut down
|
||||||
|
again instantly. If <tt>WakeupTime()</tt> returns a time that is not in
|
||||||
|
the future, the time will be ignored.
|
||||||
|
<!--X1.5.1--></td></tr></table>
|
||||||
|
|
||||||
<a name="Setup parameters"><hr><h2>Setup parameters</h2>
|
<a name="Setup parameters"><hr><h2>Setup parameters</h2>
|
||||||
|
|
||||||
<center><i><b>Remember me...</b></i></center><p>
|
<center><i><b>Remember me...</b></i></center><p>
|
||||||
@ -2046,7 +2087,7 @@ Put(uint64 Code, bool Repeat = false, bool Release = false);
|
|||||||
|
|
||||||
The other parameters have the same meaning as in the first version of this function.
|
The other parameters have the same meaning as in the first version of this function.
|
||||||
|
|
||||||
<!--X1.5.0--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
<!--X1.5.0--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||||
<a name="Conditional Access"><hr><h2>Conditional Access</h2>
|
<a name="Conditional Access"><hr><h2>Conditional Access</h2>
|
||||||
|
|
||||||
<center><i><b>Members only!</b></i></center><p>
|
<center><i><b>Members only!</b></i></center><p>
|
||||||
|
5
config.c
5
config.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.c 1.147 2007/01/26 13:32:19 kls Exp $
|
* $Id: config.c 1.148 2007/02/24 13:29:52 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -267,6 +267,7 @@ cSetup::cSetup(void)
|
|||||||
SplitEditedFiles = 0;
|
SplitEditedFiles = 0;
|
||||||
MinEventTimeout = 30;
|
MinEventTimeout = 30;
|
||||||
MinUserInactivity = 300;
|
MinUserInactivity = 300;
|
||||||
|
NextWakeupTime = 0;
|
||||||
MultiSpeedMode = 0;
|
MultiSpeedMode = 0;
|
||||||
ShowReplayMode = 0;
|
ShowReplayMode = 0;
|
||||||
ResumeID = 0;
|
ResumeID = 0;
|
||||||
@ -428,6 +429,7 @@ bool cSetup::Parse(const char *Name, const char *Value)
|
|||||||
else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
|
else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
|
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
|
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
|
||||||
|
else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
|
else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
|
else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value);
|
else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value);
|
||||||
@ -496,6 +498,7 @@ bool cSetup::Save(void)
|
|||||||
Store("SplitEditedFiles", SplitEditedFiles);
|
Store("SplitEditedFiles", SplitEditedFiles);
|
||||||
Store("MinEventTimeout", MinEventTimeout);
|
Store("MinEventTimeout", MinEventTimeout);
|
||||||
Store("MinUserInactivity", MinUserInactivity);
|
Store("MinUserInactivity", MinUserInactivity);
|
||||||
|
Store("NextWakeupTime", NextWakeupTime);
|
||||||
Store("MultiSpeedMode", MultiSpeedMode);
|
Store("MultiSpeedMode", MultiSpeedMode);
|
||||||
Store("ShowReplayMode", ShowReplayMode);
|
Store("ShowReplayMode", ShowReplayMode);
|
||||||
Store("ResumeID", ResumeID);
|
Store("ResumeID", ResumeID);
|
||||||
|
3
config.h
3
config.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.h 1.284 2007/01/13 11:42:43 kls Exp $
|
* $Id: config.h 1.285 2007/02/24 13:23:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -244,6 +244,7 @@ public:
|
|||||||
int MaxVideoFileSize;
|
int MaxVideoFileSize;
|
||||||
int SplitEditedFiles;
|
int SplitEditedFiles;
|
||||||
int MinEventTimeout, MinUserInactivity;
|
int MinEventTimeout, MinUserInactivity;
|
||||||
|
time_t NextWakeupTime;
|
||||||
int MultiSpeedMode;
|
int MultiSpeedMode;
|
||||||
int ShowReplayMode;
|
int ShowReplayMode;
|
||||||
int ResumeID;
|
int ResumeID;
|
||||||
|
134
i18n.c
134
i18n.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: i18n.c 1.287 2007/01/26 13:26:05 kls Exp $
|
* $Id: i18n.c 1.288 2007/02/25 10:11:26 kls Exp $
|
||||||
*
|
*
|
||||||
* Translations provided by:
|
* Translations provided by:
|
||||||
*
|
*
|
||||||
@ -1341,6 +1341,28 @@ const tI18nPhrase Phrases[] = {
|
|||||||
"Optagelse igang - genstart alligevel?",
|
"Optagelse igang - genstart alligevel?",
|
||||||
"Systém je zaneprázdnìn - pøesto restartovat?",
|
"Systém je zaneprázdnìn - pøesto restartovat?",
|
||||||
},
|
},
|
||||||
|
{ "Editing - restart anyway?",
|
||||||
|
"Schnitt läuft - trotzdem neu starten?",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
{ "Recording - shut down anyway?",
|
{ "Recording - shut down anyway?",
|
||||||
"Aufnahme läuft - trotzdem ausschalten?",
|
"Aufnahme läuft - trotzdem ausschalten?",
|
||||||
"Snemanje - zares izklopi?",
|
"Snemanje - zares izklopi?",
|
||||||
@ -1407,6 +1429,116 @@ const tI18nPhrase Phrases[] = {
|
|||||||
"Tryk vilkårlig tast for at annullere sluk",
|
"Tryk vilkårlig tast for at annullere sluk",
|
||||||
"Jakákoliv klávesa zru¹í vypnutí",
|
"Jakákoliv klávesa zru¹í vypnutí",
|
||||||
},
|
},
|
||||||
|
{ "Press any key to cancel restart",
|
||||||
|
"Taste drücken, um Neustart abzubrechen",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
|
{ "VDR will shut down later - press Power to force",
|
||||||
|
"VDR schaltet später aus - Power zum erzwingen",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"VDR sammuu myöhemmin - pakota virtakytkimellä",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
|
{ "VDR will shut down in %s minutes",
|
||||||
|
"VDR wird in %s Minuten ausschalten",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"VDR sammuu %s minuutin kuluttua",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
|
{ "Editing - shut down anyway?",
|
||||||
|
"Schnitt läuft - trotzdem ausschalten?",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"Leikkaus kesken - sammutetaanko?",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
|
{ "Plugin %s wakes up in %ld min, continue?",
|
||||||
|
"Plugin %s wacht in %ld Min auf, weiter?",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"Laajennos %s herää %ld minuutin kuluttua - sammutetaanko?",
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
"",//TODO
|
||||||
|
},
|
||||||
// Channel parameters:
|
// Channel parameters:
|
||||||
{ "Name",
|
{ "Name",
|
||||||
"Name",
|
"Name",
|
||||||
|
3
keys.h
3
keys.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: keys.h 1.10 2006/10/14 10:41:20 kls Exp $
|
* $Id: keys.h 1.11 2007/02/25 10:49:35 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __KEYS_H
|
#ifndef __KEYS_H
|
||||||
@ -74,6 +74,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
|
|||||||
#define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0)
|
#define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0)
|
||||||
#define NORMALKEY(k) (eKeys((k) & ~k_Repeat))
|
#define NORMALKEY(k) (eKeys((k) & ~k_Repeat))
|
||||||
#define ISMODELESSKEY(k) (RAWKEY(k) > k9)
|
#define ISMODELESSKEY(k) (RAWKEY(k) > k9)
|
||||||
|
#define ISREALKEY(k) (k != kNone && k != k_Plugin)
|
||||||
|
|
||||||
#define BASICKEY(k) (eKeys((k) & 0xFFFF))
|
#define BASICKEY(k) (eKeys((k) & 0xFFFF))
|
||||||
#define KBDKEY(k) (eKeys(((k) << 16) | kKbd))
|
#define KBDKEY(k) (eKeys(((k) << 16) | kKbd))
|
||||||
|
11
menu.c
11
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menu.c 1.447 2007/01/07 14:19:48 kls Exp $
|
* $Id: menu.c 1.448 2007/02/25 09:51:53 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
|
#include "shutdown.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "themes.h"
|
#include "themes.h"
|
||||||
@ -2770,10 +2771,8 @@ void cMenuSetup::Set(void)
|
|||||||
|
|
||||||
eOSState cMenuSetup::Restart(void)
|
eOSState cMenuSetup::Restart(void)
|
||||||
{
|
{
|
||||||
if (Interface->Confirm(tr("Really restart?"))
|
if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
|
||||||
&& (!cRecordControls::Active() || Interface->Confirm(tr("Recording - restart anyway?")))
|
ShutdownHandler.Exit(1);
|
||||||
&& !cPluginManager::Active(tr("restart anyway?"))) {
|
|
||||||
cThread::EmergencyExit(true);
|
|
||||||
return osEnd;
|
return osEnd;
|
||||||
}
|
}
|
||||||
return osContinue;
|
return osContinue;
|
||||||
@ -3699,7 +3698,7 @@ bool cRecordControls::Start(cTimer *Timer, bool Pause)
|
|||||||
if (device) {
|
if (device) {
|
||||||
dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
|
dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
|
||||||
if (!device->SwitchChannel(channel, false)) {
|
if (!device->SwitchChannel(channel, false)) {
|
||||||
cThread::EmergencyExit(true);
|
ShutdownHandler.RequestEmergencyExit();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Timer || Timer->Matches()) {
|
if (!Timer || Timer->Matches()) {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# how to reach the author.
|
||||||
#
|
#
|
||||||
# $Id: newplugin 1.30 2006/09/09 12:38:35 kls Exp $
|
# $Id: newplugin 1.31 2007/02/24 13:23:08 kls Exp $
|
||||||
|
|
||||||
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
|
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
|
||||||
|
|
||||||
@ -169,6 +169,7 @@ public:
|
|||||||
virtual void Housekeeping(void);
|
virtual void Housekeeping(void);
|
||||||
virtual void MainThreadHook(void);
|
virtual void MainThreadHook(void);
|
||||||
virtual cString Active(void);
|
virtual cString Active(void);
|
||||||
|
virtual time_t WakeupTime(void);
|
||||||
virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
|
virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
|
||||||
virtual cOsdObject *MainMenuAction(void);
|
virtual cOsdObject *MainMenuAction(void);
|
||||||
virtual cMenuSetupPage *SetupMenu(void);
|
virtual cMenuSetupPage *SetupMenu(void);
|
||||||
@ -236,6 +237,12 @@ cString cPlugin${PLUGIN_CLASS}::Active(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t cPlugin${PLUGIN_CLASS}::WakeupTime(void)
|
||||||
|
{
|
||||||
|
// Return custom wakeup time for shutdown script
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cOsdObject *cPlugin${PLUGIN_CLASS}::MainMenuAction(void)
|
cOsdObject *cPlugin${PLUGIN_CLASS}::MainMenuAction(void)
|
||||||
{
|
{
|
||||||
// Perform the action when selected from the main VDR menu.
|
// Perform the action when selected from the main VDR menu.
|
||||||
|
27
plugin.c
27
plugin.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: plugin.c 1.24 2006/10/14 09:49:16 kls Exp $
|
* $Id: plugin.c 1.25 2007/02/24 13:44:23 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@ -80,6 +80,11 @@ cString cPlugin::Active(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t cPlugin::WakeupTime(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *cPlugin::MainMenuEntry(void)
|
const char *cPlugin::MainMenuEntry(void)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -403,6 +408,26 @@ bool cPluginManager::Active(const char *Prompt)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cPlugin *cPluginManager::GetNextWakeupPlugin(void)
|
||||||
|
{
|
||||||
|
cPlugin *NextPlugin = NULL;
|
||||||
|
if (pluginManager) {
|
||||||
|
time_t Now = time(NULL);
|
||||||
|
time_t Next = 0;
|
||||||
|
for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
|
||||||
|
cPlugin *p = dll->Plugin();
|
||||||
|
if (p) {
|
||||||
|
time_t t = p->WakeupTime();
|
||||||
|
if (t > Now && (!Next || t < Next)) {
|
||||||
|
Next = t;
|
||||||
|
NextPlugin = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NextPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
bool cPluginManager::HasPlugins(void)
|
bool cPluginManager::HasPlugins(void)
|
||||||
{
|
{
|
||||||
return pluginManager && pluginManager->dlls.Count();
|
return pluginManager && pluginManager->dlls.Count();
|
||||||
|
4
plugin.h
4
plugin.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: plugin.h 1.13 2006/04/17 09:18:16 kls Exp $
|
* $Id: plugin.h 1.14 2007/02/24 13:45:28 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PLUGIN_H
|
#ifndef __PLUGIN_H
|
||||||
@ -41,6 +41,7 @@ public:
|
|||||||
virtual void Housekeeping(void);
|
virtual void Housekeeping(void);
|
||||||
virtual void MainThreadHook(void);
|
virtual void MainThreadHook(void);
|
||||||
virtual cString Active(void);
|
virtual cString Active(void);
|
||||||
|
virtual time_t WakeupTime(void);
|
||||||
|
|
||||||
virtual const char *MainMenuEntry(void);
|
virtual const char *MainMenuEntry(void);
|
||||||
virtual cOsdObject *MainMenuAction(void);
|
virtual cOsdObject *MainMenuAction(void);
|
||||||
@ -93,6 +94,7 @@ public:
|
|||||||
void Housekeeping(void);
|
void Housekeeping(void);
|
||||||
void MainThreadHook(void);
|
void MainThreadHook(void);
|
||||||
static bool Active(const char *Prompt = NULL);
|
static bool Active(const char *Prompt = NULL);
|
||||||
|
static cPlugin *GetNextWakeupPlugin(void);
|
||||||
static bool HasPlugins(void);
|
static bool HasPlugins(void);
|
||||||
static cPlugin *GetPlugin(int Index);
|
static cPlugin *GetPlugin(int Index);
|
||||||
static cPlugin *GetPlugin(const char *Name);
|
static cPlugin *GetPlugin(const char *Name);
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: recorder.c 1.18 2007/01/07 14:43:09 kls Exp $
|
* $Id: recorder.c 1.19 2007/02/24 16:36:24 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include "shutdown.h"
|
||||||
|
|
||||||
#define RECORDERBUFSIZE MEGABYTE(5)
|
#define RECORDERBUFSIZE MEGABYTE(5)
|
||||||
|
|
||||||
@ -117,7 +118,7 @@ void cFileWriter::Action(void)
|
|||||||
}
|
}
|
||||||
else if (time(NULL) - t > MAXBROKENTIMEOUT) {
|
else if (time(NULL) - t > MAXBROKENTIMEOUT) {
|
||||||
esyslog("ERROR: video data stream broken");
|
esyslog("ERROR: video data stream broken");
|
||||||
cThread::EmergencyExit(true);
|
ShutdownHandler.RequestEmergencyExit();
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
remote.c
4
remote.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: remote.c 1.55 2006/12/02 11:12:42 kls Exp $
|
* $Id: remote.c 1.56 2007/02/24 13:23:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
@ -31,6 +31,7 @@ cMutex cRemote::mutex;
|
|||||||
cCondVar cRemote::keyPressed;
|
cCondVar cRemote::keyPressed;
|
||||||
const char *cRemote::keyMacroPlugin = NULL;
|
const char *cRemote::keyMacroPlugin = NULL;
|
||||||
const char *cRemote::callPlugin = NULL;
|
const char *cRemote::callPlugin = NULL;
|
||||||
|
time_t cRemote::lastActivity = 0;
|
||||||
|
|
||||||
cRemote::cRemote(const char *Name)
|
cRemote::cRemote(const char *Name)
|
||||||
{
|
{
|
||||||
@ -183,6 +184,7 @@ eKeys cRemote::Get(int WaitMs, char **UnknownCode)
|
|||||||
out = 0;
|
out = 0;
|
||||||
if ((k & k_Repeat) != 0)
|
if ((k & k_Repeat) != 0)
|
||||||
repeatTimeout.Set(REPEATTIMEOUT);
|
repeatTimeout.Set(REPEATTIMEOUT);
|
||||||
|
lastActivity = time(NULL);
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs) && repeatTimeout.TimedOut())
|
else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs) && repeatTimeout.TimedOut())
|
||||||
|
5
remote.h
5
remote.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: remote.h 1.38 2006/12/02 11:12:49 kls Exp $
|
* $Id: remote.h 1.39 2007/02/24 15:53:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __REMOTE_H
|
#ifndef __REMOTE_H
|
||||||
@ -28,6 +28,7 @@ private:
|
|||||||
static char *unknownCode;
|
static char *unknownCode;
|
||||||
static cMutex mutex;
|
static cMutex mutex;
|
||||||
static cCondVar keyPressed;
|
static cCondVar keyPressed;
|
||||||
|
static time_t lastActivity;
|
||||||
static const char *keyMacroPlugin;
|
static const char *keyMacroPlugin;
|
||||||
static const char *callPlugin;
|
static const char *callPlugin;
|
||||||
char *name;
|
char *name;
|
||||||
@ -61,6 +62,8 @@ public:
|
|||||||
///< plugin name will be reset to NULL by this call.
|
///< plugin name will be reset to NULL by this call.
|
||||||
static bool HasKeys(void);
|
static bool HasKeys(void);
|
||||||
static eKeys Get(int WaitMs = 1000, char **UnknownCode = NULL);
|
static eKeys Get(int WaitMs = 1000, char **UnknownCode = NULL);
|
||||||
|
static time_t LastActivity(void) { return lastActivity; }
|
||||||
|
///< Absolute time when last key was delivered by Get().
|
||||||
};
|
};
|
||||||
|
|
||||||
class cRemotes : public cList<cRemote> {};
|
class cRemotes : public cList<cRemote> {};
|
||||||
|
8
remux.c
8
remux.c
@ -11,13 +11,13 @@
|
|||||||
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
|
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
|
||||||
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
|
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
|
||||||
*
|
*
|
||||||
* $Id: remux.c 1.57 2006/12/01 14:46:25 kls Exp $
|
* $Id: remux.c 1.58 2007/02/24 16:36:10 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "thread.h"
|
#include "shutdown.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
|
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
|
||||||
@ -2011,7 +2011,7 @@ int cRemux::Put(const uchar *Data, int Count)
|
|||||||
esyslog("ERROR: no useful data seen within %d byte of video stream", skipped);
|
esyslog("ERROR: no useful data seen within %d byte of video stream", skipped);
|
||||||
skipped = -1;
|
skipped = -1;
|
||||||
if (exitOnFailure)
|
if (exitOnFailure)
|
||||||
cThread::EmergencyExit(true);
|
ShutdownHandler.RequestEmergencyExit();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skipped += used;
|
skipped += used;
|
||||||
@ -2059,7 +2059,7 @@ uchar *cRemux::Get(int &Count, uchar *PictureType)
|
|||||||
if (pt < I_FRAME || B_FRAME < pt) {
|
if (pt < I_FRAME || B_FRAME < pt) {
|
||||||
esyslog("ERROR: unknown picture type '%d'", pt);
|
esyslog("ERROR: unknown picture type '%d'", pt);
|
||||||
if (++numUPTerrors > MAXNUMUPTERRORS && exitOnFailure)
|
if (++numUPTerrors > MAXNUMUPTERRORS && exitOnFailure)
|
||||||
cThread::EmergencyExit(true);
|
ShutdownHandler.RequestEmergencyExit();
|
||||||
}
|
}
|
||||||
else if (!synced) {
|
else if (!synced) {
|
||||||
if (pt == I_FRAME) {
|
if (pt == I_FRAME) {
|
||||||
|
250
shutdown.c
Normal file
250
shutdown.c
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* shutdown.c: Handling of shutdown and inactivity
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* Original version written by Udo Richter <udo_richter@gmx.de>.
|
||||||
|
*
|
||||||
|
* $Id: shutdown.c 1.1 2007/02/24 17:24:11 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shutdown.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include "channels.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "cutter.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
#include "interface.h"
|
||||||
|
#include "menu.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "timers.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
cShutdownHandler ShutdownHandler;
|
||||||
|
|
||||||
|
cCountdown::cCountdown(void)
|
||||||
|
{
|
||||||
|
timeout = 0;
|
||||||
|
counter = 0;
|
||||||
|
timedOut = false;
|
||||||
|
message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCountdown::Start(const char *Message, int Seconds)
|
||||||
|
{
|
||||||
|
timeout = time(NULL) + Seconds;
|
||||||
|
counter = -1;
|
||||||
|
timedOut = false;
|
||||||
|
message = Message;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCountdown::Cancel(void)
|
||||||
|
{
|
||||||
|
if (timeout) {
|
||||||
|
timeout = 0;
|
||||||
|
timedOut = false;
|
||||||
|
Skins.Message(mtStatus, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCountdown::Done(void)
|
||||||
|
{
|
||||||
|
if (timedOut) {
|
||||||
|
Cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCountdown::Update(void)
|
||||||
|
{
|
||||||
|
if (timeout) {
|
||||||
|
int NewCounter = (timeout - time(NULL) + 9) / 10;
|
||||||
|
if (NewCounter <= 0)
|
||||||
|
timedOut = true;
|
||||||
|
if (counter != NewCounter) {
|
||||||
|
counter = NewCounter;
|
||||||
|
char time[10];
|
||||||
|
snprintf(time, sizeof(time), "%d:%d0", counter > 0 ? counter / 6 : 0, counter > 0 ? counter % 6 : 0);
|
||||||
|
cString Message = cString::sprintf(message, time);
|
||||||
|
Skins.Message(mtStatus, Message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cShutdownHandler::cShutdownHandler(void)
|
||||||
|
{
|
||||||
|
activeTimeout = 0;
|
||||||
|
retry = 0;
|
||||||
|
shutdownCommand = NULL;
|
||||||
|
exitCode = -1;
|
||||||
|
emergencyExitRequested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cShutdownHandler::~cShutdownHandler()
|
||||||
|
{
|
||||||
|
free(shutdownCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cShutdownHandler::RequestEmergencyExit(void)
|
||||||
|
{
|
||||||
|
esyslog("initiating emergency exit");
|
||||||
|
emergencyExitRequested = true;
|
||||||
|
Exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cShutdownHandler::CheckManualStart(int ManualStart)
|
||||||
|
{
|
||||||
|
time_t Delta = Setup.NextWakeupTime ? Setup.NextWakeupTime - time(NULL) : 0;
|
||||||
|
|
||||||
|
if (!Setup.NextWakeupTime || abs(Delta) > ManualStart) {
|
||||||
|
// Apparently the user started VDR manually
|
||||||
|
dsyslog("assuming manual start of VDR");
|
||||||
|
// Set inactive after MinUserInactivity
|
||||||
|
SetUserInactiveTimeout();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Set inactive from now on
|
||||||
|
SetUserInactive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cShutdownHandler::SetShutdownCommand(const char *ShutdownCommand)
|
||||||
|
{
|
||||||
|
free(shutdownCommand);
|
||||||
|
shutdownCommand = ShutdownCommand ? strdup(ShutdownCommand) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cShutdownHandler::CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
|
||||||
|
{
|
||||||
|
time_t Delta = WakeupTime ? WakeupTime - time(NULL) : 0;
|
||||||
|
cString cmd = cString::sprintf("%s %ld %ld %d \"%s\" %d", shutdownCommand, WakeupTime, Delta, Channel, *strescape(File, "\"$"), UserShutdown);
|
||||||
|
isyslog("executing '%s'", *cmd);
|
||||||
|
if (SystemExec(cmd, true) == 0)
|
||||||
|
Setup.NextWakeupTime = WakeupTime; // Remember this wakeup time for comparison on reboot
|
||||||
|
}
|
||||||
|
|
||||||
|
void cShutdownHandler::SetUserInactiveTimeout(int Seconds, bool Force)
|
||||||
|
{
|
||||||
|
if (!Setup.MinUserInactivity && !Force) {
|
||||||
|
activeTimeout = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Seconds < 0)
|
||||||
|
Seconds = Setup.MinUserInactivity * 60;
|
||||||
|
activeTimeout = time(NULL) + Seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cShutdownHandler::ConfirmShutdown(bool Interactive)
|
||||||
|
{
|
||||||
|
if (!shutdownCommand) {
|
||||||
|
if (Interactive)
|
||||||
|
Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cCutter::Active()) {
|
||||||
|
if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?")))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer *timer = Timers.GetNextActiveTimer();
|
||||||
|
time_t Next = timer ? timer->StartTime() : 0;
|
||||||
|
time_t Delta = timer ? Next - time(NULL) : 0;
|
||||||
|
|
||||||
|
if (cRecordControls::Active() || (Next && Delta <= 0)) {
|
||||||
|
// VPS recordings in timer end margin may cause Delta <= 0
|
||||||
|
if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?")))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (Next && Delta <= Setup.MinEventTimeout * 60) {
|
||||||
|
// Timer within Min Event Timeout
|
||||||
|
if (!Interactive)
|
||||||
|
return false;
|
||||||
|
cString buf = cString::sprintf(tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
|
||||||
|
if (!Interface->Confirm(buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cPlugin *Plugin = cPluginManager::GetNextWakeupPlugin();
|
||||||
|
Next = Plugin ? Plugin->WakeupTime() : 0;
|
||||||
|
Delta = Next ? Next - time(NULL) : 0;
|
||||||
|
if (Next && Delta <= Setup.MinEventTimeout * 60) {
|
||||||
|
// Plugin wakeup within Min Event Timeout
|
||||||
|
if (!Interactive)
|
||||||
|
return false;
|
||||||
|
cString buf = cString::sprintf(tr("Plugin %s wakes up in %ld min, continue?"), Plugin->Name(), Delta / 60);
|
||||||
|
if (!Interface->Confirm(buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cShutdownHandler::ConfirmRestart(bool Interactive)
|
||||||
|
{
|
||||||
|
if (cCutter::Active()) {
|
||||||
|
if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?")))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer *timer = Timers.GetNextActiveTimer();
|
||||||
|
time_t Next = timer ? timer->StartTime() : 0;
|
||||||
|
time_t Delta = timer ? Next - time(NULL) : 0;
|
||||||
|
|
||||||
|
if (cRecordControls::Active() || (Next && Delta <= 0)) {
|
||||||
|
// VPS recordings in timer end margin may cause Delta <= 0
|
||||||
|
if (!Interactive || !Interface->Confirm(tr("Recording - restart anyway?")))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cPluginManager::Active(Interactive ? tr("restart anyway?") : NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cShutdownHandler::DoShutdown(bool Force)
|
||||||
|
{
|
||||||
|
time_t Now = time(NULL);
|
||||||
|
cTimer *timer = Timers.GetNextActiveTimer();
|
||||||
|
cPlugin *Plugin = cPluginManager::GetNextWakeupPlugin();
|
||||||
|
|
||||||
|
time_t Next = timer ? timer->StartTime() : 0;
|
||||||
|
time_t NextPlugin = Plugin ? Plugin->WakeupTime() : 0;
|
||||||
|
if (NextPlugin && (!Next || Next > NextPlugin)) {
|
||||||
|
Next = NextPlugin;
|
||||||
|
timer = NULL;
|
||||||
|
}
|
||||||
|
time_t Delta = Next ? Next - Now : 0;
|
||||||
|
|
||||||
|
if (Next && Delta < Setup.MinEventTimeout * 60) {
|
||||||
|
if (!Force)
|
||||||
|
return false;
|
||||||
|
Delta = Setup.MinEventTimeout * 60;
|
||||||
|
Next = Now + Delta;
|
||||||
|
timer = NULL;
|
||||||
|
dsyslog("reboot at %s", *TimeToString(Next));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Next && timer) {
|
||||||
|
dsyslog("next timer event at %s", *TimeToString(Next));
|
||||||
|
CallShutdownCommand(Next, timer->Channel()->Number(), timer->File(), Force);
|
||||||
|
}
|
||||||
|
else if (Next && Plugin) {
|
||||||
|
CallShutdownCommand(Next, 0, Plugin->Name(), Force);
|
||||||
|
dsyslog("next plugin wakeup at %s", *TimeToString(Next));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CallShutdownCommand(Next, 0, "", Force); // Next should always be 0 here. Just for safety, pass it.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
112
shutdown.h
Normal file
112
shutdown.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* shutdown.h: Handling of shutdown and inactivity
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* Original version written by Udo Richter <udo_richter@gmx.de>.
|
||||||
|
*
|
||||||
|
* $Id: shutdown.h 1.1 2007/02/24 17:23:59 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHUTDOWN_H
|
||||||
|
#define __SHUTDOWN_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
class cCountdown {
|
||||||
|
private:
|
||||||
|
time_t timeout; ///< 5-minute countdown timer
|
||||||
|
int counter; ///< last shown time in 10s units
|
||||||
|
bool timedOut; ///< countdown did run down to 0 and was not canceled
|
||||||
|
const char *message; ///< message to display, %s is placeholder for time
|
||||||
|
public:
|
||||||
|
cCountdown(void);
|
||||||
|
void Start(const char *Message, int Seconds);
|
||||||
|
///< Start the 5 minute shutdown warning countdown.
|
||||||
|
void Cancel(void);
|
||||||
|
///< Cancel the 5 minute shutdown warning countdown.
|
||||||
|
bool Done(void);
|
||||||
|
///< Check if countdown timer has run out without canceling.
|
||||||
|
operator bool(void) const { return timeout != 0; }
|
||||||
|
///< Check if countdown is running.
|
||||||
|
bool Update(void);
|
||||||
|
///< Update status display of the countdown.
|
||||||
|
///< Returns true on actual update.
|
||||||
|
};
|
||||||
|
|
||||||
|
class cShutdownHandler {
|
||||||
|
private:
|
||||||
|
time_t activeTimeout;
|
||||||
|
///< Time when VDR will become non-interactive. 0 means never.
|
||||||
|
time_t retry;
|
||||||
|
///< Time for retrying the shutdown.
|
||||||
|
char *shutdownCommand;
|
||||||
|
///< Command for shutting down VDR.
|
||||||
|
int exitCode;
|
||||||
|
///< Exit code, if VDR exit was requested, or -1 if not requested.
|
||||||
|
bool emergencyExitRequested;
|
||||||
|
///< The requested exit is an emergency exit.
|
||||||
|
public:
|
||||||
|
cCountdown countdown;
|
||||||
|
cShutdownHandler(void);
|
||||||
|
~cShutdownHandler();
|
||||||
|
void Exit(int ExitCode) { exitCode = ExitCode; }
|
||||||
|
///< Set VDR exit code and initiate end of VDR main loop.
|
||||||
|
///< This will exit VDR without any confirmation.
|
||||||
|
bool DoExit(void) { return exitCode >= 0; }
|
||||||
|
///< Check if an exit code was set, and VDR should exit.
|
||||||
|
int GetExitCode(void) { return exitCode >= 0 ? exitCode : 0; }
|
||||||
|
///< Get the currently set exit code of VDR.
|
||||||
|
bool EmergencyExitRequested(void) { return emergencyExitRequested; }
|
||||||
|
///< Returns true if an emergency exit was requested.
|
||||||
|
void RequestEmergencyExit(void);
|
||||||
|
///< Requests an emergency exit of the VDR main loop.
|
||||||
|
void CheckManualStart(int ManualStart);
|
||||||
|
///< Check whether the next timer is in ManualStart time window.
|
||||||
|
///< If yes, assume non-interactive use.
|
||||||
|
void SetShutdownCommand(const char *ShutdownCommand);
|
||||||
|
///< Set the command string for shutdown command.
|
||||||
|
void CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown);
|
||||||
|
///< Call the shutdown command with the given parameters.
|
||||||
|
bool IsUserInactive(time_t AtTime = 0) { return activeTimeout && activeTimeout <= (AtTime ? AtTime : time(NULL)); }
|
||||||
|
///< Check whether VDR is in interactive mode or non-interactive mode (waiting for shutdown).
|
||||||
|
///< AtTime checks whether VDR will probably be inactive at that time.
|
||||||
|
time_t GetUserInactiveTime(void) { return activeTimeout; }
|
||||||
|
///< Time when user will become non-inactive, or 0 if never.
|
||||||
|
void SetUserInactiveTimeout(int Seconds = -1, bool Force = false);
|
||||||
|
///< Set the time when VDR will switch into non-interactive mode or power down.
|
||||||
|
///< -1 means Setup.MinUserInactivity in the future.
|
||||||
|
///< Otherwise, seconds in the future.
|
||||||
|
///< If MinUserInactivity = 0 and Force = false, Seconds is ignored and VDR will
|
||||||
|
///< stay interactive forever.
|
||||||
|
void SetUserInactive(void) { SetUserInactiveTimeout(0, true); }
|
||||||
|
///< Set VDR manually into non-interactive mode.
|
||||||
|
bool Retry(time_t AtTime = 0) { return retry <= (AtTime ? AtTime : time(NULL)); }
|
||||||
|
///< Check whether its time to re-try the shutdown.
|
||||||
|
///< AtTime checks whether VDR will probably be inactive at that time.
|
||||||
|
time_t GetRetry(void) { return retry; }
|
||||||
|
///< Time when shutdown retry block ends.
|
||||||
|
void SetRetry(int Seconds) { retry = time(NULL) + Seconds; }
|
||||||
|
///< Set shutdown retry so that VDR will not try to automatically shut down
|
||||||
|
///< within Seconds.
|
||||||
|
bool ConfirmShutdown(bool Ask);
|
||||||
|
///< Check for background activity that blocks shutdown.
|
||||||
|
///< Returns immediately and without user interaction if Ask = false.
|
||||||
|
///< Asks for confirmation if Ask = true.
|
||||||
|
///< Returns true if ready for shutdown.
|
||||||
|
bool ConfirmRestart(bool Ask);
|
||||||
|
///< Check for background activity that blocks restart.
|
||||||
|
///< Returns immediately and without user interaction if Ask = false.
|
||||||
|
///< Asks for confirmation if Ask = true.
|
||||||
|
///< Returns true if ready for restart.
|
||||||
|
bool DoShutdown(bool Force);
|
||||||
|
///< Call the shutdown script with data of the next pending timer.
|
||||||
|
///< Fails if Force = false and a timer is running or within MinEventTimeout.
|
||||||
|
///< Always calls shutdown on Force = true.
|
||||||
|
///< Returns true on success.
|
||||||
|
};
|
||||||
|
|
||||||
|
extern cShutdownHandler ShutdownHandler;
|
||||||
|
|
||||||
|
#endif
|
27
thread.c
27
thread.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: thread.c 1.59 2007/01/07 14:44:22 kls Exp $
|
* $Id: thread.c 1.60 2007/02/24 16:13:33 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -200,7 +200,6 @@ void cMutex::Unlock(void)
|
|||||||
// --- cThread ---------------------------------------------------------------
|
// --- cThread ---------------------------------------------------------------
|
||||||
|
|
||||||
tThreadId cThread::mainThreadId = 0;
|
tThreadId cThread::mainThreadId = 0;
|
||||||
bool cThread::emergencyExitRequested = false;
|
|
||||||
|
|
||||||
cThread::cThread(const char *Description)
|
cThread::cThread(const char *Description)
|
||||||
{
|
{
|
||||||
@ -320,14 +319,6 @@ void cThread::Cancel(int WaitSeconds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cThread::EmergencyExit(bool Request)
|
|
||||||
{
|
|
||||||
if (!Request)
|
|
||||||
return emergencyExitRequested;
|
|
||||||
esyslog("initiating emergency exit");
|
|
||||||
return emergencyExitRequested = true; // yes, it's an assignment, not a comparison!
|
|
||||||
}
|
|
||||||
|
|
||||||
tThreadId cThread::ThreadId(void)
|
tThreadId cThread::ThreadId(void)
|
||||||
{
|
{
|
||||||
return syscall(__NR_gettid);
|
return syscall(__NR_gettid);
|
||||||
@ -505,7 +496,7 @@ int cPipe::Close(void)
|
|||||||
|
|
||||||
// --- SystemExec ------------------------------------------------------------
|
// --- SystemExec ------------------------------------------------------------
|
||||||
|
|
||||||
int SystemExec(const char *Command)
|
int SystemExec(const char *Command, bool Detached)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
@ -515,14 +506,24 @@ int SystemExec(const char *Command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pid > 0) { // parent process
|
if (pid > 0) { // parent process
|
||||||
int status;
|
int status = 0;
|
||||||
if (waitpid(pid, &status, 0) < 0) {
|
if (!Detached && waitpid(pid, &status, 0) < 0) {
|
||||||
LOG_ERROR;
|
LOG_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
else { // child process
|
else { // child process
|
||||||
|
if (Detached) {
|
||||||
|
// Start a new session
|
||||||
|
pid_t sid = setsid();
|
||||||
|
if (sid < 0)
|
||||||
|
LOG_ERROR;
|
||||||
|
// close STDIN and re-open as /dev/null
|
||||||
|
int devnull = open("/dev/null", O_RDONLY);
|
||||||
|
if (devnull < 0 || dup2(devnull, 0) < 0)
|
||||||
|
LOG_ERROR;
|
||||||
|
}
|
||||||
int MaxPossibleFileDescriptors = getdtablesize();
|
int MaxPossibleFileDescriptors = getdtablesize();
|
||||||
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
||||||
close(i); //close all dup'ed filedescriptors
|
close(i); //close all dup'ed filedescriptors
|
||||||
|
8
thread.h
8
thread.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: thread.h 1.38 2007/01/07 14:44:38 kls Exp $
|
* $Id: thread.h 1.39 2007/02/24 16:13:28 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __THREAD_H
|
#ifndef __THREAD_H
|
||||||
@ -84,7 +84,6 @@ private:
|
|||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
char *description;
|
char *description;
|
||||||
static tThreadId mainThreadId;
|
static tThreadId mainThreadId;
|
||||||
static bool emergencyExitRequested;
|
|
||||||
static void *StartThread(cThread *Thread);
|
static void *StartThread(cThread *Thread);
|
||||||
protected:
|
protected:
|
||||||
void SetPriority(int Priority);
|
void SetPriority(int Priority);
|
||||||
@ -118,7 +117,6 @@ public:
|
|||||||
///< If the thread is already running, nothing happens.
|
///< If the thread is already running, nothing happens.
|
||||||
bool Active(void);
|
bool Active(void);
|
||||||
///< Checks whether the thread is still alive.
|
///< Checks whether the thread is still alive.
|
||||||
static bool EmergencyExit(bool Request = false);
|
|
||||||
static tThreadId ThreadId(void);
|
static tThreadId ThreadId(void);
|
||||||
static tThreadId IsMainThread(void) { return ThreadId() == mainThreadId; }
|
static tThreadId IsMainThread(void) { return ThreadId() == mainThreadId; }
|
||||||
static void SetMainThreadId(void);
|
static void SetMainThreadId(void);
|
||||||
@ -175,7 +173,9 @@ public:
|
|||||||
|
|
||||||
// SystemExec() implements a 'system()' call that closes all unnecessary file
|
// SystemExec() implements a 'system()' call that closes all unnecessary file
|
||||||
// descriptors in the child process.
|
// descriptors in the child process.
|
||||||
|
// With Detached=true, calls command in background and in a separate session,
|
||||||
|
// with stdin connected to /dev/null.
|
||||||
|
|
||||||
int SystemExec(const char *Command);
|
int SystemExec(const char *Command, bool Detached = false);
|
||||||
|
|
||||||
#endif //__THREAD_H
|
#endif //__THREAD_H
|
||||||
|
10
vdr.1
10
vdr.1
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" vdr distribution.
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: vdr.1 1.28 2007/01/07 14:03:56 kls Exp $
|
.\" $Id: vdr.1 1.29 2007/02/24 17:40:20 kls Exp $
|
||||||
.\"
|
.\"
|
||||||
.TH vdr 1 "07 Jan 2007" "1.4.5" "Video Disk Recorder"
|
.TH vdr 1 "07 Jan 2007" "1.4.5" "Video Disk Recorder"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -153,6 +153,14 @@ Print version information and exit.
|
|||||||
.BI \-w\ sec ,\ \-\-watchdog= sec
|
.BI \-w\ sec ,\ \-\-watchdog= sec
|
||||||
Activate the watchdog timer with a timeout of \fIsec\fR seconds.
|
Activate the watchdog timer with a timeout of \fIsec\fR seconds.
|
||||||
A value of \fB0\fR (default) disables the watchdog.
|
A value of \fB0\fR (default) disables the watchdog.
|
||||||
|
.SH SIGNALS
|
||||||
|
.TP
|
||||||
|
.B SIGINT, SIGTERM
|
||||||
|
Program exits with status 0.
|
||||||
|
.TP
|
||||||
|
.B SIGHUP
|
||||||
|
Program exits with status 1. This can be used to force a reload, for example
|
||||||
|
if an update has been installed.
|
||||||
.SH EXIT STATUS
|
.SH EXIT STATUS
|
||||||
.TP
|
.TP
|
||||||
.B 0
|
.B 0
|
||||||
|
201
vdr.c
201
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/vdr
|
* The project's page is at http://www.cadsoft.de/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 1.283 2007/01/07 14:46:14 kls Exp $
|
* $Id: vdr.c 1.284 2007/02/25 10:56:29 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -54,6 +54,7 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "rcu.h"
|
#include "rcu.h"
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
|
#include "shutdown.h"
|
||||||
#include "skinclassic.h"
|
#include "skinclassic.h"
|
||||||
#include "skinsttng.h"
|
#include "skinsttng.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
@ -66,20 +67,23 @@
|
|||||||
#define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
|
#define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
|
||||||
#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
|
#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
|
||||||
#define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
|
#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 SHUTDOWNCANCELROMPT 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 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 CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
|
||||||
#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
|
#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 MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
|
||||||
#define SHUTDOWNRETRY 300 // seconds before trying again to shut down
|
|
||||||
#define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
|
#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 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 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 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
|
#define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
|
||||||
|
|
||||||
#define EXIT(v) { ExitCode = (v); goto Exit; }
|
#define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
|
||||||
|
|
||||||
static int Interrupted = 0;
|
static int LastSignal = 0;
|
||||||
|
|
||||||
static bool SetUser(const char *UserName)
|
static bool SetUser(const char *UserName)
|
||||||
{
|
{
|
||||||
@ -138,9 +142,17 @@ static bool SetKeepCaps(bool On)
|
|||||||
|
|
||||||
static void SignalHandler(int signum)
|
static void SignalHandler(int signum)
|
||||||
{
|
{
|
||||||
if (signum != SIGPIPE) {
|
isyslog("caught signal %d", signum);
|
||||||
Interrupted = signum;
|
switch (signum) {
|
||||||
|
case SIGPIPE:
|
||||||
|
break;
|
||||||
|
case SIGHUP:
|
||||||
|
LastSignal = signum;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LastSignal = signum;
|
||||||
Interface->Interrupt();
|
Interface->Interrupt();
|
||||||
|
ShutdownHandler.Exit(0);
|
||||||
}
|
}
|
||||||
signal(signum, SignalHandler);
|
signal(signum, SignalHandler);
|
||||||
}
|
}
|
||||||
@ -184,7 +196,6 @@ int main(int argc, char *argv[])
|
|||||||
bool MuteAudio = false;
|
bool MuteAudio = false;
|
||||||
int WatchdogTimeout = DEFAULTWATCHDOG;
|
int WatchdogTimeout = DEFAULTWATCHDOG;
|
||||||
const char *Terminal = NULL;
|
const char *Terminal = NULL;
|
||||||
const char *Shutdown = NULL;
|
|
||||||
|
|
||||||
bool UseKbd = true;
|
bool UseKbd = true;
|
||||||
const char *LircDevice = NULL;
|
const char *LircDevice = NULL;
|
||||||
@ -205,7 +216,6 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
cPluginManager PluginManager(DEFAULTPLUGINDIR);
|
cPluginManager PluginManager(DEFAULTPLUGINDIR);
|
||||||
int ExitCode = 0;
|
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{ "audio", required_argument, NULL, 'a' },
|
{ "audio", required_argument, NULL, 'a' },
|
||||||
@ -313,7 +323,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'r': cRecordingUserCommand::SetCommand(optarg);
|
case 'r': cRecordingUserCommand::SetCommand(optarg);
|
||||||
break;
|
break;
|
||||||
case 's': Shutdown = optarg;
|
case 's': ShutdownHandler.SetShutdownCommand(optarg);
|
||||||
break;
|
break;
|
||||||
case 't': Terminal = optarg;
|
case 't': Terminal = optarg;
|
||||||
if (access(Terminal, R_OK | W_OK) < 0) {
|
if (access(Terminal, R_OK | W_OK) < 0) {
|
||||||
@ -498,10 +508,7 @@ int main(int argc, char *argv[])
|
|||||||
int PreviousChannel[2] = { 1, 1 };
|
int PreviousChannel[2] = { 1, 1 };
|
||||||
int PreviousChannelIndex = 0;
|
int PreviousChannelIndex = 0;
|
||||||
time_t LastChannelChanged = time(NULL);
|
time_t LastChannelChanged = time(NULL);
|
||||||
time_t LastActivity = 0;
|
|
||||||
int MaxLatencyTime = 0;
|
int MaxLatencyTime = 0;
|
||||||
bool ForceShutdown = false;
|
|
||||||
bool UserShutdown = false;
|
|
||||||
bool InhibitEpgScan = false;
|
bool InhibitEpgScan = false;
|
||||||
bool IsInfoMenu = false;
|
bool IsInfoMenu = false;
|
||||||
cSkin *CurrentSkin = NULL;
|
cSkin *CurrentSkin = NULL;
|
||||||
@ -596,6 +603,10 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for timers in automatic start time window:
|
||||||
|
|
||||||
|
ShutdownHandler.CheckManualStart(MANUALSTART);
|
||||||
|
|
||||||
// User interface:
|
// User interface:
|
||||||
|
|
||||||
Interface = new cInterface(SVDRPport);
|
Interface = new cInterface(SVDRPport);
|
||||||
@ -668,12 +679,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
#define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
|
#define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
|
||||||
|
|
||||||
while (!Interrupted) {
|
while (!ShutdownHandler.DoExit()) {
|
||||||
// Handle emergency exits:
|
|
||||||
if (cThread::EmergencyExit()) {
|
|
||||||
esyslog("emergency exit requested - shutting down");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef DEBUGRINGBUFFERS
|
#ifdef DEBUGRINGBUFFERS
|
||||||
cRingBufferLinear::PrintDebugRBL();
|
cRingBufferLinear::PrintDebugRBL();
|
||||||
#endif
|
#endif
|
||||||
@ -856,9 +862,13 @@ int main(int argc, char *argv[])
|
|||||||
// User Input:
|
// User Input:
|
||||||
cOsdObject *Interact = Menu ? Menu : cControl::Control();
|
cOsdObject *Interact = Menu ? Menu : cControl::Control();
|
||||||
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
|
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
|
||||||
if (NORMALKEY(key) != kNone) {
|
if (ISREALKEY(key)) {
|
||||||
EITScanner.Activity();
|
EITScanner.Activity();
|
||||||
LastActivity = time(NULL);
|
// Cancel shutdown countdown:
|
||||||
|
if (ShutdownHandler.countdown)
|
||||||
|
ShutdownHandler.countdown.Cancel();
|
||||||
|
// Set user active for MinUserInactivity time in the future:
|
||||||
|
ShutdownHandler.SetUserInactiveTimeout();
|
||||||
}
|
}
|
||||||
// Keys that must work independent of any interactive mode:
|
// Keys that must work independent of any interactive mode:
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@ -996,37 +1006,32 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Power off:
|
// Power off:
|
||||||
case kPower: {
|
case kPower:
|
||||||
isyslog("Power button pressed");
|
isyslog("Power button pressed");
|
||||||
DELETE_MENU;
|
DELETE_MENU;
|
||||||
if (!Shutdown) {
|
// Check for activity, request power button again if active:
|
||||||
Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
|
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();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LastActivity = 1; // not 0, see below!
|
// No activity or power button pressed twice - ask for confirmation:
|
||||||
UserShutdown = true;
|
if (!ShutdownHandler.ConfirmShutdown(true)) {
|
||||||
if (cRecordControls::Active()) {
|
// Non-confirmed background activity - set VDR to be non-interactive and power down later:
|
||||||
if (!Interface->Confirm(tr("Recording - shut down anyway?")))
|
ShutdownHandler.SetUserInactive();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cPluginManager::Active(tr("shut down anyway?")))
|
// Ask the final question:
|
||||||
|
if (!Interface->Confirm(tr("Press any key to cancel shutdown"), SHUTDOWNCANCELROMPT, true))
|
||||||
|
// If final question was canceled, continue to be active:
|
||||||
break;
|
break;
|
||||||
if (!cRecordControls::Active()) {
|
// Ok, now call the shutdown script:
|
||||||
cTimer *timer = Timers.GetNextActiveTimer();
|
ShutdownHandler.DoShutdown(true);
|
||||||
time_t Next = timer ? timer->StartTime() : 0;
|
// Set VDR to be non-interactive and power down again later:
|
||||||
time_t Delta = timer ? Next - time(NULL) : 0;
|
ShutdownHandler.SetUserInactive();
|
||||||
if (Next && Delta <= Setup.MinEventTimeout * 60) {
|
// Do not attempt to automatically shut down for a while:
|
||||||
char *buf;
|
ShutdownHandler.SetRetry(SHUTDOWNRETRY);
|
||||||
asprintf(&buf, tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
|
|
||||||
bool confirm = Interface->Confirm(buf);
|
|
||||||
free(buf);
|
|
||||||
if (!confirm)
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
ForceShutdown = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
Interact = Menu ? Menu : cControl::Control(); // might have been closed in the mean time
|
Interact = Menu ? Menu : cControl::Control(); // might have been closed in the mean time
|
||||||
@ -1041,7 +1046,7 @@ int main(int argc, char *argv[])
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (time(NULL) - LastActivity > MENUTIMEOUT)
|
else if (time(NULL) - cRemote::LastActivity() > MENUTIMEOUT)
|
||||||
state = osEnd;
|
state = osEnd;
|
||||||
}
|
}
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -1143,77 +1148,55 @@ int main(int argc, char *argv[])
|
|||||||
Skins.Message(mtInfo, tr("Editing process finished"));
|
Skins.Message(mtInfo, tr("Editing process finished"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Interact && ((!cRecordControls::Active() && !cCutter::Active() && (!Interface->HasSVDRPConnection() || UserShutdown)) || ForceShutdown)) {
|
|
||||||
time_t Now = time(NULL);
|
// SIGHUP shall cause a restart:
|
||||||
if (Now - LastActivity > ACTIVITYTIMEOUT) {
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Interact && !cRecordControls::Active() && !cCutter::Active() && !Interface->HasSVDRPConnection() && cRemote::LastActivity() > ACTIVITYTIMEOUT) {
|
||||||
|
// Handle housekeeping tasks
|
||||||
|
|
||||||
// Shutdown:
|
// Shutdown:
|
||||||
if (Shutdown && (Setup.MinUserInactivity || LastActivity == 1) && Now - LastActivity > Setup.MinUserInactivity * 60) {
|
// Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
|
||||||
cTimer *timer = Timers.GetNextActiveTimer();
|
time_t Soon = time(NULL) + SHUTDOWNWAIT;
|
||||||
time_t Next = timer ? timer->StartTime() : 0;
|
if (ShutdownHandler.IsUserInactive(Soon) && ShutdownHandler.Retry(Soon) && !ShutdownHandler.countdown) {
|
||||||
time_t Delta = timer ? Next - Now : 0;
|
if (ShutdownHandler.ConfirmShutdown(false))
|
||||||
if (!LastActivity) {
|
// Time to shut down - start final countdown:
|
||||||
if (!timer || Delta > MANUALSTART) {
|
ShutdownHandler.countdown.Start(tr("VDR will shut down in %s minutes"), SHUTDOWNWAIT); // the placeholder is really %s!
|
||||||
// Apparently the user started VDR manually
|
// Dont try to shut down again for a while:
|
||||||
dsyslog("assuming manual start of VDR");
|
ShutdownHandler.SetRetry(SHUTDOWNRETRY);
|
||||||
LastActivity = Now;
|
|
||||||
continue; // don't run into the actual shutdown procedure below
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LastActivity = 1;
|
|
||||||
}
|
|
||||||
if (timer && Delta < Setup.MinEventTimeout * 60 && ForceShutdown) {
|
|
||||||
Delta = Setup.MinEventTimeout * 60;
|
|
||||||
Next = Now + Delta;
|
|
||||||
timer = NULL;
|
|
||||||
dsyslog("reboot at %s", *TimeToString(Next));
|
|
||||||
}
|
|
||||||
if (!ForceShutdown && cPluginManager::Active()) {
|
|
||||||
LastActivity = Now - Setup.MinUserInactivity * 60 + SHUTDOWNRETRY; // try again later
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
|
|
||||||
ForceShutdown = false;
|
|
||||||
if (timer)
|
|
||||||
dsyslog("next timer event at %s", *TimeToString(Next));
|
|
||||||
if (WatchdogTimeout > 0)
|
|
||||||
signal(SIGALRM, SIG_IGN);
|
|
||||||
if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
|
|
||||||
cControl::Shutdown();
|
|
||||||
int Channel = timer ? timer->Channel()->Number() : 0;
|
|
||||||
const char *File = timer ? timer->File() : "";
|
|
||||||
if (timer)
|
|
||||||
Delta = Next - time(NULL); // compensates for Confirm() timeout
|
|
||||||
char *cmd;
|
|
||||||
asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, *strescape(File, "\"$"), UserShutdown);
|
|
||||||
isyslog("executing '%s'", cmd);
|
|
||||||
SystemExec(cmd);
|
|
||||||
free(cmd);
|
|
||||||
LastActivity = time(NULL) - Setup.MinUserInactivity * 60 + SHUTDOWNRETRY; // try again later
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LastActivity = Now;
|
|
||||||
if (WatchdogTimeout > 0) {
|
|
||||||
alarm(WatchdogTimeout);
|
|
||||||
if (signal(SIGALRM, Watchdog) == SIG_IGN)
|
|
||||||
signal(SIGALRM, SIG_IGN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UserShutdown = false;
|
|
||||||
continue; // skip the rest of the housekeeping for now
|
|
||||||
}
|
}
|
||||||
|
// 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:
|
// Disk housekeeping:
|
||||||
RemoveDeletedRecordings();
|
RemoveDeletedRecordings();
|
||||||
cSchedules::Cleanup();
|
cSchedules::Cleanup();
|
||||||
// Plugins housekeeping:
|
// Plugins housekeeping:
|
||||||
PluginManager.Housekeeping();
|
PluginManager.Housekeeping();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Main thread hooks of plugins:
|
// Main thread hooks of plugins:
|
||||||
PluginManager.MainThreadHook();
|
PluginManager.MainThreadHook();
|
||||||
}
|
}
|
||||||
if (Interrupted)
|
|
||||||
isyslog("caught signal %d", Interrupted);
|
if (ShutdownHandler.EmergencyExitRequested())
|
||||||
|
esyslog("emergency exit requested - shutting down");
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
|
|
||||||
@ -1227,7 +1210,7 @@ Exit:
|
|||||||
Remotes.Clear();
|
Remotes.Clear();
|
||||||
Audios.Clear();
|
Audios.Clear();
|
||||||
Skins.Clear();
|
Skins.Clear();
|
||||||
if (ExitCode != 2) {
|
if (ShutdownHandler.GetExitCode() != 2) {
|
||||||
Setup.CurrentChannel = cDevice::CurrentChannel();
|
Setup.CurrentChannel = cDevice::CurrentChannel();
|
||||||
Setup.CurrentVolume = cDevice::CurrentVolume();
|
Setup.CurrentVolume = cDevice::CurrentVolume();
|
||||||
Setup.Save();
|
Setup.Save();
|
||||||
@ -1238,14 +1221,12 @@ Exit:
|
|||||||
ReportEpgBugFixStats();
|
ReportEpgBugFixStats();
|
||||||
if (WatchdogTimeout > 0)
|
if (WatchdogTimeout > 0)
|
||||||
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
||||||
isyslog("exiting");
|
isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
|
||||||
|
if (ShutdownHandler.EmergencyExitRequested())
|
||||||
|
esyslog("emergency exit!");
|
||||||
if (SysLogLevel > 0)
|
if (SysLogLevel > 0)
|
||||||
closelog();
|
closelog();
|
||||||
if (HasStdin)
|
if (HasStdin)
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
|
tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
|
||||||
if (cThread::EmergencyExit()) {
|
return ShutdownHandler.GetExitCode();
|
||||||
esyslog("emergency exit!");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return ExitCode;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user