vdr 2.7.7
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 5.2 2025/07/21 19:58:14 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
37void 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
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;
86}
87
92
93static time_t GetWakeupTime(const cTimer *Timer)
94{
95 if (Timer) {
96 time_t t = Timer->StartTime();
97 if (Timer->HasFlags(tfVps))
98 t -= Setup.VpsMargin;
99 return t;
100 }
101 return 0;
102}
103
105{
106 if (Setup.EmergencyExit) {
107 esyslog("initiating emergency exit");
109 Exit(1);
110 }
111 else
112 dsyslog("emergency exit request ignored according to setup");
113}
114
116{
117 time_t Delta = Setup.NextWakeupTime ? Setup.NextWakeupTime - time(NULL) : 0;
118
119 if (!Setup.NextWakeupTime || abs(Delta) > ManualStart) {
120 // Apparently the user started VDR manually
121 dsyslog("assuming manual start of VDR");
122 // Set inactive after MinUserInactivity
124 }
125 else {
126 // Set inactive from now on
127 dsyslog("scheduled wakeup time in %jd minutes, assuming automatic start of VDR", intmax_t(Delta / 60));
128 SetUserInactiveTimeout(-3, true);
129 }
130}
131
132void cShutdownHandler::SetShutdownCommand(const char *ShutdownCommand)
133{
134 free(shutdownCommand);
135 shutdownCommand = ShutdownCommand ? strdup(ShutdownCommand) : NULL;
136}
137
138void cShutdownHandler::CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
139{
140 time_t Delta = WakeupTime ? WakeupTime - time(NULL) : 0;
141 cString cmd = cString::sprintf("%s %jd %jd %d \"%s\" %d", shutdownCommand, intmax_t(WakeupTime), intmax_t(Delta), Channel, *strescape(File, "\\\"$"), UserShutdown);
142 isyslog("executing '%s'", *cmd);
143 int Status = SystemExec(cmd, true);
144 if (!WIFEXITED(Status) || WEXITSTATUS(Status))
145 esyslog("SystemExec() failed with status %d", Status);
146 else {
147 Setup.NextWakeupTime = WakeupTime; // Remember this wakeup time for comparison on reboot
148 Setup.Save();
149 }
150}
151
152void cShutdownHandler::SetUserInactiveTimeout(int Seconds, bool Force)
153{
154 if (!Setup.MinUserInactivity && !Force) {
155 activeTimeout = 0;
156 return;
157 }
158 if (Seconds >= 0)
159 activeTimeout = time(NULL) + Seconds;
160 else if (Seconds == -1)
161 activeTimeout = time(NULL) + Setup.MinUserInactivity * 60;
162 else if (Seconds == -2)
163 activeTimeout = 0;
164 else if (Seconds == -3)
165 activeTimeout = 1;
166}
167
169{
170 if (!Interactive && !cRemote::Enabled())
171 return false;
172
173 if (!shutdownCommand) {
174 if (Interactive)
175 Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
176 return false;
177 }
178 if (RecordingsHandler.Active()) {
179 if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?")))
180 return false;
181 }
182
184 time_t Next = GetWakeupTime(Timers->GetNextActiveTimer());
185 time_t Delta = Next ? Next - time(NULL) : 0;
186
187 if (cRecordControls::Active() || (Next && Delta <= 0)) {
188 // VPS recordings in timer end margin may cause Delta <= 0
189 if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?")))
190 return false;
191 }
192 else if (Next && Delta <= Setup.MinEventTimeout * 60) {
193 // Timer within Min Event Timeout
194 if (!Interactive)
195 return false;
196 cString buf = cString::sprintf(tr("Recording in %jd minutes, shut down anyway?"), intmax_t(Delta / 60));
197 if (!Interface->Confirm(buf))
198 return false;
199 }
200
201 if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL))
202 return false;
203
205 Next = Plugin ? Plugin->WakeupTime() : 0;
206 Delta = Next ? Next - time(NULL) : 0;
207 if (Next && Delta <= Setup.MinEventTimeout * 60) {
208 // Plugin wakeup within Min Event Timeout
209 if (!Interactive)
210 return false;
211 cString buf = cString::sprintf(tr("Plugin %s wakes up in %jd min, continue?"), Plugin->Name(), intmax_t(Delta / 60));
212 if (!Interface->Confirm(buf))
213 return false;
214 }
215
216 return true;
217}
218
220{
221 if (RecordingsHandler.Active()) {
222 if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?")))
223 return false;
224 }
225
227 time_t Next = GetWakeupTime(Timers->GetNextActiveTimer());
228 time_t Delta = Next ? Next - time(NULL) : 0;
229
230 if (cRecordControls::Active() || (Next && Delta <= 0)) {
231 // VPS recordings in timer end margin may cause Delta <= 0
232 if (!Interactive || !Interface->Confirm(tr("Recording - restart anyway?")))
233 return false;
234 }
235
236 if (cPluginManager::Active(Interactive ? tr("restart anyway?") : NULL))
237 return false;
238
239 return true;
240}
241
243{
245 time_t Now = time(NULL);
246 const cTimer *Timer = Timers->GetNextActiveTimer();
248
249 time_t Next = GetWakeupTime(Timer);
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}
int Number(void) const
Definition channels.h:179
time_t timeout
5-minute countdown timer
Definition shutdown.h:19
cCountdown(void)
Definition shutdown.c:29
bool timedOut
countdown did run down to 0 and was not canceled
Definition shutdown.h:21
bool Update(void)
Update status display of the countdown.
Definition shutdown.c:64
int counter
last shown time in 10s units
Definition shutdown.h:20
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition shutdown.c:37
const char * message
message to display, s is placeholder for time
Definition shutdown.h:22
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
static cPlugin * GetNextWakeupPlugin(void)
Definition plugin.c:445
static bool Active(const char *Prompt=NULL)
Definition plugin.c:428
virtual time_t WakeupTime(void)
Definition plugin.c:86
const char * Name(void)
Definition plugin.h:36
static bool Active(void)
Definition menu.c:5748
static bool Enabled(void)
Definition remote.h:49
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition shutdown.c:115
time_t activeTimeout
Time when VDR will become non-interactive. 0 means never, 1 means unknown time ago.
Definition shutdown.h:40
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition shutdown.c:132
char * shutdownCommand
Command for shutting down VDR.
Definition shutdown.h:44
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition shutdown.c:168
int exitCode
Exit code, if VDR exit was requested, or -1 if not requested.
Definition shutdown.h:46
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition shutdown.c:104
cShutdownHandler(void)
Definition shutdown.c:79
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition shutdown.c:242
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition shutdown.c:219
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition shutdown.h:54
void CallShutdownCommand(time_t WakeupTime, int Channel, const char *File, bool UserShutdown)
Call the shutdown command with the given parameters.
Definition shutdown.c:138
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:152
time_t retry
Time for retrying the shutdown.
Definition shutdown.h:42
bool emergencyExitRequested
The requested exit is an emergency exit.
Definition shutdown.h:48
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1195
const char * File(void) const
Definition timers.h:78
time_t StartTime(void) const
The start time of this timer, which is the time as given by the user (for normal timers) or the start...
Definition timers.c:828
const cChannel * Channel(void) const
Definition timers.h:70
bool HasFlags(uint Flags) const
Definition timers.c:1135
cSetup Setup
Definition config.c:372
#define tr(s)
Definition i18n.h:85
cInterface * Interface
Definition interface.c:20
cRecordingsHandler RecordingsHandler
Definition recording.c:2123
cShutdownHandler ShutdownHandler
Definition shutdown.c:27
static time_t GetWakeupTime(const cTimer *Timer)
Definition shutdown.c:93
cSkins Skins
Definition skins.c:253
@ mtError
Definition skins.h:37
@ mtStatus
Definition skins.h:37
int SystemExec(const char *Command, bool Detached)
Definition thread.c:1042
#define LOCK_TIMERS_READ
Definition timers.h:275
@ tfVps
Definition timers.h:21
cString strescape(const char *s, const char *chars)
Definition tools.c:280
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:1271
#define dsyslog(a...)
Definition tools.h:37
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36