void print_warnings(const MythBackendCommandLineParser &cmdline) { if (cmdline.toBool("nohousekeeper")) { LOG(VB_GENERAL, LOG_WARNING, LOC + "****** The Housekeeper has been DISABLED with " "the --nohousekeeper option ******"); } if (cmdline.toBool("nosched")) { LOG(VB_GENERAL, LOG_WARNING, LOC + "********** The Scheduler has been DISABLED with " "the --nosched option **********"); } if (cmdline.toBool("noautoexpire")) { LOG(VB_GENERAL, LOG_WARNING, LOC + "********* Auto-Expire has been DISABLED with " "the --noautoexpire option ********"); } if (cmdline.toBool("nojobqueue")) { LOG(VB_GENERAL, LOG_WARNING, LOC + "********* The JobQueue has been DISABLED with " "the --nojobqueue option *********"); } }
bool setup_context(MythBackendCommandLineParser &cmdline) { if (!gContext->Init(false)) { VERBOSE(VB_IMPORTANT, "Failed to init MythContext."); return false; } if (cmdline.toBool("event") || cmdline.toBool("systemevent") || cmdline.toBool("setverbose") || cmdline.toBool("printsched") || cmdline.toBool("testsched") || cmdline.toBool("resched") || cmdline.toBool("scanvideos") || cmdline.toBool("clearcache") || cmdline.toBool("printexpire")) gCoreContext->SetBackend(false); else gCoreContext->SetBackend(true); QMap<QString,QString> settingsOverride = cmdline.GetSettingsOverride(); if (settingsOverride.size()) { QMap<QString, QString>::iterator it; for (it = settingsOverride.begin(); it != settingsOverride.end(); ++it) { VERBOSE(VB_IMPORTANT, QString("Setting '%1' being forced to '%2'") .arg(it.key()).arg(*it)); gCoreContext->OverrideSettingForSession(it.key(), *it); } } return true; }
int setup_basics(const MythBackendCommandLineParser &cmdline) { ofstream pidfs; if (!openPidfile(pidfs, cmdline.toString("pidfile"))) return GENERIC_EXIT_PERMISSIONS_ERROR; if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to ignore SIGPIPE"); if (cmdline.toBool("daemon") && (daemon(0, 1) < 0)) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to daemonize" + ENO); return GENERIC_EXIT_DAEMONIZING_ERROR; } QString username = cmdline.toString("username"); if (!username.isEmpty() && !setUser(username)) return GENERIC_EXIT_PERMISSIONS_ERROR; if (pidfs) { pidfs << getpid() << endl; pidfs.close(); } return GENERIC_EXIT_OK; }
int main(int argc, char **argv) { MythBackendCommandLineParser cmdline; if (!cmdline.Parse(argc, argv)) { cmdline.PrintHelp(); return GENERIC_EXIT_INVALID_CMDLINE; } if (cmdline.toBool("showhelp")) { cmdline.PrintHelp(); return GENERIC_EXIT_OK; } if (cmdline.toBool("showversion")) { cmdline.PrintVersion(); return GENERIC_EXIT_OK; } #ifndef _WIN32 for (int i = UNUSED_FILENO; i < sysconf(_SC_OPEN_MAX) - 1; ++i) close(i); QCoreApplication a(argc, argv); #else // MINGW application needs a window to receive messages // such as socket notifications :[ QApplication a(argc, argv); #endif QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHBACKEND); pidfile = cmdline.toString("pidfile"); int retval = cmdline.Daemonize(); if (retval != GENERIC_EXIT_OK) return retval; bool daemonize = cmdline.toBool("daemon"); QString mask("general"); if ((retval = cmdline.ConfigureLogging(mask, daemonize)) != GENERIC_EXIT_OK) return retval; if (daemonize) // Don't listen to console input if daemonized close(0); CleanupGuard callCleanup(cleanup); #ifndef _WIN32 QList<int> signallist; signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT; SignalHandler handler(signallist); signal(SIGHUP, SIG_IGN); #endif gContext = new MythContext(MYTH_BINARY_VERSION); if (!gContext->Init(false)) { LOG(VB_GENERAL, LOG_CRIT, "Failed to init MythContext."); return GENERIC_EXIT_NO_MYTHCONTEXT; } setHttpProxy(); cmdline.ApplySettingsOverride(); if (cmdline.toBool("event") || cmdline.toBool("systemevent") || cmdline.toBool("setverbose") || cmdline.toBool("printsched") || cmdline.toBool("testsched") || cmdline.toBool("resched") || cmdline.toBool("scanvideos") || cmdline.toBool("clearcache") || cmdline.toBool("printexpire") || cmdline.toBool("setloglevel")) { gCoreContext->SetBackend(false); return handle_command(cmdline); } gCoreContext->SetBackend(true); retval = run_backend(cmdline); return retval; }
int run_backend(MythBackendCommandLineParser &cmdline) { gBackendContext = new BackendContext(); if (!DBUtil::CheckTimeZoneSupport()) { LOG(VB_GENERAL, LOG_ERR, "MySQL time zone support is missing. " "Please install it and try again. " "See 'mysql_tzinfo_to_sql' for assistance."); return GENERIC_EXIT_DB_NOTIMEZONE; } bool ismaster = gCoreContext->IsMasterHost(); if (!UpgradeTVDatabaseSchema(ismaster, ismaster)) { LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema"); return GENERIC_EXIT_DB_OUTOFDATE; } MythTranslation::load("mythfrontend"); if (!ismaster) { int ret = connect_to_master(); if (ret != GENERIC_EXIT_OK) return ret; } int port = gCoreContext->GetBackendServerPort(); if (gCoreContext->GetBackendServerIP().isEmpty()) { cerr << "No setting found for this machine's BackendServerIP.\n" << "Please run setup on this machine and modify the first page\n" << "of the general settings.\n"; return GENERIC_EXIT_SETUP_ERROR; } MythSystemEventHandler *sysEventHandler = new MythSystemEventHandler(); if (ismaster) { LOG(VB_GENERAL, LOG_NOTICE, LOC + "Starting up as the master server."); } else { LOG(VB_GENERAL, LOG_NOTICE, LOC + "Running as a slave backend."); } print_warnings(cmdline); bool fatal_error = false; bool runsched = setupTVs(ismaster, fatal_error); if (fatal_error) { delete sysEventHandler; return GENERIC_EXIT_SETUP_ERROR; } Scheduler *sched = NULL; if (ismaster) { if (runsched) { sched = new Scheduler(true, &tvList); int err = sched->GetError(); if (err) return err; if (cmdline.toBool("nosched")) sched->DisableScheduling(); } if (!cmdline.toBool("noautoexpire")) { expirer = new AutoExpire(&tvList); if (sched) sched->SetExpirer(expirer); } gCoreContext->SetScheduler(sched); } if (!cmdline.toBool("nohousekeeper")) { housekeeping = new HouseKeeper(); if (ismaster) { housekeeping->RegisterTask(new LogCleanerTask()); housekeeping->RegisterTask(new CleanupTask()); housekeeping->RegisterTask(new ThemeUpdateTask()); housekeeping->RegisterTask(new ArtworkTask()); housekeeping->RegisterTask(new MythFillDatabaseTask()); // only run this task if MythMusic is installed and we have a new enough schema if (gCoreContext->GetNumSetting("MusicDBSchemaVer", 0) >= 1024) housekeeping->RegisterTask(new RadioStreamUpdateTask()); } housekeeping->RegisterTask(new JobQueueRecoverTask()); #ifdef __linux__ #ifdef CONFIG_BINDINGS_PYTHON housekeeping->RegisterTask(new HardwareProfileTask()); #endif #endif housekeeping->Start(); } if (!cmdline.toBool("nojobqueue")) jobqueue = new JobQueue(ismaster); // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- if (g_pUPnp == NULL) { g_pUPnp = new MediaServer(); g_pUPnp->Init(ismaster, cmdline.toBool("noupnp")); } // ---------------------------------------------------------------------- // Setup status server // ---------------------------------------------------------------------- HttpStatus *httpStatus = NULL; HttpServer *pHS = g_pUPnp->GetHttpServer(); if (pHS) { LOG(VB_GENERAL, LOG_INFO, "Main::Registering HttpStatus Extension"); httpStatus = new HttpStatus( &tvList, sched, expirer, ismaster ); pHS->RegisterExtension( httpStatus ); } mainServer = new MainServer( ismaster, port, &tvList, sched, expirer); int exitCode = mainServer->GetExitCode(); if (exitCode != GENERIC_EXIT_OK) { LOG(VB_GENERAL, LOG_CRIT, "Backend exiting, MainServer initialization error."); cleanup(); return exitCode; } if (httpStatus && mainServer) httpStatus->SetMainServer(mainServer); StorageGroup::CheckAllStorageGroupDirs(); if (gCoreContext->IsMasterBackend()) gCoreContext->SendSystemEvent("MASTER_STARTED"); #ifdef USING_SYSTEMD_NOTIFY // Provide systemd ready notification (for type=notify units) (void)sd_notify(0, "READY=1"); #endif /////////////////////////////// /////////////////////////////// exitCode = qApp->exec(); /////////////////////////////// /////////////////////////////// if (gCoreContext->IsMasterBackend()) { gCoreContext->SendSystemEvent("MASTER_SHUTDOWN"); qApp->processEvents(); } LOG(VB_GENERAL, LOG_NOTICE, "MythBackend exiting"); delete sysEventHandler; return exitCode; }
int handle_command(const MythBackendCommandLineParser &cmdline) { QString eventString; if (cmdline.toBool("event")) eventString = cmdline.toString("event"); else if (cmdline.toBool("systemevent")) eventString = "SYSTEM_EVENT " + cmdline.toString("systemevent") + QString(" SENDER %1").arg(gCoreContext->GetHostName()); if (!eventString.isEmpty()) { if (gCoreContext->ConnectToMasterServer()) { gCoreContext->SendMessage(eventString); return GENERIC_EXIT_OK; } return GENERIC_EXIT_NO_MYTHCONTEXT; } if (cmdline.toBool("setverbose")) { if (gCoreContext->ConnectToMasterServer()) { QString message = "SET_VERBOSE "; message += cmdline.toString("setverbose"); gCoreContext->SendMessage(message); LOG(VB_GENERAL, LOG_INFO, QString("Sent '%1' message").arg(message)); return GENERIC_EXIT_OK; } else { LOG(VB_GENERAL, LOG_ERR, "Unable to connect to backend, verbose mask unchanged "); return GENERIC_EXIT_CONNECT_ERROR; } } if (cmdline.toBool("setloglevel")) { if (gCoreContext->ConnectToMasterServer()) { QString message = "SET_LOG_LEVEL "; message += cmdline.toString("setloglevel"); gCoreContext->SendMessage(message); LOG(VB_GENERAL, LOG_INFO, QString("Sent '%1' message").arg(message)); return GENERIC_EXIT_OK; } else { LOG(VB_GENERAL, LOG_ERR, "Unable to connect to backend, log level unchanged "); return GENERIC_EXIT_CONNECT_ERROR; } } if (cmdline.toBool("clearcache")) { if (gCoreContext->ConnectToMasterServer()) { gCoreContext->SendMessage("CLEAR_SETTINGS_CACHE"); LOG(VB_GENERAL, LOG_INFO, "Sent CLEAR_SETTINGS_CACHE message"); return GENERIC_EXIT_OK; } else { LOG(VB_GENERAL, LOG_ERR, "Unable to connect to backend, settings " "cache will not be cleared."); return GENERIC_EXIT_CONNECT_ERROR; } } if (cmdline.toBool("printsched") || cmdline.toBool("testsched")) { Scheduler *sched = new Scheduler(false, &tvList); if (cmdline.toBool("printsched")) { if (!gCoreContext->ConnectToMasterServer()) { LOG(VB_GENERAL, LOG_ERR, "Cannot connect to master"); delete sched; return GENERIC_EXIT_CONNECT_ERROR; } cout << "Retrieving Schedule from Master backend.\n"; sched->FillRecordListFromMaster(); } else { cout << "Calculating Schedule from database.\n" << "Inputs, Card IDs, and Conflict info may be invalid " "if you have multiple tuners.\n"; ProgramInfo::CheckProgramIDAuthorities(); sched->FillRecordListFromDB(); } verboseMask |= VB_SCHEDULE; LogLevel_t oldLogLevel = logLevel; logLevel = LOG_DEBUG; sched->PrintList(true); logLevel = oldLogLevel; delete sched; return GENERIC_EXIT_OK; } if (cmdline.toBool("resched")) { bool ok = false; if (gCoreContext->ConnectToMasterServer()) { LOG(VB_GENERAL, LOG_INFO, "Connected to master for reschedule"); ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(), "MythBackendCommand"); ok = true; } else LOG(VB_GENERAL, LOG_ERR, "Cannot connect to master for reschedule"); return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR; } if (cmdline.toBool("scanvideos")) { bool ok = false; if (gCoreContext->ConnectToMasterServer()) { gCoreContext->SendReceiveStringList(QStringList() << "SCAN_VIDEOS"); LOG(VB_GENERAL, LOG_INFO, "Requested video scan"); ok = true; } else LOG(VB_GENERAL, LOG_ERR, "Cannot connect to master for video scan"); return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR; } if (cmdline.toBool("printexpire")) { expirer = new AutoExpire(); expirer->PrintExpireList(cmdline.toString("printexpire")); return GENERIC_EXIT_OK; } // This should never actually be reached.. return GENERIC_EXIT_OK; }
int run_backend(MythBackendCommandLineParser &cmdline) { bool ismaster = gCoreContext->IsMasterHost(); if (!UpgradeTVDatabaseSchema(ismaster, ismaster)) { LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema"); return GENERIC_EXIT_DB_OUTOFDATE; } MythTranslation::load("mythfrontend"); if (!ismaster) { int ret = connect_to_master(); if (ret != GENERIC_EXIT_OK) return ret; } QString myip = gCoreContext->GetSetting("BackendServerIP"); int port = gCoreContext->GetNumSetting("BackendServerPort", 6543); if (myip.isEmpty()) { cerr << "No setting found for this machine's BackendServerIP.\n" << "Please run setup on this machine and modify the first page\n" << "of the general settings.\n"; return GENERIC_EXIT_SETUP_ERROR; } MythSystemEventHandler *sysEventHandler = new MythSystemEventHandler(); if (ismaster) { LOG(VB_GENERAL, LOG_NOTICE, LOC + "Starting up as the master server."); } else { LOG(VB_GENERAL, LOG_NOTICE, LOC + "Running as a slave backend."); } print_warnings(cmdline); bool fatal_error = false; bool runsched = setupTVs(ismaster, fatal_error); if (fatal_error) { delete sysEventHandler; return GENERIC_EXIT_SETUP_ERROR; } if (ismaster) { if (runsched) { sched = new Scheduler(true, &tvList); int err = sched->GetError(); if (err) return err; if (cmdline.toBool("nosched")) sched->DisableScheduling(); } if (!cmdline.toBool("nohousekeeper")) housekeeping = new HouseKeeper(true, ismaster, sched); if (!cmdline.toBool("noautoexpire")) { expirer = new AutoExpire(&tvList); if (sched) sched->SetExpirer(expirer); } } else if (!cmdline.toBool("nohousekeeper")) { housekeeping = new HouseKeeper(true, ismaster, NULL); } if (!cmdline.toBool("nojobqueue")) jobqueue = new JobQueue(ismaster); // ---------------------------------------------------------------------- // // ---------------------------------------------------------------------- if (g_pUPnp == NULL) { g_pUPnp = new MediaServer(); g_pUPnp->Init(ismaster, cmdline.toBool("noupnp")); } // ---------------------------------------------------------------------- // Setup status server // ---------------------------------------------------------------------- HttpStatus *httpStatus = NULL; HttpServer *pHS = g_pUPnp->GetHttpServer(); if (pHS) { LOG(VB_GENERAL, LOG_INFO, "Main::Registering HttpStatus Extension"); httpStatus = new HttpStatus( &tvList, sched, expirer, ismaster ); pHS->RegisterExtension( httpStatus ); } MainServer *mainServer = new MainServer(ismaster, port, &tvList, sched, expirer); int exitCode = mainServer->GetExitCode(); if (exitCode != GENERIC_EXIT_OK) { LOG(VB_GENERAL, LOG_CRIT, "Backend exiting, MainServer initialization error."); delete mainServer; return exitCode; } if (httpStatus && mainServer) httpStatus->SetMainServer(mainServer); StorageGroup::CheckAllStorageGroupDirs(); if (gCoreContext->IsMasterBackend()) SendMythSystemEvent("MASTER_STARTED"); /////////////////////////////// /////////////////////////////// exitCode = qApp->exec(); /////////////////////////////// /////////////////////////////// if (gCoreContext->IsMasterBackend()) { SendMythSystemEvent("MASTER_SHUTDOWN"); qApp->processEvents(); } LOG(VB_GENERAL, LOG_NOTICE, "MythBackend exiting"); delete sysEventHandler; delete mainServer; cleanup(); return exitCode; }
int handle_command(const MythBackendCommandLineParser &cmdline) { QString eventString; if (cmdline.toBool("event")) eventString = cmdline.toString("event"); else if (cmdline.toBool("systemevent")) eventString = "SYSTEM_EVENT " + cmdline.toString("systemevent") + QString(" SENDER %1").arg(gCoreContext->GetHostName()); if (!eventString.isEmpty()) { if (gCoreContext->ConnectToMasterServer()) { RemoteSendMessage(eventString); return GENERIC_EXIT_OK; } return GENERIC_EXIT_NO_MYTHCONTEXT; } if (cmdline.toBool("setverbose")) { if (gCoreContext->ConnectToMasterServer()) { QString message = "SET_VERBOSE "; message += cmdline.toString("setverbose"); RemoteSendMessage(message); VERBOSE(VB_IMPORTANT, QString("Sent '%1' message").arg(message)); return GENERIC_EXIT_OK; } else { VERBOSE(VB_IMPORTANT, "Unable to connect to backend, verbose level unchanged "); return GENERIC_EXIT_CONNECT_ERROR; } } if (cmdline.toBool("clearcache")) { if (gCoreContext->ConnectToMasterServer()) { RemoteSendMessage("CLEAR_SETTINGS_CACHE"); VERBOSE(VB_IMPORTANT, "Sent CLEAR_SETTINGS_CACHE message"); return GENERIC_EXIT_OK; } else { VERBOSE(VB_IMPORTANT, "Unable to connect to backend, settings " "cache will not be cleared."); return GENERIC_EXIT_CONNECT_ERROR; } } if (cmdline.toBool("printsched") || cmdline.toBool("testsched")) { sched = new Scheduler(false, &tvList); if (!cmdline.toBool("testsched") && gCoreContext->ConnectToMasterServer()) { cout << "Retrieving Schedule from Master backend.\n"; sched->FillRecordListFromMaster(); } else { cout << "Calculating Schedule from database.\n" << "Inputs, Card IDs, and Conflict info may be invalid " "if you have multiple tuners.\n"; sched->FillRecordListFromDB(); } print_verbose_messages |= VB_SCHEDULE; sched->PrintList(true); return GENERIC_EXIT_OK; } if (cmdline.toBool("resched")) { bool ok = false; if (gCoreContext->ConnectToMasterServer()) { VERBOSE(VB_IMPORTANT, "Connected to master for reschedule"); ScheduledRecording::signalChange(-1); ok = true; } else VERBOSE(VB_IMPORTANT, "Cannot connect to master for reschedule"); return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR; } if (cmdline.toBool("scanvideos")) { bool ok = false; if (gCoreContext->ConnectToMasterServer()) { gCoreContext->SendReceiveStringList(QStringList() << "SCAN_VIDEOS"); VERBOSE(VB_IMPORTANT, "Requested video scan"); ok = true; } else VERBOSE(VB_IMPORTANT, "Cannot connect to master for video scan"); return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR; } if (!cmdline.toBool("printexpire")) { expirer = new AutoExpire(); expirer->PrintExpireList(cmdline.toString("printexpire")); return GENERIC_EXIT_OK; } // This should never actually be reached.. return GENERIC_EXIT_OK; }