MythTV  master
mythshutdown.cpp
Go to the documentation of this file.
1 
2 // C/C++
3 #include <cstdlib>
4 #include <iostream>
5 #include <unistd.h>
6 
7 // Qt
8 #include <QtGlobal>
9 #include <QCoreApplication>
10 #include <QFile>
11 #include <QTimeZone>
12 
13 // MythTV
14 #include "libmyth/mythcontext.h"
15 #include "libmythbase/compat.h"
16 #include "libmythbase/exitcodes.h"
17 #include "libmythbase/mythdate.h"
18 #include "libmythbase/mythdb.h"
21 #include "libmythbase/mythversion.h"
23 #include "libmythbase/remoteutil.h"
25 #include "libmythtv/jobqueue.h"
26 #include "libmythtv/tv.h"
27 #include "libmythtv/tvremoteutil.h"
28 
29 // MythShutdown
31 
32 static void setGlobalSetting(const QString &key, const QString &v)
33 {
34  QString value = (v.isNull()) ? QString("") : v;
35 
37  if (query.isConnected())
38  {
39  query.prepare("DELETE FROM settings WHERE value = :KEY;");
40  query.bindValue(":KEY", key);
41 
42  if (!query.exec() || !query.isActive())
43  MythDB::DBError("Clear setting", query);
44 
45  query.prepare("INSERT INTO settings ( value, data ) "
46  "VALUES ( :VALUE, :DATA );");
47  query.bindValue(":VALUE", key);
48  query.bindValue(":DATA", value);
49 
50  if (!query.exec() || !query.isActive())
51  MythDB::DBError("Save new global setting", query);
52  }
53  else
54  {
55  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
56  QString("Error: Database not open while trying "
57  "to save setting: %1\n").arg(key));
58  }
59 }
60 
61 static QString getGlobalSetting(const QString &key, const QString &defaultval)
62 {
63  QString value = defaultval;
64 
66  if (query.isConnected())
67  {
68  query.prepare("SELECT data FROM settings WHERE value = :KEY AND "
69  "hostname IS NULL;");
70  query.bindValue(":KEY", key);
71  if (query.exec() && query.next())
72  value = query.value(0).toString();
73  }
74  else
75  {
76  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
77  QObject::tr("Error: Database not open while trying to "
78  "load setting: %1", "mythshutdown").arg(key) + "\n");
79  }
80 
81  return value;
82 }
83 
84 static int lockShutdown()
85 {
86  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --lock");
87 
89 
90  // lock setting table
91  int tries = 0;
92  while (!query.exec("LOCK TABLE settings WRITE;") && tries < 5)
93  {
94  LOG(VB_GENERAL, LOG_INFO, "Waiting for lock on setting table");
95  sleep(1);
96  tries++;
97  }
98 
99  if (tries >= 5)
100  {
101  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
102  QObject::tr("Error: Waited too long to obtain "
103  "lock on setting table", "mythshutdown") + "\n");
104  return 1;
105  }
106 
107  // does the setting already exist?
108  query.prepare("SELECT * FROM settings "
109  "WHERE value = 'MythShutdownLock' AND hostname IS NULL;");
110  if (!query.exec())
111  MythDB::DBError("lockShutdown -- select", query);
112 
113  if (query.size() < 1)
114  {
115  // add the lock setting
116  query.prepare("INSERT INTO settings (value, data) "
117  "VALUES ('MythShutdownLock', '1');");
118  if (!query.exec())
119  MythDB::DBError("lockShutdown -- insert", query);
120  }
121  else
122  {
123  // update the lock setting
124  query.prepare("UPDATE settings SET data = data + 1 "
125  "WHERE value = 'MythShutdownLock' "
126  "AND hostname IS NULL;");
127  if (!query.exec())
128  MythDB::DBError("lockShutdown -- update", query);
129  }
130 
131  // unlock settings table
132  if (!query.exec("UNLOCK TABLES;"))
133  MythDB::DBError("lockShutdown -- unlock", query);
134 
135  return 0;
136 }
137 
138 static int unlockShutdown()
139 {
140  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --unlock");
141 
142  MSqlQuery query(MSqlQuery::InitCon());
143 
144  // lock setting table
145  int tries = 0;
146  while (!query.exec("LOCK TABLE settings WRITE;") && tries < 5)
147  {
148  LOG(VB_GENERAL, LOG_INFO, "Waiting for lock on setting table");
149  sleep(1);
150  tries++;
151  }
152 
153  if (tries >= 5)
154  {
155  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
156  QObject::tr("Error: Waited too long to obtain "
157  "lock on setting table", "mythshutdown") + "\n");
158  return 1;
159  }
160 
161  // does the setting exist?
162  query.prepare("SELECT * FROM settings "
163  "WHERE value = 'MythShutdownLock' AND hostname IS NULL;");
164  if (!query.exec())
165  MythDB::DBError("unlockShutdown -- select", query);
166 
167  if (query.size() < 1)
168  {
169  // add the lock setting
170  query.prepare("INSERT INTO settings (value, data) "
171  "VALUES ('MythShutdownLock', '0');");
172  if (!query.exec())
173  MythDB::DBError("unlockShutdown -- insert", query);
174  }
175  else
176  {
177  // update lock setting
178  query.prepare("UPDATE settings SET data = GREATEST(0, data - 1) "
179  "WHERE value = 'MythShutdownLock' "
180  "AND hostname IS NULL;");
181  if (!query.exec())
182  MythDB::DBError("unlockShutdown -- update", query);
183  }
184 
185  // unlock table
186  if (!query.exec("UNLOCK TABLES;"))
187  MythDB::DBError("unlockShutdown -- unlock", query);
188 
189  // tell the master BE to reset its idle time
190  gCoreContext->SendMessage("RESET_IDLETIME");
191 
192  return 0;
193 }
194 
208 static bool isRunning(const char *program)
209 {
210  QString command = QString("ps ch -C %1 -o pid > /dev/null").arg(program);
211  return (myth_system(command) == GENERIC_EXIT_OK);
212 }
213 
214 static QDateTime getDailyWakeupTime(const QString& sPeriod)
215 {
216  QString sTime = getGlobalSetting(sPeriod, "00:00");
217  QTime tTime = QTime::fromString(sTime, "hh:mm");
218 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
219  return QDateTime(MythDate::current().toLocalTime().date(),
220  tTime, Qt::LocalTime).toUTC();
221 #else
222  return QDateTime(MythDate::current().toLocalTime().date(),
223  tTime, QTimeZone(QTimeZone::LocalTime)).toUTC();
224 #endif
225 }
226 
227 static bool isRecording()
228 {
230  {
231  LOG(VB_GENERAL, LOG_INFO,
232  "isRecording: Attempting to connect to master server...");
233  if (!gCoreContext->ConnectToMasterServer(false))
234  {
235  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
236  QObject::tr("Error: Could not connect to master server",
237  "mythshutdown") + "\n");
238  return false;
239  }
240  }
241 
242  return RemoteGetRecordingStatus(nullptr, false);
243 }
244 
245 static int getStatus(bool bWantRecStatus)
246 {
247  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --status");
248 
249  int res = 0;
250 
251  if (isRunning("mythtranscode"))
252  {
253  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
254  QObject::tr("Transcoding in progress...", "mythshutdown") + "\n");
255  res |= 1;
256  }
257 
258  if (isRunning("mythcommflag"))
259  {
260  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
261  QObject::tr("Commercial Detection in progress...",
262  "mythshutdown") + "\n");
263  res |= 2;
264  }
265 
266  if (isRunning("mythfilldatabase"))
267  {
268  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
269  QObject::tr("Grabbing EPG data in progress...", "mythshutdown") +
270  "\n");
271  res |= 4;
272  }
273 
274  if (bWantRecStatus && isRecording())
275  {
276  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
277  QObject::tr("Recording in progress...", "mythshutdown") + "\n");
278  res |= 8;
279  }
280 
281  if (getGlobalSetting("MythShutdownLock", "0") != "0")
282  {
283  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
284  QObject::tr("Shutdown is locked", "mythshutdown") + "\n");
285  res |= 16;
286  }
287 
289  {
290  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
291  QObject::tr("Has queued or pending jobs", "mythshutdown") + "\n");
292  res |= 32;
293  }
294 
295  QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1");
296  QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1");
297  QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2");
298  QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2");
299  QDateTime dtCurrent = MythDate::current();
300 
301  // Check for time periods that cross midnight
302  if (dtPeriod1End < dtPeriod1Start)
303  {
304  if (dtCurrent > dtPeriod1End)
305  dtPeriod1End = dtPeriod1End.addDays(1);
306  else
307  dtPeriod1Start = dtPeriod1Start.addDays(-1);
308  }
309 
310  if (dtPeriod2End < dtPeriod2Start)
311  {
312  if (dtCurrent > dtPeriod2End)
313  dtPeriod2End = dtPeriod2End.addDays(1);
314  else
315  dtPeriod2Start = dtPeriod2Start.addDays(-1);
316  }
317 
318  // Check for one of the daily wakeup periods
319  if (dtPeriod1Start != dtPeriod1End)
320  {
321  if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End)
322  {
323  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
324  QObject::tr("In a daily wakeup period (1).", "mythshutdown") +
325  "\n");
326  res |= 64;
327  }
328  }
329 
330  if (dtPeriod2Start != dtPeriod2End)
331  {
332  if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End)
333  {
334  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
335  QObject::tr("In a daily wakeup period (2).", "mythshutdown") +
336  "\n");
337  res |= 64;
338  }
339  }
340 
341  // Are we about to start a daily wakeup period
342  // allow for a 15 minute window
343  if (dtPeriod1Start != dtPeriod1End)
344  {
345  auto delta = std::chrono::seconds(dtCurrent.secsTo(dtPeriod1Start));
346  if (delta >= 0s && delta <= 15min)
347  {
348  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
349  QObject::tr("About to start daily wakeup period (1)",
350  "mythshutdown") + "\n");
351  res |= 128;
352  }
353  }
354 
355  if (dtPeriod2Start != dtPeriod2End)
356  {
357  auto delta = std::chrono::seconds(dtCurrent.secsTo(dtPeriod2Start));
358  if (delta >= 0s && delta <= 15min)
359  {
360  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
361  QObject::tr("About to start daily wakeup period (2)",
362  "mythshutdown") + "\n");
363  res |= 128;
364  }
365  }
366 
367  if (isRunning("mythtv-setup"))
368  {
369  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
370  QObject::tr("Setup is running...", "mythshutdown") + "\n");
371  res = 255;
372  }
373 
374  LOG(VB_GENERAL, LOG_INFO,
375  QObject::tr("Mythshutdown: --status returned: %1",
376  "mythshutdown").arg(res) + "\n");
377 
378  return res;
379 }
380 
381 static int checkOKShutdown(bool bWantRecStatus)
382 {
383  // mythbackend wants 0=ok to shutdown,
384  // 1=reset idle count, 2=wait for frontend
385 
386  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --check");
387 
388  int res = getStatus(bWantRecStatus);
389 
390  if (res > 0)
391  {
392  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
393  QObject::tr("Not OK to shutdown", "mythshutdown") + "\n");
394  res = 1;
395  }
396  else
397  {
398  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
399  QObject::tr("OK to shutdown", "mythshutdown") + "\n");
400  res = 0;
401  }
402 
403  LOG(VB_GENERAL, LOG_INFO,
404  QString("Mythshutdown: --check returned: %1").arg(res));
405 
406  return res;
407 }
408 
409 static void setWakeupTime(const QDateTime &wakeupTime)
410 {
411  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --setwakeup");
412 
413  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
414  QObject::tr("Wakeup time given is: %1 (local time)", "mythshutdown")
415  .arg(MythDate::toString(wakeupTime, MythDate::kDateTimeShort)) + "\n");
416 
417  setGlobalSetting("MythShutdownNextScheduled",
419 }
420 
422 {
424  {
425  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
426  QObject::tr("Setting scheduled wakeup time: "
427  "Attempting to connect to master server...",
428  "mythshutdown") + "\n");
429  if (!gCoreContext->ConnectToMasterServer(false))
430  {
431  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
432  QObject::tr("Setting scheduled wakeup time: "
433  "Could not connect to master server!",
434  "mythshutdown") + "\n");
435  return 1;
436  }
437  }
438 
439  QDateTime nextRecordingStart;
440  GetNextRecordingList(nextRecordingStart);
441 
442  // set the wakeup time for the next scheduled recording
443  if (!nextRecordingStart.isNull())
444  {
445  int m_preRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll");
446  QDateTime restarttime = nextRecordingStart
447  .addSecs((-1LL) * m_preRollSeconds);
448 
449  int add = gCoreContext->GetNumSetting(
450  "StartupSecsBeforeRecording", 240);
451 
452  if (add)
453  restarttime = restarttime.addSecs((-1LL) * add);
454 
455  setWakeupTime(restarttime);
456 
457  return 0;
458  }
459  return 1;
460 }
461 
462 static int shutdown()
463 {
464  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --shutdown");
465 
466  // get next daily wakeup times if any are set
467  QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1");
468  QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1");
469  QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2");
470  QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2");
471  QDateTime dtCurrent = MythDate::current();
472  QDateTime dtNextDailyWakeup = QDateTime();
473 
474  // Make sure Period1 is before Period2
475  if (dtPeriod2Start < dtPeriod1Start)
476  {
477  QDateTime temp = dtPeriod1Start;
478  dtPeriod1Start = dtPeriod2Start;
479  dtPeriod2Start = temp;
480  temp = dtPeriod1End;
481  dtPeriod1End = dtPeriod2End;
482  dtPeriod2End = temp;
483  }
484 
485  // Check for time periods that cross midnight
486  if (dtPeriod1End < dtPeriod1Start)
487  {
488  if (dtCurrent > dtPeriod1End)
489  dtPeriod1End = dtPeriod1End.addDays(1);
490  else
491  dtPeriod1Start = dtPeriod1Start.addDays(-1);
492  }
493 
494  if (dtPeriod2End < dtPeriod2Start)
495  {
496  if (dtCurrent > dtPeriod2End)
497  dtPeriod2End = dtPeriod2End.addDays(1);
498  else
499  dtPeriod2Start = dtPeriod2Start.addDays(-1);
500  }
501 
502  // have we passed the first wakeup time today
503  if (dtPeriod1Start != dtPeriod1End)
504  {
505  if (dtCurrent < dtPeriod1Start)
506  {
507  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
508  QObject::tr("Daily wakeup today at %1", "mythshutdown")
509  .arg(MythDate::toString(dtPeriod1Start, MythDate::kTime)) +
510  "\n");
511  dtNextDailyWakeup = dtPeriod1Start;
512  }
513  }
514 
515  // have we passed the second wakeup time today
516  if (!dtNextDailyWakeup.isValid() && dtPeriod2Start != dtPeriod2End)
517  {
518  if (dtCurrent < dtPeriod2Start)
519  {
520  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
521  QObject::tr("Daily wakeup today at %1", "mythshutdown")
522  .arg(MythDate::toString(dtPeriod2Start, MythDate::kTime)) +
523  "\n");
524  dtNextDailyWakeup = dtPeriod2Start;
525  }
526  }
527 
528  // if we have at least one valid daily wakeup time
529  // and dtNextDailyWakeup is still not valid
530  // then next daily wakeup is tomorrow
531  if (!dtNextDailyWakeup.isValid())
532  {
533  if (dtPeriod1Start != dtPeriod1End)
534  dtNextDailyWakeup = dtPeriod1Start;
535  else if (dtPeriod2Start != dtPeriod2End)
536  dtNextDailyWakeup = dtPeriod2Start;
537 
538  if (dtNextDailyWakeup.isValid())
539  {
540  dtNextDailyWakeup = dtNextDailyWakeup.addDays(1);
541 
542  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
543  QObject::tr("Next daily wakeup is tomorrow at %1",
544  "mythshutdown")
545  .arg(MythDate::toString(dtNextDailyWakeup, MythDate::kTime)) +
546  "\n");
547  }
548  }
549 
550  // if dtNextDailyWakeup is still not valid then no daily wakeups are set
551  if (!dtNextDailyWakeup.isValid())
552  {
553  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
554  QObject::tr("Error: no daily wakeup times are set",
555  "mythshutdown") + "\n");
556  }
557 
558  // get next scheduled wake up for a recording if any
559  QDateTime dtNextRecordingStart = QDateTime();
560  QString s = getGlobalSetting("MythShutdownNextScheduled", "");
561  if (!s.isEmpty())
562  dtNextRecordingStart = MythDate::fromString(s);
563 
564  if (!dtNextRecordingStart.isValid())
565  {
566  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
567  QObject::tr("Error: no recording time is set", "mythshutdown") +
568  "\n");
569  }
570  else
571  {
572  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
573  QObject::tr("Recording scheduled at: %1", "mythshutdown")
574  .arg(MythDate::toString(dtNextRecordingStart, MythDate::kTime)) +
575  "\n");
576  }
577 
578  // check if scheduled recording time has already passed
579  if (dtNextRecordingStart.isValid())
580  {
581  int delta = dtCurrent.secsTo(dtNextRecordingStart);
582 
583  if (delta < 0)
584  {
585  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
586  QObject::tr("Scheduled recording time has already passed. "
587  "Schedule deleted", "mythshutdown") + "\n");
588 
589  dtNextRecordingStart = QDateTime();
590  setGlobalSetting("MythShutdownNextScheduled", "");
591  }
592  }
593 
594  QDateTime dtWakeupTime = QDateTime();
595 
596  // simple case
597  // no daily wakeup set
598  // no scheduled program set
599  // just shut down
600  if (!dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid())
601  {
602  dtWakeupTime = QDateTime();
603  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
604  QObject::tr("Error: no wake up time set and no scheduled program",
605  "mythshutdown") + "\n");
606  }
607 
608  // no daily wakeup set
609  // scheduled program is set
610  if (dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid())
611  {
612  dtWakeupTime = dtNextRecordingStart;
613  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
614  QObject::tr("Will wake up at next scheduled program",
615  "mythshutdown") + "\n");
616  }
617 
618  // daily wakeup is set
619  // no scheduled program is set
620  if (!dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid())
621  {
622  dtWakeupTime = dtNextDailyWakeup;
623  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
624  QObject::tr("Will wake up at next daily wakeup",
625  "mythshutdown") + "\n");
626  }
627 
628  // daily wakeup is set
629  // scheduled program is set
630  // wake up at which ever is the earliest
631  if (dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid())
632  {
633  if (dtNextDailyWakeup < dtNextRecordingStart)
634  {
635  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
636  QObject::tr("Program is scheduled but will "
637  "wake up at next daily wakeup",
638  "mythshutdown") + "\n");
639  dtWakeupTime = dtNextDailyWakeup;
640  }
641  else
642  {
643  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
644  QObject::tr("Daily wakeup is set but will wake up "
645  "at next scheduled program",
646  "mythshutdown") + "\n");
647  dtWakeupTime = dtNextRecordingStart;
648  }
649  }
650 
651  // save the next wakuptime in the db
652  setGlobalSetting("MythShutdownWakeupTime",
653  MythDate::toString(dtWakeupTime, MythDate::kDatabase));
654 
655  // stop here to debug
656  //return 0;
657 
658  int shutdownmode = 0; // default to poweroff no reboot
659  QString nvramRestartCmd =
660  gCoreContext->GetSetting("MythShutdownNvramRestartCmd", "");
661 
662  if (dtWakeupTime.isValid())
663  {
664  // dont't shutdown if we are within idleWait mins of the next wakeup time
665  std::chrono::seconds idleWaitForRecordingTime =
666  gCoreContext->GetDurSetting<std::chrono::minutes>("idleWaitForRecordingTime", 15min);
667  if (dtCurrent.secsTo(dtWakeupTime) > idleWaitForRecordingTime.count())
668  {
669  QString nvramCommand =
671  "MythShutdownNvramCmd",
672  "/usr/bin/nvram-wakeup --settime $time");
673 
674  QString wakeup_timeformat = gCoreContext->GetSetting(
675  "MythShutdownWakeupTimeFmt", "time_t");
676 
677  if (wakeup_timeformat == "time_t")
678  {
679  QString time_ts;
680  nvramCommand.replace(
681  "$time", time_ts.setNum(dtWakeupTime.toSecsSinceEpoch())
682  );
683  }
684  else
685  {
686  nvramCommand.replace(
687  "$time", dtWakeupTime.toLocalTime()
688  .toString(wakeup_timeformat));
689  }
690 
691  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
692  QObject::tr("Sending command to set time in BIOS %1",
693  "mythshutdown")
694  .arg(nvramCommand) + "\n");
695 
696  shutdownmode = myth_system(nvramCommand);
697 
698  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
699  QObject::tr("Program %1 exited with code %2", "mythshutdown")
700  .arg(nvramCommand).arg(shutdownmode) + "\n");
701 
702  if (shutdownmode == 2)
703  {
704  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
705  QObject::tr("Error: nvram-wakeup failed to "
706  "set time in BIOS", "mythshutdown") + "\n");
707  return 1;
708  }
709 
710  // we don't trust the return code from nvram-wakeup so only reboot
711  // if the user has set a restart command
712  if (nvramRestartCmd.isEmpty())
713  shutdownmode = 0;
714  else
715  shutdownmode = 1;
716  }
717  else
718  {
719  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
720  QObject::tr("The next wakeup time is less than "
721  "15 mins away, not shutting down.",
722  "mythshutdown") + "\n");
723  return 0;
724  }
725  }
726 
727  int res = 0;
728 
729  switch (shutdownmode)
730  {
731  case 0:
732  {
733  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
734  QObject::tr("everything looks fine, shutting down ...",
735  "mythshutdown") + "\n");
736  QString poweroffCmd = gCoreContext->GetSetting(
737  "MythShutdownPoweroff", "/sbin/poweroff");
738  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
739  "..\n.\n" + QObject::tr("shutting down", "mythshutdown") +
740  " ...\n");
741 
742  myth_system(poweroffCmd);
743  res = 0;
744  break;
745  }
746  case 1:
747  {
748  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
749  QObject::tr("Everything looks fine, but reboot is needed",
750  "mythshutdown") + "\n");
751  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
752  QObject::tr("Sending command to bootloader", "mythshutdown") +
753  " ...\n");
754  LOG(VB_STDIO|VB_FLUSH, LOG_ERR, nvramRestartCmd);
755 
756  myth_system(nvramRestartCmd);
757 
758  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
759  "..\n.\n" + QObject::tr("rebooting", "mythshutdown") +
760  " ...\n");
761 
762  QString rebootCmd =
763  gCoreContext->GetSetting("MythShutdownReboot", "/sbin/reboot");
764  myth_system(rebootCmd);
765  res = 0;
766  break;
767  }
768  default:
769  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
770  QObject::tr("Error: Invalid shutdown mode, doing nothing.",
771  "mythshutdown") + "\n");
772  res = 1;
773  break;
774  }
775 
776  return res;
777 }
778 
779 static int startup()
780 {
781  LOG(VB_GENERAL, LOG_INFO, "Mythshutdown: --startup");
782 
783  int res = 0;
784  QDateTime startupTime = QDateTime();
785  QString s = getGlobalSetting("MythshutdownWakeupTime", "");
786  if (!s.isEmpty())
787  startupTime = MythDate::fromString(s);
788 
789  // if we don't have a valid startup time assume we were started manually
790  if (!startupTime.isValid())
791  res = 1;
792  else
793  {
794  // if we started within 15mins of the saved wakeup time assume we started
795  // automatically to record or for a daily wakeup/shutdown period
796  auto delta = MythDate::secsInPast(startupTime);
797  delta = std::chrono::abs(delta);
798 
799  if (delta < 15min)
800  res = 0;
801  else
802  res = 1;
803  }
804 
805  if (res)
806  {
807  LOG(VB_GENERAL, LOG_INFO,
808  QString("looks like we were started manually: %1").arg(res));
809  }
810  else
811  {
812  LOG(VB_GENERAL, LOG_INFO,
813  QString("looks like we were started automatically: %1").arg(res));
814  }
815 
816 
817  LOG(VB_GENERAL, LOG_INFO,
818  QString("Mythshutdown: --startup returned: %1").arg(res));
819 
820  return res;
821 }
822 
823 int main(int argc, char **argv)
824 {
826  if (!cmdline.Parse(argc, argv))
827  {
828  cmdline.PrintHelp();
830  }
831 
832  if (cmdline.toBool("showhelp"))
833  {
834  cmdline.PrintHelp();
835  return GENERIC_EXIT_OK;
836  }
837 
838  if (cmdline.toBool("showversion"))
839  {
841  return GENERIC_EXIT_OK;
842  }
843 
844  QCoreApplication a(argc, argv);
845  QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHSHUTDOWN);
846 
847  int retval = cmdline.ConfigureLogging("none");
848  if (retval != GENERIC_EXIT_OK)
849  return retval;
850 
851 #ifndef _WIN32
853 #endif
854 
855  gContext = new MythContext(MYTH_BINARY_VERSION);
856  if (!gContext->Init(false))
857  {
858  LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Error: "
859  "Could not initialize MythContext. Exiting.\n");
862  }
863 
864  int res = 0;
865 
866  if (cmdline.toBool("lock"))
867  res = lockShutdown();
868  else if (cmdline.toBool("unlock"))
869  res = unlockShutdown();
870  else if (cmdline.toBool("check"))
871  res = checkOKShutdown(cmdline.toInt("check") == 1);
872  else if (cmdline.toBool("setschedwakeup"))
873  res = setScheduledWakeupTime();
874  else if (cmdline.toBool("startup"))
875  res = startup();
876  else if (cmdline.toBool("shutdown"))
877  res = shutdown();
878  else if (cmdline.toBool("status"))
879  res = getStatus(cmdline.toInt("status") == 1);
880  else if (cmdline.toBool("setwakeup"))
881  {
882  // only one of --utc or --localtime can be passed per
883  // CommandLineArg::AllowOneOf() in commandlineparser.cpp
884  bool utc = cmdline.toBool("utc");
885  QString tmp = cmdline.toString("setwakeup");
886 
887  QDateTime wakeuptime = (utc) ?
890 
891  if (!wakeuptime.isValid())
892  {
893  LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
894  QObject::tr("Error: "
895  "--setwakeup invalid date format (%1)\n\t\t\t"
896  "must be yyyy-MM-ddThh:mm:ss", "mythshutdown")
897  .arg(tmp) + "\n");
898  res = 1;
899  }
900  else
901  {
902  setWakeupTime(wakeuptime);
903  }
904  }
905  else if (cmdline.toBool("safeshutdown"))
906  {
907  res = checkOKShutdown(true);
908  if (res == 0)
909  {
910  // Nothing to stop a shutdown (eg. recording in progress).
912  res = shutdown();
913  }
914 
915  }
916  else
917  {
918  cmdline.PrintHelp();
919  }
920 
921  delete gContext;
922 
924 
925  return res;
926 }
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1525
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
tv.h
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
mythdb.h
shutdown
static int shutdown()
Definition: mythshutdown.cpp:462
cmdline
MythCommFlagCommandLineParser cmdline
Definition: mythcommflag.cpp:72
MythCoreContext::ConnectToMasterServer
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
Definition: mythcorecontext.cpp:357
setWakeupTime
static void setWakeupTime(const QDateTime &wakeupTime)
Definition: mythshutdown.cpp:409
MythContext
Startup context for MythTV.
Definition: mythcontext.h:43
setGlobalSetting
static void setGlobalSetting(const QString &key, const QString &v)
Definition: mythshutdown.cpp:32
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
myth_system
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
Definition: mythsystemlegacy.cpp:506
remoteutil.h
MythDate::kDateTimeShort
@ kDateTimeShort
Default local time.
Definition: mythdate.h:24
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
lockShutdown
static int lockShutdown()
Definition: mythshutdown.cpp:84
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
mythsystemlegacy.h
MythCoreContext::IsConnectedToMaster
bool IsConnectedToMaster(void)
Definition: mythcorecontext.cpp:594
main
int main(int argc, char **argv)
Definition: mythshutdown.cpp:823
MythCommandLineParser::Parse
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
Definition: mythcommandlineparser.cpp:1552
mythdate.h
unlockShutdown
static int unlockShutdown()
Definition: mythshutdown.cpp:138
programinfo.h
getStatus
static int getStatus(bool bWantRecStatus)
Definition: mythshutdown.cpp:245
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
mythlogging.h
signalhandling.h
RemoteGetRecordingStatus
int RemoteGetRecordingStatus(const ProgramInfo *pginfo, int overrecsecs, int underrecsecs)
Get status of an individual programme (with pre-post roll?).
Definition: remoteutil.cpp:505
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
compat.h
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:168
getDailyWakeupTime
static QDateTime getDailyWakeupTime(const QString &sPeriod)
Definition: mythshutdown.cpp:214
MYTH_APPNAME_MYTHSHUTDOWN
static constexpr const char * MYTH_APPNAME_MYTHSHUTDOWN
Definition: mythcorecontext.h:29
isRunning
static bool isRunning(const char *program)
Returns true if a program containing the specified string is running on this machine.
Definition: mythshutdown.cpp:208
MythCommandLineParser::PrintVersion
static void PrintVersion(void)
Print application version information.
Definition: mythcommandlineparser.cpp:1380
isRecording
static bool isRecording()
Definition: mythshutdown.cpp:227
MythCommandLineParser::PrintHelp
void PrintHelp(void) const
Print command line option help.
Definition: mythcommandlineparser.cpp:1396
jobqueue.h
JobQueue::HasRunningOrPendingJobs
static bool HasRunningOrPendingJobs(std::chrono::minutes startingWithinMins=0min)
Definition: jobqueue.cpp:1229
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:137
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
setScheduledWakeupTime
static int setScheduledWakeupTime()
Definition: mythshutdown.cpp:421
tvremoteutil.h
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
SignalHandler::Init
static void Init(QObject *parent=nullptr)
Definition: signalhandling.cpp:128
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:212
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2354
getGlobalSetting
static QString getGlobalSetting(const QString &key, const QString &defaultval)
Definition: mythshutdown.cpp:61
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2197
GetNextRecordingList
bool GetNextRecordingList(QDateTime &nextRecordingStart, bool *hasConflicts, std::vector< ProgramInfo > *list)
Definition: programinfo.cpp:6383
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
mythcontext.h
mythshutdown_commandlineparser.h
MythDate::kDatabase
@ kDatabase
Default UTC, database format.
Definition: mythdate.h:27
MythShutdownCommandLineParser
Definition: mythshutdown_commandlineparser.h:6
MythCommandLineParser::ConfigureLogging
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
Definition: mythcommandlineparser.cpp:2870
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
startup
static int startup()
Definition: mythshutdown.cpp:779
exitcodes.h
MythCommandLineParser::toInt
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2219
idleWaitForRecordingTime
static GlobalSpinBoxSetting * idleWaitForRecordingTime()
Definition: backendsettings.cpp:534
gContext
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:64
MythContext::Init
bool Init(bool gui=true, bool promptForBackend=false, bool disableAutoDiscovery=false, bool ignoreDB=false)
Definition: mythcontext.cpp:1608
checkOKShutdown
static int checkOKShutdown(bool bWantRecStatus)
Definition: mythshutdown.cpp:381
SignalHandler::Done
static void Done(void)
Definition: signalhandling.cpp:135
GENERIC_EXIT_NO_MYTHCONTEXT
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:16
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837