vdr  2.0.4
shutdown.c
Go to the documentation of this file.
1 /*
2  * shutdown.c: Handling of shutdown and inactivity
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * Original version written by Udo Richter <udo_richter@gmx.de>.
8  *
9  * $Id: shutdown.c 2.1 2013/02/18 10:33:26 kls Exp $
10  */
11 
12 #include "shutdown.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include "channels.h"
18 #include "config.h"
19 #include "cutter.h"
20 #include "filetransfer.h"
21 #include "i18n.h"
22 #include "interface.h"
23 #include "menu.h"
24 #include "plugin.h"
25 #include "timers.h"
26 #include "tools.h"
27 
29 
31 {
32  timeout = 0;
33  counter = 0;
34  timedOut = false;
35  message = NULL;
36 }
37 
38 void cCountdown::Start(const char *Message, int Seconds)
39 {
40  timeout = time(NULL) + Seconds;
41  counter = -1;
42  timedOut = false;
43  message = Message;
44  Update();
45 }
46 
48 {
49  if (timeout) {
50  timeout = 0;
51  timedOut = false;
52  Skins.Message(mtStatus, NULL);
53  }
54 }
55 
56 bool cCountdown::Done(void)
57 {
58  if (timedOut) {
59  Cancel();
60  return true;
61  }
62  return false;
63 }
64 
66 {
67  if (timeout) {
68  int NewCounter = (timeout - time(NULL) + 9) / 10;
69  if (NewCounter <= 0)
70  timedOut = true;
71  if (counter != NewCounter) {
72  counter = NewCounter;
73  char time[10];
74  snprintf(time, sizeof(time), "%d:%d0", counter > 0 ? counter / 6 : 0, counter > 0 ? counter % 6 : 0);
75  cString Message = cString::sprintf(message, time);
76  Skins.Message(mtStatus, Message);
77  return true;
78  }
79  }
80  return false;
81 }
82 
84 {
85  activeTimeout = 0;
86  retry = 0;
87  shutdownCommand = NULL;
88  exitCode = -1;
89  emergencyExitRequested = false;
90 }
91 
93 {
94  free(shutdownCommand);
95 }
96 
98 {
99  if (Setup.EmergencyExit) {
100  esyslog("initiating emergency exit");
101  emergencyExitRequested = true;
102  Exit(1);
103  }
104  else
105  dsyslog("emergency exit request ignored according to setup");
106 }
107 
109 {
110  time_t Delta = Setup.NextWakeupTime ? Setup.NextWakeupTime - time(NULL) : 0;
111 
112  if (!Setup.NextWakeupTime || abs(Delta) > ManualStart) {
113  // Apparently the user started VDR manually
114  dsyslog("assuming manual start of VDR");
115  // Set inactive after MinUserInactivity
117  }
118  else {
119  // Set inactive from now on
120  dsyslog("scheduled wakeup time in %ld minutes, assuming automatic start of VDR", Delta / 60);
121  SetUserInactiveTimeout(-3, true);
122  }
123 }
124 
125 void cShutdownHandler::SetShutdownCommand(const char *ShutdownCommand)
126 {
127  free(shutdownCommand);
128  shutdownCommand = ShutdownCommand ? strdup(ShutdownCommand) : NULL;
129 }
130 
131 void cShutdownHandler::CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
132 {
133  time_t Delta = WakeupTime ? WakeupTime - time(NULL) : 0;
134  cString cmd = cString::sprintf("%s %ld %ld %d \"%s\" %d", shutdownCommand, WakeupTime, Delta, Channel, *strescape(File, "\\\"$"), UserShutdown);
135  isyslog("executing '%s'", *cmd);
136  int Status = SystemExec(cmd, true);
137  if (!WIFEXITED(Status) || WEXITSTATUS(Status))
138  esyslog("SystemExec() failed with status %d", Status);
139  else {
140  Setup.NextWakeupTime = WakeupTime; // Remember this wakeup time for comparison on reboot
141  Setup.Save();
142  }
143 }
144 
145 void cShutdownHandler::SetUserInactiveTimeout(int Seconds, bool Force)
146 {
147  if (!Setup.MinUserInactivity && !Force) {
148  activeTimeout = 0;
149  return;
150  }
151  if (Seconds >= 0)
152  activeTimeout = time(NULL) + Seconds;
153  else if (Seconds == -1)
154  activeTimeout = time(NULL) + Setup.MinUserInactivity * 60;
155  else if (Seconds == -2)
156  activeTimeout = 0;
157  else if (Seconds == -3)
158  activeTimeout = 1;
159 }
160 
161 bool cShutdownHandler::ConfirmShutdown(bool Interactive)
162 {
163  if (!Interactive && !cRemote::Enabled())
164  return false;
165 
166  if (!shutdownCommand) {
167  if (Interactive)
168  Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
169  return false;
170  }
171  if (cCutter::Active()) {
172  if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?")))
173  return false;
174  }
175  if (cFileTransfer::Active()) {
176  if (!Interactive || !Interface->Confirm(tr("Transfering file - shut down anyway?")))
177  return false;
178  }
179 
180  cTimer *timer = Timers.GetNextActiveTimer();
181  time_t Next = timer ? timer->StartTime() : 0;
182  time_t Delta = timer ? Next - time(NULL) : 0;
183 
184  if (cRecordControls::Active() || (Next && Delta <= 0)) {
185  // VPS recordings in timer end margin may cause Delta <= 0
186  if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?")))
187  return false;
188  }
189  else if (Next && Delta <= Setup.MinEventTimeout * 60) {
190  // Timer within Min Event Timeout
191  if (!Interactive)
192  return false;
193  cString buf = cString::sprintf(tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
194  if (!Interface->Confirm(buf))
195  return false;
196  }
197 
198  if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL))
199  return false;
200 
202  Next = Plugin ? Plugin->WakeupTime() : 0;
203  Delta = Next ? Next - time(NULL) : 0;
204  if (Next && Delta <= Setup.MinEventTimeout * 60) {
205  // Plugin wakeup within Min Event Timeout
206  if (!Interactive)
207  return false;
208  cString buf = cString::sprintf(tr("Plugin %s wakes up in %ld min, continue?"), Plugin->Name(), Delta / 60);
209  if (!Interface->Confirm(buf))
210  return false;
211  }
212 
213  return true;
214 }
215 
216 bool cShutdownHandler::ConfirmRestart(bool Interactive)
217 {
218  if (cCutter::Active()) {
219  if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?")))
220  return false;
221  }
222  if (cFileTransfer::Active()) {
223  if (!Interactive || !Interface->Confirm(tr("Transfering file - restart anyway?")))
224  return false;
225  }
226 
227  cTimer *timer = Timers.GetNextActiveTimer();
228  time_t Next = timer ? timer->StartTime() : 0;
229  time_t Delta = timer ? Next - time(NULL) : 0;
230 
231  if (cRecordControls::Active() || (Next && Delta <= 0)) {
232  // VPS recordings in timer end margin may cause Delta <= 0
233  if (!Interactive || !Interface->Confirm(tr("Recording - restart anyway?")))
234  return false;
235  }
236 
237  if (cPluginManager::Active(Interactive ? tr("restart anyway?") : NULL))
238  return false;
239 
240  return true;
241 }
242 
244 {
245  time_t Now = time(NULL);
246  cTimer *timer = Timers.GetNextActiveTimer();
248 
249  time_t Next = timer ? timer->StartTime() : 0;
250  time_t NextPlugin = Plugin ? Plugin->WakeupTime() : 0;
251  if (NextPlugin && (!Next || Next > NextPlugin)) {
252  Next = NextPlugin;
253  timer = NULL;
254  }
255  time_t Delta = Next ? Next - Now : 0;
256 
257  if (Next && Delta < Setup.MinEventTimeout * 60) {
258  if (!Force)
259  return false;
260  Delta = Setup.MinEventTimeout * 60;
261  Next = Now + Delta;
262  timer = NULL;
263  dsyslog("reboot at %s", *TimeToString(Next));
264  }
265 
266  if (Next && timer) {
267  dsyslog("next timer event at %s", *TimeToString(Next));
268  CallShutdownCommand(Next, timer->Channel()->Number(), timer->File(), Force);
269  }
270  else if (Next && Plugin) {
271  CallShutdownCommand(Next, 0, Plugin->Name(), Force);
272  dsyslog("next plugin wakeup at %s", *TimeToString(Next));
273  }
274  else
275  CallShutdownCommand(Next, 0, "", Force); // Next should always be 0 here. Just for safety, pass it.
276 
277  return true;
278 }
void CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
Call the shutdown command with the given parameters.
Definition: shutdown.c:131
int Number(void) const
Definition: channels.h:191
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition: shutdown.c:108
#define dsyslog(a...)
Definition: tools.h:36
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition: interface.c:64
const char * Name(void)
Definition: plugin.h:34
int counter
last shown time in 10s units
Definition: shutdown.h:20
cTimers Timers
Definition: timers.c:694
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1011
Definition: plugin.h:20
bool timedOut
countdown did run down to 0 and was not canceled
Definition: shutdown.h:21
#define esyslog(a...)
Definition: tools.h:34
time_t retry
Time for retrying the shutdown.
Definition: shutdown.h:42
int MinUserInactivity
Definition: config.h:330
bool Save(void)
Definition: config.c:693
bool Update(void)
Update status display of the countdown.
Definition: shutdown.c:65
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition: shutdown.c:243
time_t StartTime(void) const
Definition: timers.c:497
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition: shutdown.h:54
cTimer * GetNextActiveTimer(void)
Definition: timers.c:757
char * shutdownCommand
Command for shutting down VDR.
Definition: shutdown.h:44
time_t activeTimeout
Time when VDR will become non-interactive. 0 means never, 1 means unknown time ago.
Definition: shutdown.h:40
const cChannel * Channel(void) const
Definition: timers.h:56
static bool Active(const char *Prompt=NULL)
Definition: plugin.c:415
Definition: timers.h:27
int EmergencyExit
Definition: config.h:344
cString TimeToString(time_t t)
Converts the given time to a string of the form &quot;www mmm dd hh:mm:ss yyyy&quot;.
Definition: tools.c:1087
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition: shutdown.c:38
cShutdownHandler(void)
Definition: shutdown.c:83
const char * message
message to display, s is placeholder for time
Definition: shutdown.h:22
int exitCode
Exit code, if VDR exit was requested, or -1 if not requested.
Definition: shutdown.h:46
static bool Active(void)
Definition: menu.c:4885
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition: shutdown.c:161
cSetup Setup
Definition: config.c:373
cShutdownHandler ShutdownHandler
Definition: shutdown.c:28
int SystemExec(const char *Command, bool Detached)
Definition: thread.c:560
int MinEventTimeout
Definition: config.h:330
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:234
Definition: skins.h:23
static bool Enabled(void)
Definition: remote.h:49
Definition: skins.h:23
static bool Active(const char *FileName=NULL)
Returns true if the cutter is currently active.
Definition: cutter.c:715
static cPlugin * GetNextWakeupPlugin(void)
Definition: plugin.c:432
void SetUserInactiveTimeout(int Seconds=-1, bool Force=false)
Set the time in the future when VDR will switch into non-interactive mode or power down...
Definition: shutdown.c:145
time_t NextWakeupTime
Definition: config.h:331
cCountdown(void)
Definition: shutdown.c:30
#define tr(s)
Definition: i18n.h:85
const char * File(void) const
Definition: timers.h:63
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition: shutdown.c:216
#define isyslog(a...)
Definition: tools.h:35
cString strescape(const char *s, const char *chars)
Definition: tools.c:205
cInterface * Interface
Definition: interface.c:17
virtual time_t WakeupTime(void)
Definition: plugin.c:85
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition: shutdown.c:125
static bool Active(void)
Definition: filetransfer.c:252
bool emergencyExitRequested
The requested exit is an emergency exit.
Definition: shutdown.h:48
time_t timeout
5-minute countdown timer
Definition: shutdown.h:19
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition: shutdown.c:97
Definition: tools.h:166
void Cancel(void)
Cancel the 5 minute shutdown warning countdown.
Definition: shutdown.c:47
bool Done(void)
Check if countdown timer has run out without canceling.
Definition: shutdown.c:56
cSkins Skins
Definition: skins.c:203