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