コード例 #1
0
int run_backend(const MythCommandLineParser &cmdline)
{
    if (!setup_context(cmdline))
        return GENERIC_EXIT_NO_MYTHCONTEXT;

    bool ismaster = gCoreContext->IsMasterHost();

    if (!UpgradeTVDatabaseSchema(ismaster, ismaster))
    {
        VERBOSE(VB_IMPORTANT, "Couldn't upgrade database to new schema");
        return GENERIC_EXIT_DB_OUTOFDATE;
    }

    ///////////////////////////////////////////

    g_pUPnp = new MediaServer(ismaster, !cmdline.IsUPnPEnabled() );

    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)
    {
        VERBOSE(VB_GENERAL, LOC + "Starting up as the master server.");
        gCoreContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started as master server", "");
    }
    else
    {
        VERBOSE(VB_GENERAL, LOC + "Running as a slave backend.");
        gCoreContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started 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.IsSchedulerEnabled())
                sched->DisableScheduling();
        }

        if (cmdline.IsHouseKeeperEnabled())
            housekeeping = new HouseKeeper(true, ismaster, sched);

        if (cmdline.IsAutoExpirerEnabled())
        {
            expirer = new AutoExpire(&tvList);
            if (sched)
                sched->SetExpirer(expirer);
        }
    }
    else if (cmdline.IsHouseKeeperEnabled())
    {
        housekeeping = new HouseKeeper(true, ismaster, NULL);
    }

    if (cmdline.IsJobQueueEnabled())
        jobqueue = new JobQueue(ismaster);

    // Setup status server
    HttpStatus *httpStatus = NULL;
    HttpServer *pHS = g_pUPnp->GetHttpServer();
    if (pHS)
    {
        VERBOSE(VB_IMPORTANT, "Main::Registering HttpStatus Extension");

        httpStatus = new HttpStatus(&tvList, sched, expirer, ismaster);
        if (httpStatus)
            pHS->RegisterExtension(httpStatus);
    }

    VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1")
            .arg(verboseString));

    MainServer *mainServer = new MainServer(
        ismaster, port, &tvList, sched, expirer);

    int exitCode = mainServer->GetExitCode();
    if (exitCode != GENERIC_EXIT_OK)
    {
        VERBOSE(VB_IMPORTANT, "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();
    }

    gCoreContext->LogEntry("mythbackend", LP_INFO, "MythBackend exiting", "");

    delete sysEventHandler;
    delete mainServer;

    return exitCode;
}
コード例 #2
0
ファイル: main_helpers.cpp プロジェクト: Openivo/mythtv
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;
}
コード例 #3
0
ファイル: main_helpers.cpp プロジェクト: DaveDaCoda/mythtv
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;
}
コード例 #4
0
int main(int argc, char **argv)
{
    bool need_gui = false;
#ifndef _WIN32
    for (int i = 3; i < sysconf(_SC_OPEN_MAX) - 1; ++i)
        close(i);
#else
    // MINGW application needs a window to receive messages
    // such as socket notifications :[
    need_gui = true;
#endif

    QApplication a(argc, argv, need_gui);

    QMap<QString, QString> settingsOverride;
    QString binname = basename(a.argv()[0]);

    long long previewFrameNumber = -2;
    long long previewSeconds     = -2;
    QSize previewSize(0,0);
    QString chanid    = QString::null;
    QString starttime = QString::null;
    QString infile    = QString::null;
    QString outfile   = QString::null;

    bool daemonize = false;
    bool printsched = false;
    bool testsched = false;
    bool resched = false;
    bool nosched = false;
    bool noupnp = false;
    bool nojobqueue = false;
    bool nohousekeeper = false;
    bool noexpirer = false;
    QString printexpire = "";
    bool clearsettingscache = false;
    bool wantupnprebuild = false;

    for (int argpos = 1; argpos < a.argc(); ++argpos)
    {
        if (!strcmp(a.argv()[argpos],"-l") ||
                !strcmp(a.argv()[argpos],"--logfile"))
        {
            if (a.argc() > argpos)
            {
                logfile = a.argv()[argpos+1];
                if (logfile.startsWith("-"))
                {
                    cerr << "Invalid or missing argument to -l/--logfile option\n";
                    return BACKEND_EXIT_INVALID_CMDLINE;
                }
                else
                {
                    ++argpos;
                }
            }
        }
        else if (!strcmp(a.argv()[argpos],"-p") ||
                 !strcmp(a.argv()[argpos],"--pidfile"))
        {
            if (a.argc() > argpos)
            {
                pidfile = a.argv()[argpos+1];
                if (pidfile.startsWith("-"))
                {
                    cerr << "Invalid or missing argument to -p/--pidfile option\n";
                    return BACKEND_EXIT_INVALID_CMDLINE;
                }
                else
                {
                    ++argpos;
                }
            }
        }
        else if (!strcmp(a.argv()[argpos],"-d") ||
                 !strcmp(a.argv()[argpos],"--daemon"))
        {
            daemonize = true;

        }
        else if (!strcmp(a.argv()[argpos],"-O") ||
                 !strcmp(a.argv()[argpos],"--override-setting"))
        {
            if (a.argc()-1 > argpos)
            {
                QString tmpArg = a.argv()[argpos+1];
                if (tmpArg.startsWith("-"))
                {
                    cerr << "Invalid or missing argument to -O/--override-setting option\n";
                    return BACKEND_EXIT_INVALID_CMDLINE;
                }

                QStringList pairs = QStringList::split(",", tmpArg);
                for (unsigned int index = 0; index < pairs.size(); ++index)
                {
                    QStringList tokens = QStringList::split("=", pairs[index]);
                    tokens[0].replace(QRegExp("^[\"']"), "");
                    tokens[0].replace(QRegExp("[\"']$"), "");
                    tokens[1].replace(QRegExp("^[\"']"), "");
                    tokens[1].replace(QRegExp("[\"']$"), "");
                    settingsOverride[tokens[0]] = tokens[1];
                }
            }
            else
            {
                cerr << "Invalid or missing argument to -O/--override-setting option\n";
                return BACKEND_EXIT_INVALID_CMDLINE;
            }

            ++argpos;
        }
        else if (!strcmp(a.argv()[argpos],"-v") ||
                 !strcmp(a.argv()[argpos],"--verbose"))
        {
            if (a.argc()-1 > argpos)
            {
                if (parse_verbose_arg(a.argv()[argpos+1]) ==
                        GENERIC_EXIT_INVALID_CMDLINE)
                    return BACKEND_EXIT_INVALID_CMDLINE;

                ++argpos;
            }
            else
            {
                cerr << "Missing argument to -v/--verbose option\n";
                return BACKEND_EXIT_INVALID_CMDLINE;
            }
        }
        else if (!strcmp(a.argv()[argpos],"--printsched"))
        {
            printsched = true;
        }
        else if (!strcmp(a.argv()[argpos],"--testsched"))
        {
            testsched = true;
        }
        else if (!strcmp(a.argv()[argpos],"--resched"))
        {
            resched = true;
        }
        else if (!strcmp(a.argv()[argpos],"--nosched"))
        {
            nosched = true;
        }
        else if (!strcmp(a.argv()[argpos],"--noupnp"))
        {
            noupnp = true;
        }
        else if (!strcmp(a.argv()[argpos],"--upnprebuild"))
        {
            wantupnprebuild = true;
        }
        else if (!strcmp(a.argv()[argpos],"--nojobqueue"))
        {
            nojobqueue = true;
        }
        else if (!strcmp(a.argv()[argpos],"--nohousekeeper"))
        {
            nohousekeeper = true;
        }
        else if (!strcmp(a.argv()[argpos],"--noautoexpire"))
        {
            noexpirer = true;
        }
        else if (!strcmp(a.argv()[argpos],"--printexpire"))
        {
            printexpire = "ALL";
            if ((a.argc()-1 > argpos) && a.argv()[argpos+1][0] != '-')
            {
                printexpire = a.argv()[argpos+1];
                ++argpos;
            }
        }
        else if (!strcmp(a.argv()[argpos],"--clearcache"))
        {
            clearsettingscache = true;
        }
        else if (!strcmp(a.argv()[argpos],"--version"))
        {
            extern const char *myth_source_version;
            extern const char *myth_source_path;
            cout << "Please include all output in bug reports." << endl;
            cout << "MythTV Version   : " << myth_source_version << endl;
            cout << "MythTV Branch    : " << myth_source_path << endl;
            cout << "Library API      : " << MYTH_BINARY_VERSION << endl;
            cout << "Network Protocol : " << MYTH_PROTO_VERSION << endl;
#ifdef MYTH_BUILD_CONFIG
            cout << "Options compiled in:" <<endl;
            cout << MYTH_BUILD_CONFIG << endl;
#endif
            return BACKEND_EXIT_OK;
        }
        else if (!strcmp(a.argv()[argpos],"--generate-preview"))
        {
            QString tmp = QString::null;
            if ((argpos + 1) < a.argc())
            {
                tmp = a.argv()[argpos+1];
                bool ok = true;
                if (tmp.left(1) == "-")
                    tmp.left(2).toInt(&ok);
                if (ok)
                    argpos++;
                else
                    tmp = QString::null;
            }

            if (!parse_preview_info(tmp, previewFrameNumber, previewSeconds,
                                    previewSize))
            {
                VERBOSE(VB_IMPORTANT,
                        QString("Unable to parse --generate-preview "
                                "option '%1'").arg(tmp));

                return BACKEND_EXIT_INVALID_CMDLINE;
            }
        }
        else if (!strcmp(a.argv()[argpos],"-c") ||
                 !strcmp(a.argv()[argpos],"--chanid"))
        {
            if (((argpos + 1) >= a.argc()) ||
                    !strncmp(a.argv()[argpos + 1], "-", 1))
            {
                VERBOSE(VB_IMPORTANT,
                        "Missing or invalid parameters for --chanid option");

                return BACKEND_EXIT_INVALID_CMDLINE;
            }

            chanid = a.argv()[++argpos];
        }
        else if (!strcmp(a.argv()[argpos],"-s") ||
                 !strcmp(a.argv()[argpos],"--starttime"))
        {
            if (((argpos + 1) >= a.argc()) ||
                    !strncmp(a.argv()[argpos + 1], "-", 1))
            {
                VERBOSE(VB_IMPORTANT,
                        "Missing or invalid parameters for --starttime option");
                return BACKEND_EXIT_INVALID_CMDLINE;
            }

            starttime = a.argv()[++argpos];
        }
        else if (!strcmp(a.argv()[argpos],"--infile"))
        {
            if (((argpos + 1) >= a.argc()) ||
                    !strncmp(a.argv()[argpos + 1], "-", 1))
            {
                VERBOSE(VB_IMPORTANT,
                        "Missing or invalid parameters for --infile option");

                return BACKEND_EXIT_INVALID_CMDLINE;
            }

            infile = a.argv()[++argpos];
        }
        else if (!strcmp(a.argv()[argpos],"--outfile"))
        {
            if (((argpos + 1) >= a.argc()) ||
                    !strncmp(a.argv()[argpos + 1], "-", 1))
            {
                VERBOSE(VB_IMPORTANT,
                        "Missing or invalid parameters for --outfile option");

                return BACKEND_EXIT_INVALID_CMDLINE;
            }

            outfile = a.argv()[++argpos];
        }
        else
        {
            if (!(!strcmp(a.argv()[argpos],"-h") ||
                    !strcmp(a.argv()[argpos],"--help")))
                cerr << "Invalid argument: " << a.argv()[argpos] << endl;
            cerr << "Valid options are: " << endl <<
                 "-h or --help                   List valid command line parameters" << endl <<
                 "-l or --logfile filename       Writes STDERR and STDOUT messages to filename" << endl <<
                 "-p or --pidfile filename       Write PID of mythbackend " <<
                 "to filename" << endl <<
                 "-d or --daemon                 Runs mythbackend as a daemon" << endl <<
                 "-v or --verbose debug-level    Use '-v help' for level info" << endl <<
                 "--printexpire                  List of auto-expire programs" << endl <<
                 "--printsched                   Upcoming scheduled programs" << endl <<
                 "--testsched                    Test run scheduler (ignore existing schedule)" << endl <<
                 "--resched                      Force the scheduler to update" << endl <<
                 "--nosched                      Do not perform any scheduling" << endl <<
                 "--noupnp                       Do not enable the UPNP server" << endl <<
                 "--nojobqueue                   Do not start the JobQueue" << endl <<
                 "--nohousekeeper                Do not start the Housekeeper" << endl <<
                 "--noautoexpire                 Do not start the AutoExpire thread" << endl <<
                 "--clearcache                   Clear the settings cache on all myth servers" << endl <<
                 "--version                      Version information" << endl <<
                 "--generate-preview             Generate a preview image" << endl <<
                 "--upnprebuild                  Force an update of UPNP media" << endl <<
                 "--infile                       Input file for preview generation" << endl <<
                 "--outfile                      Optional output file for preview generation" << endl <<
                 "--chanid                       Channel ID for preview generation" << endl <<
                 "--starttime                    Recording start time for preview generation" << endl;
            return BACKEND_EXIT_INVALID_CMDLINE;
        }
    }

    if (((previewFrameNumber >= -1) || previewSeconds >= -1) &&
            (chanid.isEmpty() || starttime.isEmpty()) && infile.isEmpty())
    {
        cerr << "--generate-preview must be accompanied by either " <<endl
             << "\nboth --chanid and --starttime paramaters, " << endl
             << "\nor the --infile paramater." << endl;
        return BACKEND_EXIT_INVALID_CMDLINE;
    }

    if (logfile != "" )
    {
        if (log_rotate(1) < 0)
            cerr << "cannot open logfile; using stdout/stderr" << endl;
        else
            signal(SIGHUP, &log_rotate_handler);
    }

    ofstream pidfs;
    if (pidfile != "")
    {
        pidfs.open(pidfile.ascii());
        if (!pidfs)
        {
            perror(pidfile.ascii());
            cerr << "Error opening pidfile";
            return BACKEND_EXIT_OPENING_PIDFILE_ERROR;
        }
    }

    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        cerr << "Unable to ignore SIGPIPE\n";

    if (daemonize)
        if (daemon(0, 1) < 0)
        {
            perror("daemon");
            return BACKEND_EXIT_DAEMONIZING_ERROR;
        }


    if (pidfs)
    {
        pidfs << getpid() << endl;
        pidfs.close();
    }

    gContext = NULL;
    gContext = new MythContext(MYTH_BINARY_VERSION);
    if (!gContext->Init(false))
    {
        VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
        return BACKEND_EXIT_NO_MYTHCONTEXT;
    }
    gContext->SetBackend(true);

    if (wantupnprebuild)
    {
        VERBOSE(VB_GENERAL, "Rebuilding UPNP Media Map");

        UPnpMedia *rebuildit = new UPnpMedia(false,false);
        rebuildit->BuildMediaMap();

        return BACKEND_EXIT_OK;
    }

    if (clearsettingscache)
    {
        if (gContext->ConnectToMasterServer())
        {
            RemoteSendMessage("CLEAR_SETTINGS_CACHE");
            VERBOSE(VB_IMPORTANT, "Sent CLEAR_SETTINGS_CACHE message");
            return BACKEND_EXIT_OK;
        }
        else
        {
            VERBOSE(VB_IMPORTANT, "Unable to connect to backend, settings "
                    "cache will not be cleared.");
            return BACKEND_EXIT_NO_CONNECT;
        }
    }

    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.data()));
            gContext->OverrideSettingForSession(it.key(), it.data());
        }
    }

    gContext->ActivateSettingsCache(false);
    if ((CompareTVDatabaseSchemaVersion() > 0) &&
            // and Not MythContext::PromptForSchemaUpgrade() expertMode
            (gContext->GetNumSetting("DBSchemaAutoUpgrade") != -1))
    {
        VERBOSE(VB_IMPORTANT, "The schema version of your existing database "
                "is newer than this version of MythTV understands. Please "
                "ensure that you have selected the proper database server or "
                "upgrade this and all other frontends and backends to the "
                "same MythTV version and revision.");
        return BACKEND_EXIT_DB_OUTOFDATE;
    }
    if (!UpgradeTVDatabaseSchema())
    {
        VERBOSE(VB_IMPORTANT, "Couldn't upgrade database to new schema");
        return BACKEND_EXIT_DB_OUTOFDATE;
    }
    gContext->ActivateSettingsCache(true);

    close(0);

    if (printsched || testsched)
    {
        gContext->SetBackend(false);
        sched = new Scheduler(false, &tvList);
        if (!testsched && gContext->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);
        cleanup();
        return BACKEND_EXIT_OK;
    }

    if (resched)
    {
        gContext->SetBackend(false);

        bool ok = false;
        if (gContext->ConnectToMasterServer())
        {
            VERBOSE(VB_IMPORTANT, "Connected to master for reschedule");
            ScheduledRecording::signalChange(-1);
            ok = true;
        }
        else
            VERBOSE(VB_IMPORTANT, "Cannot connect to master for reschedule");

        cleanup();
        return (ok) ? BACKEND_EXIT_OK : BACKEND_EXIT_NO_CONNECT;
    }

    if (printexpire != "")
    {
        expirer = new AutoExpire();
        expirer->PrintExpireList(printexpire);
        cleanup();
        return BACKEND_EXIT_OK;
    }

    if ((previewFrameNumber >= -1) || (previewSeconds >= -1))
    {
        return preview_helper(
                   chanid, starttime,
                   previewFrameNumber, previewSeconds, previewSize,
                   infile, outfile);
    }

    int port = gContext->GetNumSetting("BackendServerPort", 6543);

    QString myip = gContext->GetSetting("BackendServerIP");
    if (myip.isNull() || 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 BACKEND_EXIT_NO_IP_ADDRESS;
    }

    bool ismaster = gContext->IsMasterHost();

    if (ismaster)
    {
        cerr << "Starting up as the master server.\n";
        gContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started as master server", "");

        if (nosched)
            cerr << "********** The Scheduler has been DISABLED with "
                 "the --nosched option **********\n";

        // kill -USR1 mythbackendpid will force a upnpmedia rebuild
        signal(SIGUSR1, &upnp_rebuild);
    }
    else
    {
        cerr << "Running as a slave backend.\n";
        gContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started as a slave backend", "");
    }

    // Get any initial housekeeping done before we fire up anything else
    if (nohousekeeper)
        cerr << "****** The Housekeeper has been DISABLED with "
             "the --nohousekeeper option ******\n";
    else
        housekeeping = new HouseKeeper(true, ismaster);

    bool fatal_error = false;
    bool runsched = setupTVs(ismaster, fatal_error);
    if (fatal_error)
        return BACKEND_EXIT_CAP_CARD_SETUP_ERROR;

    if (ismaster && runsched)
    {
        sched = new Scheduler(true, &tvList);

        if (nosched)
            sched->DisableScheduling();
    }

    if (ismaster)
    {
        if (noexpirer)
            cerr << "********* Auto-Expire has been DISABLED with "
                 "the --noautoexpire option ********\n";
        else
            expirer = new AutoExpire(&tvList);
    }

    if (sched && expirer)
        sched->SetExpirer(expirer);

    if (nojobqueue)
        cerr << "********* The JobQueue has been DISABLED with "
             "the --nojobqueue option *********\n";
    else
        jobqueue = new JobQueue(ismaster);

    // Start UPnP Services

    g_pUPnp = new MediaServer( ismaster, noupnp );

    HttpServer *pHS = g_pUPnp->GetHttpServer();
    if (pHS)
    {
        VERBOSE(VB_IMPORTANT, "Main::Registering HttpStatus Extension");

        pHS->RegisterExtension( new HttpStatus( &tvList, sched,
                                                expirer, ismaster ));
    }

    VERBOSE(VB_IMPORTANT, QString("%1 version: %2 www.mythtv.org")
            .arg(binname).arg(MYTH_BINARY_VERSION));

    VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1").arg(verboseString));

    new MainServer(ismaster, port, &tvList, sched, expirer);

    if (ismaster)
    {
        QString WOLslaveBackends
            = gContext->GetSetting("WOLslaveBackendsCommand","");
        if (!WOLslaveBackends.isEmpty())
        {
            VERBOSE(VB_IMPORTANT, "Waking slave Backends now.");
            system(WOLslaveBackends.ascii());
        }
    }

    StorageGroup::CheckAllStorageGroupDirs();

    a.exec();

    gContext->LogEntry("mythbackend", LP_INFO, "MythBackend exiting", "");
    cleanup();

    return BACKEND_EXIT_OK;
}