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