vdr  2.4.1
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 4.2 2018/03/23 15:39:21 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 "i18n.h"
20 #include "interface.h"
21 #include "menu.h"
22 #include "plugin.h"
23 #include "recording.h"
24 #include "timers.h"
25 #include "tools.h"
26 
28 
30 {
31  timeout = 0;
32  counter = 0;
33  timedOut = false;
34  message = NULL;
35 }
36 
37 void cCountdown::Start(const char *Message, int Seconds)
38 {
39  timeout = time(NULL) + Seconds;
40  counter = -1;
41  timedOut = false;
42  message = Message;
43  Update();
44 }
45 
47 {
48  if (timeout) {
49  timeout = 0;
50  timedOut = false;
51  Skins.Message(mtStatus, NULL);
52  }
53 }
54 
55 bool cCountdown::Done(void)
56 {
57  if (timedOut) {
58  Cancel();
59  return true;
60  }
61  return false;
62 }
63 
65 {
66  if (timeout) {
67  int NewCounter = (timeout - time(NULL) + 9) / 10;
68  if (NewCounter <= 0)
69  timedOut = true;
70  if (counter != NewCounter) {
71  counter = NewCounter;
72  Skins.Message(mtStatus, cString::sprintf(message, *cString::sprintf("%d:%d0", counter > 0 ? counter / 6 : 0, counter > 0 ? counter % 6 : 0)));
73  return true;
74  }
75  }
76  return false;
77 }
78 
80 {
81  activeTimeout = 0;
82  retry = 0;
83  shutdownCommand = NULL;
84  exitCode = -1;
85  emergencyExitRequested = false;
86 }
87 
89 {
90  free(shutdownCommand);
91 }
92 
94 {
95  if (Setup.EmergencyExit) {
96  esyslog("initiating emergency exit");
98  Exit(1);
99  }
100  else
101  dsyslog("emergency exit request ignored according to setup");
102 }
103 
105 {
106  time_t Delta = Setup.NextWakeupTime ? Setup.NextWakeupTime - time(NULL) : 0;
107 
108  if (!Setup.NextWakeupTime || abs(Delta) > ManualStart) {
109  // Apparently the user started VDR manually
110  dsyslog("assuming manual start of VDR");
111  // Set inactive after MinUserInactivity
113  }
114  else {
115  // Set inactive from now on
116  dsyslog("scheduled wakeup time in %ld minutes, assuming automatic start of VDR", Delta / 60);
117  SetUserInactiveTimeout(-3, true);
118  }
119 }
120 
121 void cShutdownHandler::SetShutdownCommand(const char *ShutdownCommand)
122 {
123  free(shutdownCommand);
124  shutdownCommand = ShutdownCommand ? strdup(ShutdownCommand) : NULL;
125 }
126 
127 void cShutdownHandler::CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
128 {
129  time_t Delta = WakeupTime ? WakeupTime - time(NULL) : 0;
130  cString cmd = cString::sprintf("%s %ld %ld %d \"%s\" %d", shutdownCommand, WakeupTime, Delta, Channel, *strescape(File, "\\\"$"), UserShutdown);
131  isyslog("executing '%s'", *cmd);
132  int Status = SystemExec(cmd, true);
133  if (!WIFEXITED(Status) || WEXITSTATUS(Status))
134  esyslog("SystemExec() failed with status %d", Status);
135  else {
136  Setup.NextWakeupTime = WakeupTime; // Remember this wakeup time for comparison on reboot
137  Setup.Save();
138  }
139 }
140 
141 void cShutdownHandler::SetUserInactiveTimeout(int Seconds, bool Force)
142 {
143  if (!Setup.MinUserInactivity && !Force) {
144  activeTimeout = 0;
145  return;
146  }
147  if (Seconds >= 0)
148  activeTimeout = time(NULL) + Seconds;
149  else if (Seconds == -1)
150  activeTimeout = time(NULL) + Setup.MinUserInactivity * 60;
151  else if (Seconds == -2)
152  activeTimeout = 0;
153  else if (Seconds == -3)
154  activeTimeout = 1;
155 }
156 
157 bool cShutdownHandler::ConfirmShutdown(bool Interactive)
158 {
159  if (!Interactive && !cRemote::Enabled())
160  return false;
161 
162  if (!shutdownCommand) {
163  if (Interactive)
164  Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
165  return false;
166  }
167  if (RecordingsHandler.Active()) {
168  if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?")))
169  return false;
170  }
171 
173  const cTimer *Timer = Timers->GetNextActiveTimer();
174  time_t Next = Timer ? Timer->StartTime() : 0;
175  time_t Delta = Timer ? Next - time(NULL) : 0;
176 
177  if (cRecordControls::Active() || (Next && Delta <= 0)) {
178  // VPS recordings in timer end margin may cause Delta <= 0
179  if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?")))
180  return false;
181  }
182  else if (Next && Delta <= Setup.MinEventTimeout * 60) {
183  // Timer within Min Event Timeout
184  if (!Interactive)
185  return false;
186  cString buf = cString::sprintf(tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
187  if (!Interface->Confirm(buf))
188  return false;
189  }
190 
191  if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL))
192  return false;
193 
195  Next = Plugin ? Plugin->WakeupTime() : 0;
196  Delta = Next ? Next - time(NULL) : 0;
197  if (Next && Delta <= Setup.MinEventTimeout * 60) {
198  // Plugin wakeup within Min Event Timeout
199  if (!Interactive)
200  return false;
201  cString buf = cString::sprintf(tr("Plugin %s wakes up in %ld min, continue?"), Plugin->Name(), Delta / 60);
202  if (!Interface->Confirm(buf))
203  return false;
204  }
205 
206  return true;
207 }
208 
209 bool cShutdownHandler::ConfirmRestart(bool Interactive)
210 {
211  if (RecordingsHandler.Active()) {
212  if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?")))
213  return false;
214  }
215 
217  const cTimer *Timer = Timers->GetNextActiveTimer();
218  time_t Next = Timer ? Timer->StartTime() : 0;
219  time_t Delta = Timer ? Next - time(NULL) : 0;
220 
221  if (cRecordControls::Active() || (Next && Delta <= 0)) {
222  // VPS recordings in timer end margin may cause Delta <= 0
223  if (!Interactive || !Interface->Confirm(tr("Recording - restart anyway?")))
224  return false;
225  }
226 
227  if (cPluginManager::Active(Interactive ? tr("restart anyway?") : NULL))
228  return false;
229 
230  return true;
231 }
232 
234 {
236  time_t Now = time(NULL);
237  const cTimer *Timer = Timers->GetNextActiveTimer();
239 
240  time_t Next = Timer ? Timer->StartTime() : 0;
241  time_t NextPlugin = Plugin ? Plugin->WakeupTime() : 0;
242  if (NextPlugin && (!Next || Next > NextPlugin)) {
243  Next = NextPlugin;
244  Timer = NULL;
245  }
246  time_t Delta = Next ? Next - Now : 0;
247 
248  if (Next && Delta < Setup.MinEventTimeout * 60) {
249  if (!Force)
250  return false;
251  Delta = Setup.MinEventTimeout * 60;
252  Next = Now + Delta;
253  Timer = NULL;
254  dsyslog("reboot at %s", *TimeToString(Next));
255  }
256 
257  if (Next && Timer) {
258  dsyslog("next timer event at %s", *TimeToString(Next));
259  CallShutdownCommand(Next, Timer->Channel()->Number(), Timer->File(), Force);
260  }
261  else if (Next && Plugin) {
262  CallShutdownCommand(Next, 0, Plugin->Name(), Force);
263  dsyslog("next plugin wakeup at %s", *TimeToString(Next));
264  }
265  else
266  CallShutdownCommand(Next, 0, "", Force); // Next should always be 0 here. Just for safety, pass it.
267 
268  return true;
269 }
void CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
Call the shutdown command with the given parameters.
Definition: shutdown.c:127
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition: shutdown.c:104
#define dsyslog(a...)
Definition: tools.h:37
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition: interface.c:59
const char * Name(void)
Definition: plugin.h:34
int counter
last shown time in 10s units
Definition: shutdown.h:20
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1127
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:35
time_t retry
Time for retrying the shutdown.
Definition: shutdown.h:42
int MinUserInactivity
Definition: config.h:341
bool Save(void)
Definition: config.c:736
bool Update(void)
Update status display of the countdown.
Definition: shutdown.c:64
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition: shutdown.c:233
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition: shutdown.h:54
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
static bool Active(const char *Prompt=NULL)
Definition: plugin.c:415
Definition: timers.h:27
int EmergencyExit
Definition: config.h:366
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition: tools.c:1203
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition: shutdown.c:37
cShutdownHandler(void)
Definition: shutdown.c:79
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:5608
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition: shutdown.c:157
cSetup Setup
Definition: config.c:372
cShutdownHandler ShutdownHandler
Definition: shutdown.c:27
const cChannel * Channel(void) const
Definition: timers.h:59
cRecordingsHandler RecordingsHandler
Definition: recording.c:1967
int SystemExec(const char *Command, bool Detached)
Definition: thread.c:1034
int MinEventTimeout
Definition: config.h:341
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:250
Definition: skins.h:37
static bool Enabled(void)
Definition: remote.h:49
Definition: skins.h:37
static cPlugin * GetNextWakeupPlugin(void)
Definition: plugin.c:432
bool Active(void)
Checks whether the thread is still alive.
Definition: thread.c:329
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:141
time_t NextWakeupTime
Definition: config.h:342
cCountdown(void)
Definition: shutdown.c:29
#define tr(s)
Definition: i18n.h:85
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition: shutdown.c:209
#define isyslog(a...)
Definition: tools.h:36
#define LOCK_TIMERS_READ
Definition: timers.h:223
cString strescape(const char *s, const char *chars)
Definition: tools.c:254
cInterface * Interface
Definition: interface.c:20
virtual time_t WakeupTime(void)
Definition: plugin.c:85
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition: shutdown.c:121
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:93
Definition: tools.h:176
time_t StartTime(void) const
Definition: timers.c:523
int Number(void) const
Definition: channels.h:179
void Cancel(void)
Cancel the 5 minute shutdown warning countdown.
Definition: shutdown.c:46
bool Done(void)
Check if countdown timer has run out without canceling.
Definition: shutdown.c:55
cSkins Skins
Definition: skins.c:219
const char * File(void) const
Definition: timers.h:66