1 | |
---|
2 | #include <iostream> |
---|
3 | #include <cstdlib> |
---|
4 | using namespace std; |
---|
5 | #include <unistd.h> |
---|
6 | |
---|
7 | #include <QApplication> |
---|
8 | #include <QFile> |
---|
9 | |
---|
10 | #include "compat.h" |
---|
11 | #include "exitcodes.h" |
---|
12 | #include "mythcontext.h" |
---|
13 | #include "mythdb.h" |
---|
14 | #include "mythsystem.h" |
---|
15 | #include "mythverbose.h" |
---|
16 | #include "mythversion.h" |
---|
17 | #include "remoteutil.h" |
---|
18 | #include "tv.h" |
---|
19 | #include "util.h" |
---|
20 | #include "libmythtv/programinfo.h" |
---|
21 | #include "libmythtv/jobqueue.h" |
---|
22 | |
---|
23 | |
---|
24 | |
---|
25 | |
---|
26 | int lockShutdown() |
---|
27 | { |
---|
28 | VERBOSE(VB_GENERAL, "Mythshutdown: --lock"); |
---|
29 | |
---|
30 | MSqlQuery query(MSqlQuery::InitCon()); |
---|
31 | |
---|
32 | // lock setting table |
---|
33 | int tries = 0; |
---|
34 | while (!query.exec("LOCK TABLE settings WRITE;") && tries < 5) |
---|
35 | { |
---|
36 | VERBOSE(VB_GENERAL, "Waiting for lock on setting table"); |
---|
37 | sleep(1); |
---|
38 | tries++; |
---|
39 | } |
---|
40 | |
---|
41 | if (tries >= 5) |
---|
42 | { |
---|
43 | VERBOSE(VB_GENERAL, "Waited too long to obtain lock on setting table"); |
---|
44 | return 1; |
---|
45 | } |
---|
46 | |
---|
47 | // does the setting already exist? |
---|
48 | query.exec("SELECT * FROM settings " |
---|
49 | "WHERE value = 'MythShutdownLock' AND hostname IS NULL;"); |
---|
50 | |
---|
51 | if (query.size() < 1) |
---|
52 | { |
---|
53 | // add the lock setting |
---|
54 | query.exec("INSERT INTO settings (value, data) " |
---|
55 | "VALUES ('MythShutdownLock', '1');"); |
---|
56 | } |
---|
57 | else |
---|
58 | { |
---|
59 | // update the lock setting |
---|
60 | query.exec("UPDATE settings SET data = data + 1 " |
---|
61 | "WHERE value = 'MythShutdownLock' AND hostname IS NULL;"); |
---|
62 | } |
---|
63 | |
---|
64 | // unlock settings table |
---|
65 | query.exec("UNLOCK TABLES;"); |
---|
66 | |
---|
67 | return 0; |
---|
68 | } |
---|
69 | |
---|
70 | int unlockShutdown() |
---|
71 | { |
---|
72 | VERBOSE(VB_GENERAL, "Mythshutdown: --unlock"); |
---|
73 | |
---|
74 | MSqlQuery query(MSqlQuery::InitCon()); |
---|
75 | |
---|
76 | // lock setting table |
---|
77 | int tries = 0; |
---|
78 | while (!query.exec("LOCK TABLE settings WRITE;") && tries < 5) |
---|
79 | { |
---|
80 | VERBOSE(VB_GENERAL, "Waiting for lock on setting table"); |
---|
81 | sleep(1); |
---|
82 | tries++; |
---|
83 | } |
---|
84 | |
---|
85 | if (tries >= 5) |
---|
86 | { |
---|
87 | VERBOSE(VB_GENERAL, "Waited too long to obtain lock on setting table"); |
---|
88 | return 1; |
---|
89 | } |
---|
90 | |
---|
91 | // does the setting exist? |
---|
92 | query.exec("SELECT * FROM settings " |
---|
93 | "WHERE value = 'MythShutdownLock' AND hostname IS NULL;"); |
---|
94 | |
---|
95 | if (query.size() < 1) |
---|
96 | { |
---|
97 | // add the lock setting |
---|
98 | query.exec("INSERT INTO settings (value, data) " |
---|
99 | "VALUES ('MythShutdownLock', '0');"); |
---|
100 | } |
---|
101 | else |
---|
102 | { |
---|
103 | // update lock setting |
---|
104 | query.exec("UPDATE settings SET data = GREATEST(0, data - 1) " |
---|
105 | "WHERE value = 'MythShutdownLock' AND hostname IS NULL;"); |
---|
106 | } |
---|
107 | |
---|
108 | // unlock table |
---|
109 | query.exec("UNLOCK TABLES;"); |
---|
110 | |
---|
111 | // tell the master BE to reset its idle time |
---|
112 | RemoteSendMessage("RESET_IDLETIME"); |
---|
113 | |
---|
114 | return 0; |
---|
115 | } |
---|
116 | |
---|
117 | QDateTime getDailyWakeupTime(QString sPeriod) |
---|
118 | { |
---|
119 | QString sTime = gContext->GetGlobalSetting(sPeriod, "00:00"); |
---|
120 | QTime tTime = QTime::fromString(sTime, "hh:mm"); |
---|
121 | QDateTime dtDateTime = QDateTime(QDate::currentDate(), tTime); |
---|
122 | |
---|
123 | return dtDateTime; |
---|
124 | } |
---|
125 | |
---|
126 | bool isRecording() |
---|
127 | { |
---|
128 | if (!gContext->IsConnectedToMaster()) |
---|
129 | { |
---|
130 | VERBOSE(VB_IMPORTANT, |
---|
131 | "isRecording: Attempting to connect to master server..."); |
---|
132 | if (!gContext->ConnectToMasterServer(false)) |
---|
133 | { |
---|
134 | VERBOSE(VB_IMPORTANT, |
---|
135 | "isRecording: Could not connect to master server!"); |
---|
136 | return false; |
---|
137 | } |
---|
138 | } |
---|
139 | |
---|
140 | return RemoteGetRecordingStatus(NULL, false); |
---|
141 | } |
---|
142 | |
---|
143 | int getStatus(bool bWantRecStatus) |
---|
144 | { |
---|
145 | VERBOSE(VB_GENERAL, "Mythshutdown: --status"); |
---|
146 | |
---|
147 | int res = 0; |
---|
148 | |
---|
149 | if (isRunning("mythtranscode")) |
---|
150 | { |
---|
151 | VERBOSE(VB_IMPORTANT, "Transcoding in progress..."); |
---|
152 | res += 1; |
---|
153 | } |
---|
154 | |
---|
155 | if (isRunning("mythcommflag")) |
---|
156 | { |
---|
157 | VERBOSE(VB_IMPORTANT, "Commercial Flagging in progress..."); |
---|
158 | res += 2; |
---|
159 | } |
---|
160 | |
---|
161 | if (isRunning("mythfilldatabase")) |
---|
162 | { |
---|
163 | VERBOSE(VB_IMPORTANT, "Grabbing EPG data in progress..."); |
---|
164 | res += 4; |
---|
165 | } |
---|
166 | |
---|
167 | if (bWantRecStatus && isRecording()) |
---|
168 | { |
---|
169 | VERBOSE(VB_IMPORTANT, "Recording in progress..."); |
---|
170 | res += 8; |
---|
171 | } |
---|
172 | |
---|
173 | if (gContext->GetGlobalSetting("MythShutdownLock", "0") != "0") |
---|
174 | { |
---|
175 | VERBOSE(VB_IMPORTANT, "Shutdown is locked"); |
---|
176 | res += 16; |
---|
177 | } |
---|
178 | |
---|
179 | if (JobQueue::HasRunningOrPendingJobs(15)) |
---|
180 | { |
---|
181 | VERBOSE(VB_IMPORTANT, "Has queued or pending jobs"); |
---|
182 | res += 32; |
---|
183 | } |
---|
184 | |
---|
185 | QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1"); |
---|
186 | QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1"); |
---|
187 | QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2"); |
---|
188 | QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2"); |
---|
189 | QDateTime dtCurrent = QDateTime::currentDateTime(); |
---|
190 | |
---|
191 | // Check for time periods that cross midnight |
---|
192 | if (dtPeriod1End < dtPeriod1Start) |
---|
193 | { |
---|
194 | if (dtCurrent > dtPeriod1End) |
---|
195 | dtPeriod1End = dtPeriod1End.addDays(1); |
---|
196 | else |
---|
197 | dtPeriod1Start = dtPeriod1Start.addDays(-1); |
---|
198 | } |
---|
199 | |
---|
200 | if (dtPeriod2End < dtPeriod2Start) |
---|
201 | { |
---|
202 | if (dtCurrent > dtPeriod2End) |
---|
203 | dtPeriod2End = dtPeriod2End.addDays(1); |
---|
204 | else |
---|
205 | dtPeriod2Start = dtPeriod2Start.addDays(-1); |
---|
206 | } |
---|
207 | |
---|
208 | // Check for one of the daily wakeup periods |
---|
209 | if (dtPeriod1Start != dtPeriod1End) |
---|
210 | { |
---|
211 | if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End) |
---|
212 | { |
---|
213 | VERBOSE(VB_IMPORTANT, "In a daily wakeup period (1)."); |
---|
214 | res |= 64; |
---|
215 | } |
---|
216 | } |
---|
217 | |
---|
218 | if (dtPeriod2Start != dtPeriod2End) |
---|
219 | { |
---|
220 | if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End) |
---|
221 | { |
---|
222 | VERBOSE(VB_IMPORTANT, "In a daily wakeup period (2)."); |
---|
223 | res |= 64; |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | // Are we about to start a daily wakeup period |
---|
228 | // allow for a 15 minute window |
---|
229 | if (dtPeriod1Start != dtPeriod1End) |
---|
230 | { |
---|
231 | int delta = dtCurrent.secsTo(dtPeriod1Start); |
---|
232 | if (delta >= 0 && delta <= 15 * 60) |
---|
233 | { |
---|
234 | VERBOSE(VB_IMPORTANT, "About to start daily wakeup period (1)"); |
---|
235 | res |= 128; |
---|
236 | } |
---|
237 | } |
---|
238 | |
---|
239 | if (dtPeriod2Start != dtPeriod2End) |
---|
240 | { |
---|
241 | int delta = dtCurrent.secsTo(dtPeriod2Start); |
---|
242 | if (delta >= 0 && delta <= 15 * 60) |
---|
243 | { |
---|
244 | VERBOSE(VB_IMPORTANT, "About to start daily wakeup period (2)"); |
---|
245 | res |= 128; |
---|
246 | } |
---|
247 | } |
---|
248 | |
---|
249 | if (isRunning("mythtv-setup")) |
---|
250 | { |
---|
251 | VERBOSE(VB_IMPORTANT, "Setup is running..."); |
---|
252 | res = 255; |
---|
253 | } |
---|
254 | |
---|
255 | VERBOSE(VB_GENERAL, "Mythshutdown: --status returned: " << res); |
---|
256 | |
---|
257 | return res; |
---|
258 | } |
---|
259 | |
---|
260 | int checkOKShutdown(bool bWantRecStatus) |
---|
261 | { |
---|
262 | // mythbackend wants 0=ok to shutdown, |
---|
263 | // 1=reset idle count, 2=wait for frontend |
---|
264 | |
---|
265 | VERBOSE(VB_GENERAL, "Mythshutdown: --check"); |
---|
266 | |
---|
267 | int res = getStatus(bWantRecStatus); |
---|
268 | |
---|
269 | if (res > 0) |
---|
270 | { |
---|
271 | VERBOSE(VB_IMPORTANT, "Not OK to shutdown"); |
---|
272 | res = 1; |
---|
273 | } |
---|
274 | else |
---|
275 | { |
---|
276 | VERBOSE(VB_IMPORTANT, "OK to shutdown"); |
---|
277 | res = 0; |
---|
278 | } |
---|
279 | |
---|
280 | VERBOSE(VB_GENERAL, "Mythshutdown: --check returned: " << res); |
---|
281 | |
---|
282 | return res; |
---|
283 | } |
---|
284 | |
---|
285 | int setWakeupTime(QString sWakeupTime) |
---|
286 | { |
---|
287 | VERBOSE(VB_GENERAL, "Mythshutdown: --setwakeup"); |
---|
288 | |
---|
289 | VERBOSE(VB_IMPORTANT, |
---|
290 | "Mythshutdown: wakeup time given is: " << sWakeupTime); |
---|
291 | |
---|
292 | // check time given is valid |
---|
293 | QDateTime dtWakeupTime; |
---|
294 | dtWakeupTime = QDateTime::fromString(sWakeupTime, Qt::ISODate); |
---|
295 | |
---|
296 | if (!dtWakeupTime.isValid()) |
---|
297 | { |
---|
298 | VERBOSE(VB_IMPORTANT, QString("Mythshutdown: --setwakeup invalid date " |
---|
299 | "format (%1)\n\t\t\t" |
---|
300 | "must be yyyy-MM-ddThh:mm:ss") |
---|
301 | .arg(sWakeupTime)); |
---|
302 | return 1; |
---|
303 | } |
---|
304 | |
---|
305 | gContext->SaveGlobalSetting("MythShutdownNextScheduled", |
---|
306 | dtWakeupTime.toString(Qt::ISODate)); |
---|
307 | |
---|
308 | return 0; |
---|
309 | } |
---|
310 | |
---|
311 | int setScheduledWakeupTime() |
---|
312 | { |
---|
313 | if (!gContext->IsConnectedToMaster()) |
---|
314 | { |
---|
315 | VERBOSE(VB_IMPORTANT, "setScheduledWakeupTime: " |
---|
316 | "Attempting to connect to master server..."); |
---|
317 | if (!gContext->ConnectToMasterServer(false)) |
---|
318 | { |
---|
319 | VERBOSE(VB_IMPORTANT, "setScheduledWakeupTime: " |
---|
320 | "Could not connect to master server!"); |
---|
321 | return false; |
---|
322 | } |
---|
323 | } |
---|
324 | |
---|
325 | QDateTime nextRecordingStart; |
---|
326 | ProgramList::GetProgramDetailList(nextRecordingStart); |
---|
327 | |
---|
328 | // set the wakeup time for the next scheduled recording |
---|
329 | if (!nextRecordingStart.isNull()) |
---|
330 | { |
---|
331 | int m_preRollSeconds = gContext->GetNumSetting("RecordPreRoll"); |
---|
332 | QDateTime restarttime = nextRecordingStart |
---|
333 | .addSecs((-1) * m_preRollSeconds); |
---|
334 | |
---|
335 | int add = gContext->GetNumSetting("StartupSecsBeforeRecording", 240); |
---|
336 | if (add) |
---|
337 | restarttime = restarttime.addSecs((-1) * add); |
---|
338 | |
---|
339 | setWakeupTime(restarttime.toString(Qt::ISODate)); |
---|
340 | |
---|
341 | return true; |
---|
342 | } |
---|
343 | return false; |
---|
344 | } |
---|
345 | |
---|
346 | int shutdown() |
---|
347 | { |
---|
348 | VERBOSE(VB_GENERAL, "Mythshutdown: --shutdown"); |
---|
349 | |
---|
350 | // get next daily wakeup times if any are set |
---|
351 | QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1"); |
---|
352 | QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1"); |
---|
353 | QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2"); |
---|
354 | QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2"); |
---|
355 | QDateTime dtCurrent = QDateTime::currentDateTime(); |
---|
356 | QDateTime dtNextDailyWakeup = QDateTime(); |
---|
357 | |
---|
358 | // Check for time periods that cross midnight |
---|
359 | if (dtPeriod1End < dtPeriod1Start) |
---|
360 | { |
---|
361 | if (dtCurrent > dtPeriod1End) |
---|
362 | dtPeriod1End = dtPeriod1End.addDays(1); |
---|
363 | else |
---|
364 | dtPeriod1Start = dtPeriod1Start.addDays(-1); |
---|
365 | } |
---|
366 | |
---|
367 | if (dtPeriod2End < dtPeriod2Start) |
---|
368 | { |
---|
369 | if (dtCurrent > dtPeriod2End) |
---|
370 | dtPeriod2End = dtPeriod2End.addDays(1); |
---|
371 | else |
---|
372 | dtPeriod2Start = dtPeriod2Start.addDays(-1); |
---|
373 | } |
---|
374 | |
---|
375 | // have we passed the first wakeup time today |
---|
376 | if (dtPeriod1Start != dtPeriod1End) |
---|
377 | { |
---|
378 | if (dtCurrent < dtPeriod1Start) |
---|
379 | { |
---|
380 | VERBOSE(VB_IMPORTANT, "daily wakeup today at " << |
---|
381 | dtPeriod1Start.toString("hh:mm:ss")); |
---|
382 | dtNextDailyWakeup = dtPeriod1Start; |
---|
383 | } |
---|
384 | } |
---|
385 | |
---|
386 | // have we passed the second wakeup time today |
---|
387 | if (!dtNextDailyWakeup.isValid() && dtPeriod2Start != dtPeriod2End) |
---|
388 | { |
---|
389 | if (dtCurrent < dtPeriod2Start) |
---|
390 | { |
---|
391 | VERBOSE(VB_IMPORTANT, "daily wakeup today at " << |
---|
392 | dtPeriod2Start.toString("hh:mm:ss")); |
---|
393 | dtNextDailyWakeup = dtPeriod2Start; |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | // if we have at least one valid daily wakeup time |
---|
398 | // and dtNextDailyWakeup is still not valid |
---|
399 | // then next daily wakeup is tomorrow |
---|
400 | if (!dtNextDailyWakeup.isValid()) |
---|
401 | { |
---|
402 | if (dtPeriod1Start != dtPeriod1End) |
---|
403 | dtNextDailyWakeup = dtPeriod1Start; |
---|
404 | else if (dtPeriod2Start != dtPeriod2End) |
---|
405 | dtNextDailyWakeup = dtPeriod2Start; |
---|
406 | |
---|
407 | if (dtNextDailyWakeup.isValid()) |
---|
408 | { |
---|
409 | dtNextDailyWakeup = dtNextDailyWakeup.addDays(1); |
---|
410 | |
---|
411 | VERBOSE(VB_IMPORTANT, "next daily wakeup is tomorrow at " << |
---|
412 | dtNextDailyWakeup.toString("hh:mm:ss")); |
---|
413 | } |
---|
414 | } |
---|
415 | |
---|
416 | // if dtNextDailyWakeup is still not valid then no daily wakeups are set |
---|
417 | if (!dtNextDailyWakeup.isValid()) |
---|
418 | VERBOSE(VB_IMPORTANT,"no daily wakeup times are set"); |
---|
419 | |
---|
420 | // get next scheduled wake up for a recording if any |
---|
421 | QDateTime dtNextRecordingStart = QDateTime(); |
---|
422 | QString s = gContext->GetGlobalSetting("MythShutdownNextScheduled", ""); |
---|
423 | if (s != "") |
---|
424 | dtNextRecordingStart = QDateTime::fromString(s, Qt::ISODate); |
---|
425 | |
---|
426 | if (!dtNextRecordingStart.isValid()) |
---|
427 | VERBOSE(VB_IMPORTANT,"no recording time is set"); |
---|
428 | else |
---|
429 | VERBOSE(VB_IMPORTANT, "recording scheduled at: " << |
---|
430 | dtNextRecordingStart.toString(Qt::ISODate)); |
---|
431 | |
---|
432 | // check if scheduled recording time has already passed |
---|
433 | if (dtNextRecordingStart.isValid()) |
---|
434 | { |
---|
435 | int delta = dtCurrent.secsTo(dtNextRecordingStart); |
---|
436 | |
---|
437 | if (delta < 0) |
---|
438 | { |
---|
439 | VERBOSE(VB_IMPORTANT, "Scheduled recording time has" |
---|
440 | " already passed. Schedule deleted"); |
---|
441 | |
---|
442 | dtNextRecordingStart = QDateTime(); |
---|
443 | gContext->SaveGlobalSetting("MythShutdownNextScheduled", ""); |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | QDateTime dtWakeupTime = QDateTime(); |
---|
448 | |
---|
449 | // simple case |
---|
450 | // no daily wakeup set |
---|
451 | // no scheduled program set |
---|
452 | // just shut down |
---|
453 | if (!dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid()) |
---|
454 | { |
---|
455 | dtWakeupTime = QDateTime(); |
---|
456 | VERBOSE(VB_IMPORTANT, "no wake up time set and no scheduled program"); |
---|
457 | } |
---|
458 | |
---|
459 | // no daily wakeup set |
---|
460 | // scheduled program is set |
---|
461 | if (dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid()) |
---|
462 | { |
---|
463 | dtWakeupTime = dtNextRecordingStart; |
---|
464 | VERBOSE(VB_IMPORTANT, "will wake up at next scheduled program"); |
---|
465 | } |
---|
466 | |
---|
467 | // daily wakeup is set |
---|
468 | // no scheduled program is set |
---|
469 | if (!dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid()) |
---|
470 | { |
---|
471 | dtWakeupTime = dtNextDailyWakeup; |
---|
472 | VERBOSE(VB_IMPORTANT, "will wake up at next daily wakeup"); |
---|
473 | } |
---|
474 | |
---|
475 | // daily wakeup is set |
---|
476 | // scheduled program is set |
---|
477 | // wake up at which ever is the earliest |
---|
478 | if (dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid()) |
---|
479 | { |
---|
480 | if (dtNextDailyWakeup < dtNextRecordingStart) |
---|
481 | { |
---|
482 | VERBOSE(VB_IMPORTANT, "program is scheduled but will wake up " |
---|
483 | "at next daily wakeup"); |
---|
484 | dtWakeupTime = dtNextDailyWakeup; |
---|
485 | } |
---|
486 | else |
---|
487 | { |
---|
488 | VERBOSE(VB_IMPORTANT, "daily wakeup is set but will wake up " |
---|
489 | "at next scheduled program"); |
---|
490 | dtWakeupTime = dtNextRecordingStart; |
---|
491 | } |
---|
492 | } |
---|
493 | |
---|
494 | // save the next wakuptime in the db |
---|
495 | gContext->SaveGlobalSetting("MythShutdownWakeupTime", |
---|
496 | dtWakeupTime.toString(Qt::ISODate)); |
---|
497 | |
---|
498 | // stop here to debug |
---|
499 | //return 0; |
---|
500 | |
---|
501 | int shutdownmode = 0; // default to poweroff no reboot |
---|
502 | QString nvramRestartCmd = |
---|
503 | gContext->GetSetting("MythShutdownNvramRestartCmd", ""); |
---|
504 | |
---|
505 | if (dtWakeupTime.isValid()) |
---|
506 | { |
---|
507 | // dont't shutdown if we are within 15 mins of the next wakeup time |
---|
508 | if (dtCurrent.secsTo(dtWakeupTime) > 15 * 60) |
---|
509 | { |
---|
510 | QString nvramCommand = gContext->GetSetting("MythShutdownNvramCmd", |
---|
511 | "/usr/bin/nvram-wakeup --settime $time"); |
---|
512 | |
---|
513 | QString wakeup_timeformat = gContext->GetSetting( |
---|
514 | "MythShutdownWakeupTimeFmt", "time_t"); |
---|
515 | |
---|
516 | if (wakeup_timeformat == "time_t") |
---|
517 | { |
---|
518 | QString time_ts; |
---|
519 | nvramCommand.replace( |
---|
520 | "$time", time_ts.setNum(dtWakeupTime.toTime_t())); |
---|
521 | } |
---|
522 | else |
---|
523 | nvramCommand.replace( |
---|
524 | "$time", dtWakeupTime.toString(wakeup_timeformat)); |
---|
525 | |
---|
526 | VERBOSE(VB_IMPORTANT, |
---|
527 | "sending command to set time in bios\n\t\t\t" |
---|
528 | + nvramCommand); |
---|
529 | |
---|
530 | shutdownmode = myth_system(nvramCommand); |
---|
531 | if (WIFEXITED(shutdownmode)) |
---|
532 | shutdownmode = WEXITSTATUS(shutdownmode); |
---|
533 | |
---|
534 | VERBOSE(VB_IMPORTANT, (nvramCommand + " exited with code %2") |
---|
535 | .arg(shutdownmode)); |
---|
536 | |
---|
537 | if (shutdownmode == 2) |
---|
538 | { |
---|
539 | VERBOSE(VB_IMPORTANT, "nvram-wakeup failed to set time in bios"); |
---|
540 | return 1; |
---|
541 | } |
---|
542 | |
---|
543 | // we don't trust the return code from nvram-wakeup so only reboot |
---|
544 | // if the user has set a restart command |
---|
545 | if (nvramRestartCmd == "") |
---|
546 | shutdownmode = 0; |
---|
547 | else |
---|
548 | shutdownmode = 1; |
---|
549 | } |
---|
550 | else |
---|
551 | { |
---|
552 | VERBOSE(VB_IMPORTANT, "The next wakeup time is less than" |
---|
553 | " 15 mins away, not shutting down"); |
---|
554 | return 0; |
---|
555 | } |
---|
556 | } |
---|
557 | |
---|
558 | int res = 0; |
---|
559 | |
---|
560 | switch (shutdownmode) |
---|
561 | { |
---|
562 | case 0: |
---|
563 | { |
---|
564 | VERBOSE(VB_IMPORTANT, "everything looks fine, shutting down ..."); |
---|
565 | QString poweroffCmd = gContext->GetSetting( |
---|
566 | "MythShutdownPoweroff", "/sbin/poweroff"); |
---|
567 | VERBOSE(VB_IMPORTANT, ".."); |
---|
568 | VERBOSE(VB_IMPORTANT, "."); |
---|
569 | VERBOSE(VB_IMPORTANT, "shutting down ..."); |
---|
570 | |
---|
571 | myth_system(poweroffCmd); |
---|
572 | res = 0; |
---|
573 | break; |
---|
574 | } |
---|
575 | case 1: |
---|
576 | { |
---|
577 | VERBOSE(VB_IMPORTANT, |
---|
578 | "everything looks fine, but reboot is needed"); |
---|
579 | VERBOSE(VB_IMPORTANT, "sending command to bootloader ..."); |
---|
580 | VERBOSE(VB_IMPORTANT, nvramRestartCmd); |
---|
581 | |
---|
582 | myth_system(nvramRestartCmd); |
---|
583 | |
---|
584 | VERBOSE(VB_IMPORTANT, ".."); |
---|
585 | VERBOSE(VB_IMPORTANT, "."); |
---|
586 | VERBOSE(VB_IMPORTANT, "rebooting ..."); |
---|
587 | |
---|
588 | QString rebootCmd = |
---|
589 | gContext->GetSetting("MythShutdownReboot", "/sbin/reboot"); |
---|
590 | myth_system(rebootCmd); |
---|
591 | res = 0; |
---|
592 | break; |
---|
593 | } |
---|
594 | default: |
---|
595 | VERBOSE(VB_IMPORTANT, "panic. invalid shutdown mode, do nothing"); |
---|
596 | res = 1; |
---|
597 | break; |
---|
598 | } |
---|
599 | |
---|
600 | return res; |
---|
601 | } |
---|
602 | |
---|
603 | int startup() |
---|
604 | { |
---|
605 | VERBOSE(VB_GENERAL, "Mythshutdown: --startup"); |
---|
606 | |
---|
607 | int res = 0; |
---|
608 | QDateTime startupTime = QDateTime(); |
---|
609 | QString s = gContext->GetGlobalSetting("MythshutdownWakeupTime", ""); |
---|
610 | if (s != "") |
---|
611 | startupTime = QDateTime::fromString(s, Qt::ISODate); |
---|
612 | |
---|
613 | // if we don't have a valid startup time assume we were started manually |
---|
614 | if (!startupTime.isValid()) |
---|
615 | res = 1; |
---|
616 | else |
---|
617 | { |
---|
618 | // if we started within 15mins of the saved wakeup time assume we started |
---|
619 | // automatically to record or for a daily wakeup/shutdown period |
---|
620 | |
---|
621 | int delta = startupTime.secsTo(QDateTime::currentDateTime()); |
---|
622 | if (delta < 0) |
---|
623 | delta = -delta; |
---|
624 | |
---|
625 | if (delta < 15 * 60) |
---|
626 | res = 0; |
---|
627 | else |
---|
628 | res = 1; |
---|
629 | } |
---|
630 | |
---|
631 | if (res) |
---|
632 | VERBOSE(VB_IMPORTANT, "looks like we were started manually" << res); |
---|
633 | else |
---|
634 | VERBOSE(VB_IMPORTANT, "looks like we were started automatically" << res); |
---|
635 | |
---|
636 | |
---|
637 | VERBOSE(VB_GENERAL, "Mythshutdown: --startup returned: " << res); |
---|
638 | |
---|
639 | return res; |
---|
640 | } |
---|
641 | |
---|
642 | void showUsage() |
---|
643 | { |
---|
644 | QString binname = "mythshutdown"; |
---|
645 | |
---|
646 | extern const char *myth_source_version; |
---|
647 | extern const char *myth_source_path; |
---|
648 | |
---|
649 | VERBOSE(VB_IMPORTANT, QString("%1 version: %2 [%3] www.mythtv.org") |
---|
650 | .arg(binname) |
---|
651 | .arg(myth_source_path) |
---|
652 | .arg(myth_source_version)); |
---|
653 | |
---|
654 | cout << "Usage of mythshutdown\n"; |
---|
655 | cout << "-w/--setwakeup time (sets the wakeup time. time=yyyy-MM-ddThh:mm:ss\n"; |
---|
656 | cout << " doesn't write it into nvram)\n"; |
---|
657 | cout << "-t/--setscheduledwakeup (sets the wakeup time to the next scheduled recording)\n"; |
---|
658 | cout << "-q/--shutdown (set nvram-wakeup time and shutdown)\n"; |
---|
659 | cout << "-x/--safeshutdown (equal to -c -t -q. check shutdown possible, set\n"; |
---|
660 | cout <<" scheduled wakeup and shutdown)\n"; |
---|
661 | cout << "-p/--startup (check startup. check will return 0 if automatic\n"; |
---|
662 | cout << " 1 for manually)\n"; |
---|
663 | cout << "-c/--check flag (check shutdown possible\n"; |
---|
664 | cout << " flag is 0 - don't check recording status\n"; |
---|
665 | cout << " 1 - do check recording status (default)\n"; |
---|
666 | cout << " returns 0 ok to shutdown\n"; |
---|
667 | cout << " 1 reset idle check)\n"; |
---|
668 | cout << "-l/--lock (disable shutdown. check will return 1.)\n"; |
---|
669 | cout << "-u/--unlock (enable shutdown. check will return 0)\n"; |
---|
670 | cout << "-s/--status flag (returns a code indicating the current status)\n"; |
---|
671 | cout << " flag is 0 - don't check recording status\n"; |
---|
672 | cout << " 1 - do check recording status (default)\n"; |
---|
673 | cout << " 0 - Idle\n"; |
---|
674 | cout << " 1 - Transcoding\n"; |
---|
675 | cout << " 2 - Commercial Flagging\n"; |
---|
676 | cout << " 4 - Grabbing EPG data\n"; |
---|
677 | cout << " 8 - Recording - only valid if flag is 1\n"; |
---|
678 | cout << " 16 - Locked\n"; |
---|
679 | cout << " 32 - Jobs running or pending\n"; |
---|
680 | cout << " 64 - In a daily wakeup/shutdown period\n"; |
---|
681 | cout << " 128 - Less than 15 minutes to next wakeup period\n"; |
---|
682 | cout << " 255 - Setup is running\n"; |
---|
683 | cout << "-v/--verbose debug-level (Use '-v help' for level info\n"; |
---|
684 | cout << "-h/--help (shows this usage)\n"; |
---|
685 | cout << "\n"; |
---|
686 | } |
---|
687 | |
---|
688 | int main(int argc, char **argv) |
---|
689 | { |
---|
690 | // by default we don't output any messages |
---|
691 | print_verbose_messages = VB_NONE; |
---|
692 | |
---|
693 | QApplication a(argc, argv, false); |
---|
694 | |
---|
695 | |
---|
696 | bool bLockShutdown = false; |
---|
697 | bool bUnlockShutdown = false; |
---|
698 | bool bCheckOKShutdown = false; |
---|
699 | bool bStartup = false; |
---|
700 | bool bShutdown = false; |
---|
701 | bool bGetStatus = false; |
---|
702 | bool bSetWakeupTime = false; |
---|
703 | QString sWakeupTime = ""; |
---|
704 | bool bSetScheduledWakeupTime = false; |
---|
705 | bool bCheckAndShutdown = false; |
---|
706 | bool bWantRecStatus = true; |
---|
707 | |
---|
708 | // Check command line arguments |
---|
709 | for (int argpos = 1; argpos < a.argc(); ++argpos) |
---|
710 | { |
---|
711 | if (!strcmp(a.argv()[argpos],"-v") || |
---|
712 | !strcmp(a.argv()[argpos],"--verbose")) |
---|
713 | { |
---|
714 | if (a.argc()-1 > argpos) |
---|
715 | { |
---|
716 | if (parse_verbose_arg(a.argv()[argpos+1]) == |
---|
717 | GENERIC_EXIT_INVALID_CMDLINE) |
---|
718 | return FRONTEND_EXIT_INVALID_CMDLINE; |
---|
719 | ++argpos; |
---|
720 | } |
---|
721 | else |
---|
722 | { |
---|
723 | cerr << "Missing argument to -v/--verbose option\n"; |
---|
724 | return FRONTEND_EXIT_INVALID_CMDLINE; |
---|
725 | } |
---|
726 | } |
---|
727 | |
---|
728 | else if (!strcmp(a.argv()[argpos],"-l") || |
---|
729 | !strcmp(a.argv()[argpos],"--lock")) |
---|
730 | { |
---|
731 | bLockShutdown = true; |
---|
732 | } |
---|
733 | else if (!strcmp(a.argv()[argpos],"-u") || |
---|
734 | !strcmp(a.argv()[argpos],"--unlock")) |
---|
735 | { |
---|
736 | bUnlockShutdown = true; |
---|
737 | } |
---|
738 | else if (!strcmp(a.argv()[argpos],"-c") || |
---|
739 | !strcmp(a.argv()[argpos],"--check")) |
---|
740 | { |
---|
741 | bCheckOKShutdown = true; |
---|
742 | if (a.argc() - 1 > argpos) |
---|
743 | { |
---|
744 | QString s = a.argv()[argpos+1]; |
---|
745 | if (!s.startsWith("-")) |
---|
746 | { |
---|
747 | if (s == "0") |
---|
748 | bWantRecStatus = false; |
---|
749 | ++argpos; |
---|
750 | } |
---|
751 | } |
---|
752 | } |
---|
753 | else if (!strcmp(a.argv()[argpos],"-s") || |
---|
754 | !strcmp(a.argv()[argpos],"--status")) |
---|
755 | { |
---|
756 | bGetStatus = true; |
---|
757 | if (a.argc() - 1 > argpos) |
---|
758 | { |
---|
759 | QString s = a.argv()[argpos+1]; |
---|
760 | if (!s.startsWith("-")) |
---|
761 | { |
---|
762 | if (s == "0") |
---|
763 | bWantRecStatus = false; |
---|
764 | ++argpos; |
---|
765 | } |
---|
766 | } |
---|
767 | } |
---|
768 | else if (!strcmp(a.argv()[argpos],"-w") || |
---|
769 | !strcmp(a.argv()[argpos],"--setwakeup")) |
---|
770 | { |
---|
771 | if (a.argc() - 1 > argpos) |
---|
772 | { |
---|
773 | sWakeupTime = a.argv()[argpos+1]; |
---|
774 | ++argpos; |
---|
775 | } |
---|
776 | else |
---|
777 | { |
---|
778 | cout << "mythshutdown: Missing argument to " |
---|
779 | "-w/--setwakeup option" << endl; |
---|
780 | return FRONTEND_EXIT_INVALID_CMDLINE; |
---|
781 | } |
---|
782 | |
---|
783 | bSetWakeupTime = true; |
---|
784 | } |
---|
785 | else if (!strcmp(a.argv()[argpos],"-q") || |
---|
786 | !strcmp(a.argv()[argpos],"--shutdown")) |
---|
787 | { |
---|
788 | bShutdown = true; |
---|
789 | } |
---|
790 | else if (!strcmp(a.argv()[argpos],"-p") || |
---|
791 | !strcmp(a.argv()[argpos],"--startup")) |
---|
792 | { |
---|
793 | bStartup = true; |
---|
794 | } |
---|
795 | else if (!strcmp(a.argv()[argpos],"-h") || |
---|
796 | !strcmp(a.argv()[argpos],"--help")) |
---|
797 | { |
---|
798 | showUsage(); |
---|
799 | return GENERIC_EXIT_OK; |
---|
800 | } |
---|
801 | else if (!strcmp(a.argv()[argpos],"-t") || |
---|
802 | !strcmp(a.argv()[argpos],"--setscheduledwakeup")) |
---|
803 | { |
---|
804 | bSetScheduledWakeupTime = true; |
---|
805 | } |
---|
806 | else if (!strcmp(a.argv()[argpos],"-x") || |
---|
807 | !strcmp(a.argv()[argpos],"--safeshutdown")) |
---|
808 | { |
---|
809 | bCheckAndShutdown = true; |
---|
810 | } |
---|
811 | |
---|
812 | else |
---|
813 | { |
---|
814 | cout << "Invalid argument: " << a.argv()[argpos] << endl; |
---|
815 | showUsage(); |
---|
816 | return FRONTEND_EXIT_INVALID_CMDLINE; |
---|
817 | } |
---|
818 | } |
---|
819 | |
---|
820 | |
---|
821 | gContext = new MythContext(MYTH_BINARY_VERSION); |
---|
822 | if (!gContext->Init(false)) |
---|
823 | { |
---|
824 | cout << "mythshutdown: Could not initialize myth context. " |
---|
825 | "Exiting." << endl; |
---|
826 | return FRONTEND_EXIT_NO_MYTHCONTEXT; |
---|
827 | } |
---|
828 | |
---|
829 | |
---|
830 | int res = 0; |
---|
831 | |
---|
832 | if (bLockShutdown) |
---|
833 | res = lockShutdown(); |
---|
834 | else if (bUnlockShutdown) |
---|
835 | res = unlockShutdown(); |
---|
836 | else if (bCheckOKShutdown) |
---|
837 | res = checkOKShutdown(bWantRecStatus); |
---|
838 | else if (bSetScheduledWakeupTime) |
---|
839 | res = setScheduledWakeupTime(); |
---|
840 | else if (bStartup) |
---|
841 | res = startup(); |
---|
842 | else if (bShutdown) |
---|
843 | res = shutdown(); |
---|
844 | else if (bGetStatus) |
---|
845 | res = getStatus(bWantRecStatus); |
---|
846 | else if (bSetWakeupTime) |
---|
847 | res = setWakeupTime(sWakeupTime); |
---|
848 | else if (bCheckAndShutdown) |
---|
849 | { |
---|
850 | res = checkOKShutdown(true); |
---|
851 | if (res == 0) // Nothing to stop a shutdown (eg. recording in progress). |
---|
852 | { |
---|
853 | res = setScheduledWakeupTime(); |
---|
854 | res = shutdown(); |
---|
855 | } |
---|
856 | } |
---|
857 | else |
---|
858 | showUsage(); |
---|
859 | |
---|
860 | delete gContext; |
---|
861 | |
---|
862 | return res; |
---|
863 | } |
---|
864 | |
---|