9#include <QCoreApplication>
23#include "libmythbase/mythversion.h"
34 QString value = (v.isNull()) ? QString(
"") : v;
39 query.
prepare(
"DELETE FROM settings WHERE value = :KEY;");
45 query.
prepare(
"INSERT INTO settings ( value, data ) "
46 "VALUES ( :VALUE, :DATA );");
55 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
56 QString(
"Error: Database not open while trying "
57 "to save setting: %1\n").arg(key));
63 QString value = defaultval;
68 query.
prepare(
"SELECT data FROM settings WHERE value = :KEY AND "
72 value = query.
value(0).toString();
76 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
77 QObject::tr(
"Error: Database not open while trying to "
78 "load setting: %1",
"mythshutdown").arg(key) +
"\n");
86 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --lock");
92 while (!query.
exec(
"LOCK TABLE settings WRITE;") && tries < 5)
94 LOG(VB_GENERAL, LOG_INFO,
"Waiting for lock on setting table");
101 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
102 QObject::tr(
"Error: Waited too long to obtain "
103 "lock on setting table",
"mythshutdown") +
"\n");
108 query.
prepare(
"SELECT * FROM settings "
109 "WHERE value = 'MythShutdownLock' AND hostname IS NULL;");
113 if (query.
size() < 1)
116 query.
prepare(
"INSERT INTO settings (value, data) "
117 "VALUES ('MythShutdownLock', '1');");
124 query.
prepare(
"UPDATE settings SET data = data + 1 "
125 "WHERE value = 'MythShutdownLock' "
126 "AND hostname IS NULL;");
132 if (!query.
exec(
"UNLOCK TABLES;"))
140 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --unlock");
146 while (!query.
exec(
"LOCK TABLE settings WRITE;") && tries < 5)
148 LOG(VB_GENERAL, LOG_INFO,
"Waiting for lock on setting table");
155 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
156 QObject::tr(
"Error: Waited too long to obtain "
157 "lock on setting table",
"mythshutdown") +
"\n");
162 query.
prepare(
"SELECT * FROM settings "
163 "WHERE value = 'MythShutdownLock' AND hostname IS NULL;");
167 if (query.
size() < 1)
170 query.
prepare(
"INSERT INTO settings (value, data) "
171 "VALUES ('MythShutdownLock', '0');");
178 query.
prepare(
"UPDATE settings SET data = GREATEST(0, data - 1) "
179 "WHERE value = 'MythShutdownLock' "
180 "AND hostname IS NULL;");
186 if (!query.
exec(
"UNLOCK TABLES;"))
210 QString command = QString(
"ps ch -C %1 -o pid > /dev/null").arg(program);
218#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
220 tTime, Qt::LocalTime).toUTC();
223 tTime, QTimeZone(QTimeZone::LocalTime)).toUTC();
231 LOG(VB_GENERAL, LOG_INFO,
232 "isRecording: Attempting to connect to master server...");
235 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
236 QObject::tr(
"Error: Could not connect to master server",
237 "mythshutdown") +
"\n");
247 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --status");
253 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
254 QObject::tr(
"Transcoding in progress...",
"mythshutdown") +
"\n");
260 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
261 QObject::tr(
"Commercial Detection in progress...",
262 "mythshutdown") +
"\n");
268 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
269 QObject::tr(
"Grabbing EPG data in progress...",
"mythshutdown") +
276 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
277 QObject::tr(
"Recording in progress...",
"mythshutdown") +
"\n");
283 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
284 QObject::tr(
"Shutdown is locked",
"mythshutdown") +
"\n");
290 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
291 QObject::tr(
"Has queued or pending jobs",
"mythshutdown") +
"\n");
302 if (dtPeriod1End < dtPeriod1Start)
304 if (dtCurrent > dtPeriod1End)
305 dtPeriod1End = dtPeriod1End.addDays(1);
307 dtPeriod1Start = dtPeriod1Start.addDays(-1);
310 if (dtPeriod2End < dtPeriod2Start)
312 if (dtCurrent > dtPeriod2End)
313 dtPeriod2End = dtPeriod2End.addDays(1);
315 dtPeriod2Start = dtPeriod2Start.addDays(-1);
319 if (dtPeriod1Start != dtPeriod1End)
321 if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End)
323 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
324 QObject::tr(
"In a daily wakeup period (1).",
"mythshutdown") +
330 if (dtPeriod2Start != dtPeriod2End)
332 if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End)
334 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
335 QObject::tr(
"In a daily wakeup period (2).",
"mythshutdown") +
343 if (dtPeriod1Start != dtPeriod1End)
345 auto delta = std::chrono::seconds(dtCurrent.secsTo(dtPeriod1Start));
346 if (delta >= 0s && delta <= 15min)
348 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
349 QObject::tr(
"About to start daily wakeup period (1)",
350 "mythshutdown") +
"\n");
355 if (dtPeriod2Start != dtPeriod2End)
357 auto delta = std::chrono::seconds(dtCurrent.secsTo(dtPeriod2Start));
358 if (delta >= 0s && delta <= 15min)
360 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
361 QObject::tr(
"About to start daily wakeup period (2)",
362 "mythshutdown") +
"\n");
369 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
370 QObject::tr(
"Setup is running...",
"mythshutdown") +
"\n");
374 LOG(VB_GENERAL, LOG_INFO,
375 QObject::tr(
"Mythshutdown: --status returned: %1",
376 "mythshutdown").arg(res) +
"\n");
386 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --check");
392 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
393 QObject::tr(
"Not OK to shutdown",
"mythshutdown") +
"\n");
398 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
399 QObject::tr(
"OK to shutdown",
"mythshutdown") +
"\n");
403 LOG(VB_GENERAL, LOG_INFO,
404 QString(
"Mythshutdown: --check returned: %1").arg(res));
411 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --setwakeup");
413 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
414 QObject::tr(
"Wakeup time given is: %1 (local time)",
"mythshutdown")
425 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
426 QObject::tr(
"Setting scheduled wakeup time: "
427 "Attempting to connect to master server...",
428 "mythshutdown") +
"\n");
431 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
432 QObject::tr(
"Setting scheduled wakeup time: "
433 "Could not connect to master server!",
434 "mythshutdown") +
"\n");
439 QDateTime nextRecordingStart;
443 if (!nextRecordingStart.isNull())
446 QDateTime restarttime = nextRecordingStart
447 .addSecs((-1LL) * m_preRollSeconds);
450 "StartupSecsBeforeRecording", 240);
453 restarttime = restarttime.addSecs((-1LL) * add);
464 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --shutdown");
472 QDateTime dtNextDailyWakeup = QDateTime();
475 if (dtPeriod2Start < dtPeriod1Start)
477 QDateTime temp = dtPeriod1Start;
478 dtPeriod1Start = dtPeriod2Start;
479 dtPeriod2Start = temp;
481 dtPeriod1End = dtPeriod2End;
486 if (dtPeriod1End < dtPeriod1Start)
488 if (dtCurrent > dtPeriod1End)
489 dtPeriod1End = dtPeriod1End.addDays(1);
491 dtPeriod1Start = dtPeriod1Start.addDays(-1);
494 if (dtPeriod2End < dtPeriod2Start)
496 if (dtCurrent > dtPeriod2End)
497 dtPeriod2End = dtPeriod2End.addDays(1);
499 dtPeriod2Start = dtPeriod2Start.addDays(-1);
503 if (dtPeriod1Start != dtPeriod1End)
505 if (dtCurrent < dtPeriod1Start)
507 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
508 QObject::tr(
"Daily wakeup today at %1",
"mythshutdown")
511 dtNextDailyWakeup = dtPeriod1Start;
516 if (!dtNextDailyWakeup.isValid() && dtPeriod2Start != dtPeriod2End)
518 if (dtCurrent < dtPeriod2Start)
520 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
521 QObject::tr(
"Daily wakeup today at %1",
"mythshutdown")
524 dtNextDailyWakeup = dtPeriod2Start;
531 if (!dtNextDailyWakeup.isValid())
533 if (dtPeriod1Start != dtPeriod1End)
534 dtNextDailyWakeup = dtPeriod1Start;
535 else if (dtPeriod2Start != dtPeriod2End)
536 dtNextDailyWakeup = dtPeriod2Start;
538 if (dtNextDailyWakeup.isValid())
540 dtNextDailyWakeup = dtNextDailyWakeup.addDays(1);
542 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
543 QObject::tr(
"Next daily wakeup is tomorrow at %1",
551 if (!dtNextDailyWakeup.isValid())
553 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
554 QObject::tr(
"Error: no daily wakeup times are set",
555 "mythshutdown") +
"\n");
559 QDateTime dtNextRecordingStart = QDateTime();
564 if (!dtNextRecordingStart.isValid())
566 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
567 QObject::tr(
"Error: no recording time is set",
"mythshutdown") +
572 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
573 QObject::tr(
"Recording scheduled at: %1",
"mythshutdown")
579 if (dtNextRecordingStart.isValid())
581 int delta = dtCurrent.secsTo(dtNextRecordingStart);
585 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
586 QObject::tr(
"Scheduled recording time has already passed. "
587 "Schedule deleted",
"mythshutdown") +
"\n");
589 dtNextRecordingStart = QDateTime();
594 QDateTime dtWakeupTime = QDateTime();
600 if (!dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid())
602 dtWakeupTime = QDateTime();
603 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
604 QObject::tr(
"Error: no wake up time set and no scheduled program",
605 "mythshutdown") +
"\n");
610 if (dtNextRecordingStart.isValid() && !dtNextDailyWakeup.isValid())
612 dtWakeupTime = dtNextRecordingStart;
613 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
614 QObject::tr(
"Will wake up at next scheduled program",
615 "mythshutdown") +
"\n");
620 if (!dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid())
622 dtWakeupTime = dtNextDailyWakeup;
623 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
624 QObject::tr(
"Will wake up at next daily wakeup",
625 "mythshutdown") +
"\n");
631 if (dtNextRecordingStart.isValid() && dtNextDailyWakeup.isValid())
633 if (dtNextDailyWakeup < dtNextRecordingStart)
635 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
636 QObject::tr(
"Program is scheduled but will "
637 "wake up at next daily wakeup",
638 "mythshutdown") +
"\n");
639 dtWakeupTime = dtNextDailyWakeup;
643 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
644 QObject::tr(
"Daily wakeup is set but will wake up "
645 "at next scheduled program",
646 "mythshutdown") +
"\n");
647 dtWakeupTime = dtNextRecordingStart;
658 int shutdownmode = 0;
659 QString nvramRestartCmd =
662 if (dtWakeupTime.isValid())
669 QString nvramCommand =
671 "MythShutdownNvramCmd",
672 "/usr/bin/nvram-wakeup --settime $time");
675 "MythShutdownWakeupTimeFmt",
"time_t");
677 if (wakeup_timeformat ==
"time_t")
680 nvramCommand.replace(
681 "$time", time_ts.setNum(dtWakeupTime.toSecsSinceEpoch())
686 nvramCommand.replace(
687 "$time", dtWakeupTime.toLocalTime()
688 .toString(wakeup_timeformat));
691 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
692 QObject::tr(
"Sending command to set time in BIOS %1",
694 .arg(nvramCommand) +
"\n");
698 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
699 QObject::tr(
"Program %1 exited with code %2",
"mythshutdown")
700 .arg(nvramCommand).arg(shutdownmode) +
"\n");
702 if (shutdownmode == 2)
704 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
705 QObject::tr(
"Error: nvram-wakeup failed to "
706 "set time in BIOS",
"mythshutdown") +
"\n");
712 if (nvramRestartCmd.isEmpty())
719 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
720 QObject::tr(
"The next wakeup time is less than "
721 "15 mins away, not shutting down.",
722 "mythshutdown") +
"\n");
729 switch (shutdownmode)
733 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
734 QObject::tr(
"everything looks fine, shutting down ...",
735 "mythshutdown") +
"\n");
737 "MythShutdownPoweroff",
"/sbin/poweroff");
738 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
739 "..\n.\n" + QObject::tr(
"shutting down",
"mythshutdown") +
748 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
749 QObject::tr(
"Everything looks fine, but reboot is needed",
750 "mythshutdown") +
"\n");
751 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
752 QObject::tr(
"Sending command to bootloader",
"mythshutdown") +
754 LOG(VB_STDIO|VB_FLUSH, LOG_ERR, nvramRestartCmd);
758 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
759 "..\n.\n" + QObject::tr(
"rebooting",
"mythshutdown") +
769 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
770 QObject::tr(
"Error: Invalid shutdown mode, doing nothing.",
771 "mythshutdown") +
"\n");
781 LOG(VB_GENERAL, LOG_INFO,
"Mythshutdown: --startup");
784 QDateTime startupTime = QDateTime();
790 if (!startupTime.isValid())
797 delta = std::chrono::abs(delta);
807 LOG(VB_GENERAL, LOG_INFO,
808 QString(
"looks like we were started manually: %1").arg(res));
812 LOG(VB_GENERAL, LOG_INFO,
813 QString(
"looks like we were started automatically: %1").arg(res));
817 LOG(VB_GENERAL, LOG_INFO,
818 QString(
"Mythshutdown: --startup returned: %1").arg(res));
844 QCoreApplication a(argc, argv);
852 if (!context.Init(
false))
854 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
"Error: "
855 "Could not initialize MythContext. Exiting.\n");
882 QDateTime wakeuptime = (utc) ?
886 if (!wakeuptime.isValid())
888 LOG(VB_STDIO|VB_FLUSH, LOG_ERR,
889 QObject::tr(
"Error: "
890 "--setwakeup invalid date format (%1)\n\t\t\t"
891 "must be yyyy-MM-ddThh:mm:ss",
"mythshutdown")
static GlobalSpinBoxSetting * idleWaitForRecordingTime()
static bool HasRunningOrPendingJobs(std::chrono::minutes startingWithinMins=0min)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool isActive(void) const
bool isConnected(void) const
Only updated once during object creation.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
void PrintHelp(void) const
Print command line option help.
Startup context for MythTV.
bool IsConnectedToMaster(void)
QString GetSetting(const QString &key, const QString &defaultval="")
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
void SendMessage(const QString &message)
int GetNumSetting(const QString &key, int defaultval=0)
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
static void DBError(const QString &where, const MSqlQuery &query)
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
static constexpr const char * MYTH_APPNAME_MYTHSHUTDOWN
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static bool isRecording()
static int checkOKShutdown(bool bWantRecStatus)
static int setScheduledWakeupTime()
static void setGlobalSetting(const QString &key, const QString &v)
int main(int argc, char **argv)
static int getStatus(bool bWantRecStatus)
static void setWakeupTime(const QDateTime &wakeupTime)
static bool isRunning(const char *program)
Returns true if a program containing the specified string is running on this machine.
static int lockShutdown()
static QString getGlobalSetting(const QString &key, const QString &defaultval)
static int unlockShutdown()
static QDateTime getDailyWakeupTime(const QString &sPeriod)
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
std::chrono::seconds secsInPast(const QDateTime &past)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
@ kDateTimeShort
Default local time.
@ kTime
Default local time.
@ kDatabase
Default UTC, database format.
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
MythCommFlagCommandLineParser cmdline
bool GetNextRecordingList(QDateTime &nextRecordingStart, bool *hasConflicts, std::vector< ProgramInfo > *list)
bool RemoteGetRecordingStatus(std::vector< TunerStatus > *tunerList, bool list_inactive)