diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2007-02-25 10:56:29 +0100 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2007-02-25 10:56:29 +0100 |
commit | ddb7f335674d668af3dd06bd61a0853b3af60df0 (patch) | |
tree | 5d52ba7939f6aa0b18cc01f546ce5c82ae8d3b80 /shutdown.c | |
parent | 50b14be807e1d3002246f359de83a8a18a0e6008 (diff) | |
download | vdr-ddb7f335674d668af3dd06bd61a0853b3af60df0.tar.gz vdr-ddb7f335674d668af3dd06bd61a0853b3af60df0.tar.bz2 |
Rewrite of shutdown handling; implemented cPlugin::WakeupTime(); SIGHUP forces reload; cThread::EmergencyExit() replaced by ShutdownHandler.RequestEmergencyExit()
Diffstat (limited to 'shutdown.c')
-rw-r--r-- | shutdown.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/shutdown.c b/shutdown.c new file mode 100644 index 00000000..4029a78c --- /dev/null +++ b/shutdown.c @@ -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; +} |