vdr
1.7.27
|
00001 /* 00002 * shutdown.c: Handling of shutdown and inactivity 00003 * 00004 * See the main source file 'vdr.c' for copyright information and 00005 * how to reach the author. 00006 * 00007 * Original version written by Udo Richter <udo_richter@gmx.de>. 00008 * 00009 * $Id: shutdown.c 2.0 2008/02/24 10:29:00 kls Exp $ 00010 */ 00011 00012 #include "shutdown.h" 00013 #include <stdio.h> 00014 #include <stdlib.h> 00015 #include <sys/types.h> 00016 #include <sys/wait.h> 00017 #include "channels.h" 00018 #include "config.h" 00019 #include "cutter.h" 00020 #include "filetransfer.h" 00021 #include "i18n.h" 00022 #include "interface.h" 00023 #include "menu.h" 00024 #include "plugin.h" 00025 #include "timers.h" 00026 #include "tools.h" 00027 00028 cShutdownHandler ShutdownHandler; 00029 00030 cCountdown::cCountdown(void) 00031 { 00032 timeout = 0; 00033 counter = 0; 00034 timedOut = false; 00035 message = NULL; 00036 } 00037 00038 void cCountdown::Start(const char *Message, int Seconds) 00039 { 00040 timeout = time(NULL) + Seconds; 00041 counter = -1; 00042 timedOut = false; 00043 message = Message; 00044 Update(); 00045 } 00046 00047 void cCountdown::Cancel(void) 00048 { 00049 if (timeout) { 00050 timeout = 0; 00051 timedOut = false; 00052 Skins.Message(mtStatus, NULL); 00053 } 00054 } 00055 00056 bool cCountdown::Done(void) 00057 { 00058 if (timedOut) { 00059 Cancel(); 00060 return true; 00061 } 00062 return false; 00063 } 00064 00065 bool cCountdown::Update(void) 00066 { 00067 if (timeout) { 00068 int NewCounter = (timeout - time(NULL) + 9) / 10; 00069 if (NewCounter <= 0) 00070 timedOut = true; 00071 if (counter != NewCounter) { 00072 counter = NewCounter; 00073 char time[10]; 00074 snprintf(time, sizeof(time), "%d:%d0", counter > 0 ? counter / 6 : 0, counter > 0 ? counter % 6 : 0); 00075 cString Message = cString::sprintf(message, time); 00076 Skins.Message(mtStatus, Message); 00077 return true; 00078 } 00079 } 00080 return false; 00081 } 00082 00083 cShutdownHandler::cShutdownHandler(void) 00084 { 00085 activeTimeout = 0; 00086 retry = 0; 00087 shutdownCommand = NULL; 00088 exitCode = -1; 00089 emergencyExitRequested = false; 00090 } 00091 00092 cShutdownHandler::~cShutdownHandler() 00093 { 00094 free(shutdownCommand); 00095 } 00096 00097 void cShutdownHandler::RequestEmergencyExit(void) 00098 { 00099 if (Setup.EmergencyExit) { 00100 esyslog("initiating emergency exit"); 00101 emergencyExitRequested = true; 00102 Exit(1); 00103 } 00104 else 00105 dsyslog("emergency exit request ignored according to setup"); 00106 } 00107 00108 void cShutdownHandler::CheckManualStart(int ManualStart) 00109 { 00110 time_t Delta = Setup.NextWakeupTime ? Setup.NextWakeupTime - time(NULL) : 0; 00111 00112 if (!Setup.NextWakeupTime || abs(Delta) > ManualStart) { 00113 // Apparently the user started VDR manually 00114 dsyslog("assuming manual start of VDR"); 00115 // Set inactive after MinUserInactivity 00116 SetUserInactiveTimeout(); 00117 } 00118 else { 00119 // Set inactive from now on 00120 dsyslog("scheduled wakeup time in %ld minutes, assuming automatic start of VDR", Delta / 60); 00121 SetUserInactive(); 00122 } 00123 } 00124 00125 void cShutdownHandler::SetShutdownCommand(const char *ShutdownCommand) 00126 { 00127 free(shutdownCommand); 00128 shutdownCommand = ShutdownCommand ? strdup(ShutdownCommand) : NULL; 00129 } 00130 00131 void cShutdownHandler::CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown) 00132 { 00133 time_t Delta = WakeupTime ? WakeupTime - time(NULL) : 0; 00134 cString cmd = cString::sprintf("%s %ld %ld %d \"%s\" %d", shutdownCommand, WakeupTime, Delta, Channel, *strescape(File, "\\\"$"), UserShutdown); 00135 isyslog("executing '%s'", *cmd); 00136 int Status = SystemExec(cmd, true); 00137 if (!WIFEXITED(Status) || WEXITSTATUS(Status)) 00138 esyslog("SystemExec() failed with status %d", Status); 00139 else { 00140 Setup.NextWakeupTime = WakeupTime; // Remember this wakeup time for comparison on reboot 00141 Setup.Save(); 00142 } 00143 } 00144 00145 void cShutdownHandler::SetUserInactiveTimeout(int Seconds, bool Force) 00146 { 00147 if (!Setup.MinUserInactivity && !Force) { 00148 activeTimeout = 0; 00149 return; 00150 } 00151 if (Seconds < 0) 00152 Seconds = Setup.MinUserInactivity * 60; 00153 activeTimeout = time(NULL) + Seconds; 00154 } 00155 00156 bool cShutdownHandler::ConfirmShutdown(bool Interactive) 00157 { 00158 if (!Interactive && !cRemote::Enabled()) 00159 return false; 00160 00161 if (!shutdownCommand) { 00162 if (Interactive) 00163 Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!")); 00164 return false; 00165 } 00166 if (cCutter::Active()) { 00167 if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?"))) 00168 return false; 00169 } 00170 if (cFileTransfer::Active()) { 00171 if (!Interactive || !Interface->Confirm(tr("Transfering file - shut down anyway?"))) 00172 return false; 00173 } 00174 00175 cTimer *timer = Timers.GetNextActiveTimer(); 00176 time_t Next = timer ? timer->StartTime() : 0; 00177 time_t Delta = timer ? Next - time(NULL) : 0; 00178 00179 if (cRecordControls::Active() || (Next && Delta <= 0)) { 00180 // VPS recordings in timer end margin may cause Delta <= 0 00181 if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?"))) 00182 return false; 00183 } 00184 else if (Next && Delta <= Setup.MinEventTimeout * 60) { 00185 // Timer within Min Event Timeout 00186 if (!Interactive) 00187 return false; 00188 cString buf = cString::sprintf(tr("Recording in %ld minutes, shut down anyway?"), Delta / 60); 00189 if (!Interface->Confirm(buf)) 00190 return false; 00191 } 00192 00193 if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL)) 00194 return false; 00195 00196 cPlugin *Plugin = cPluginManager::GetNextWakeupPlugin(); 00197 Next = Plugin ? Plugin->WakeupTime() : 0; 00198 Delta = Next ? Next - time(NULL) : 0; 00199 if (Next && Delta <= Setup.MinEventTimeout * 60) { 00200 // Plugin wakeup within Min Event Timeout 00201 if (!Interactive) 00202 return false; 00203 cString buf = cString::sprintf(tr("Plugin %s wakes up in %ld min, continue?"), Plugin->Name(), Delta / 60); 00204 if (!Interface->Confirm(buf)) 00205 return false; 00206 } 00207 00208 return true; 00209 } 00210 00211 bool cShutdownHandler::ConfirmRestart(bool Interactive) 00212 { 00213 if (cCutter::Active()) { 00214 if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?"))) 00215 return false; 00216 } 00217 if (cFileTransfer::Active()) { 00218 if (!Interactive || !Interface->Confirm(tr("Transfering file - restart anyway?"))) 00219 return false; 00220 } 00221 00222 cTimer *timer = Timers.GetNextActiveTimer(); 00223 time_t Next = timer ? timer->StartTime() : 0; 00224 time_t Delta = timer ? Next - time(NULL) : 0; 00225 00226 if (cRecordControls::Active() || (Next && Delta <= 0)) { 00227 // VPS recordings in timer end margin may cause Delta <= 0 00228 if (!Interactive || !Interface->Confirm(tr("Recording - restart anyway?"))) 00229 return false; 00230 } 00231 00232 if (cPluginManager::Active(Interactive ? tr("restart anyway?") : NULL)) 00233 return false; 00234 00235 return true; 00236 } 00237 00238 bool cShutdownHandler::DoShutdown(bool Force) 00239 { 00240 time_t Now = time(NULL); 00241 cTimer *timer = Timers.GetNextActiveTimer(); 00242 cPlugin *Plugin = cPluginManager::GetNextWakeupPlugin(); 00243 00244 time_t Next = timer ? timer->StartTime() : 0; 00245 time_t NextPlugin = Plugin ? Plugin->WakeupTime() : 0; 00246 if (NextPlugin && (!Next || Next > NextPlugin)) { 00247 Next = NextPlugin; 00248 timer = NULL; 00249 } 00250 time_t Delta = Next ? Next - Now : 0; 00251 00252 if (Next && Delta < Setup.MinEventTimeout * 60) { 00253 if (!Force) 00254 return false; 00255 Delta = Setup.MinEventTimeout * 60; 00256 Next = Now + Delta; 00257 timer = NULL; 00258 dsyslog("reboot at %s", *TimeToString(Next)); 00259 } 00260 00261 if (Next && timer) { 00262 dsyslog("next timer event at %s", *TimeToString(Next)); 00263 CallShutdownCommand(Next, timer->Channel()->Number(), timer->File(), Force); 00264 } 00265 else if (Next && Plugin) { 00266 CallShutdownCommand(Next, 0, Plugin->Name(), Force); 00267 dsyslog("next plugin wakeup at %s", *TimeToString(Next)); 00268 } 00269 else 00270 CallShutdownCommand(Next, 0, "", Force); // Next should always be 0 here. Just for safety, pass it. 00271 00272 return true; 00273 }