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