PtpClock * ptpdStartup(int argc, char **argv, Integer16 * ret, RunTimeOpts * rtOpts) { PtpClock * ptpClock; TimeInternal tmpTime; int i = 0; /* * Set the default mode for all newly created files - previously * this was not the case for log files. This adds consistency * and allows to use FILE* vs. fds everywhere */ umask(~DEFAULT_FILE_PERMS); /* get some entropy in... */ getTime(&tmpTime); srand(tmpTime.seconds ^ tmpTime.nanoseconds); /** * If a required setting, such as interface name, or a setting * requiring a range check is to be set via getopts_long, * the respective currentConfig dictionary entry should be set, * instead of just setting the rtOpts field. * * Config parameter evaluation priority order: * 1. Any dictionary keys set in the getopt_long loop * 2. CLI long section:key type options * 3. Any built-in config templates * 4. Any templates loaded from template file * 5. Config file (parsed last), merged with 2. and 3 - will be overwritten by CLI options * 6. Defaults and any rtOpts fields set in the getopt_long loop **/ /** * Load defaults. Any options set here and further inside loadCommandLineOptions() * by setting rtOpts fields, will be considered the defaults * for config file and section:key long options. */ loadDefaultSettings(rtOpts); /* initialise the config dictionary */ rtOpts->candidateConfig = dictionary_new(0); rtOpts->cliConfig = dictionary_new(0); /* parse all long section:key options and clean up argv for getopt */ loadCommandLineKeys(rtOpts->cliConfig,argc,argv); /* parse the normal short and long options, exit on error */ if (!loadCommandLineOptions(rtOpts, rtOpts->cliConfig, argc, argv, ret)) { goto fail; } /* Display startup info and argv if not called with -? or -H */ NOTIFY("%s version %s starting\n",USER_DESCRIPTION, USER_VERSION); dump_command_line_parameters(argc, argv); /* * we try to catch as many error conditions as possible, but before we call daemon(). * the exception is the lock file, as we get a new pid when we call daemon(), * so this is checked twice: once to read, second to read/write */ if(geteuid() != 0) { printf("Error: "PTPD_PROGNAME" daemon can only be run as root\n"); *ret = 1; goto fail; } /* Have we got a config file? */ if(strlen(rtOpts->configFile) > 0) { /* config file settings overwrite all others, except for empty strings */ INFO("Loading configuration file: %s\n",rtOpts->configFile); if(loadConfigFile(&rtOpts->candidateConfig, rtOpts)) { dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, 1, "from command line"); } else { *ret = 1; dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, 1, "from command line"); goto configcheck; } } else { dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, 1, "from command line"); } /** * This is where the final checking of the candidate settings container happens. * A dictionary is returned with only the known options, explicitly set to defaults * if not present. NULL is returned on any config error - parameters missing, out of range, * etc. The getopt loop in loadCommandLineOptions() only sets keys verified here. */ if( ( rtOpts->currentConfig = parseConfig(CFGOP_PARSE, NULL, rtOpts->candidateConfig,rtOpts)) == NULL ) { *ret = 1; dictionary_del(&rtOpts->candidateConfig); goto configcheck; } /* we've been told to print the lock file and exit cleanly */ if(rtOpts->printLockFile) { printf("%s\n", rtOpts->lockFile); *ret = 0; goto fail; } /* we don't need the candidate config any more */ dictionary_del(&rtOpts->candidateConfig); /* Check network before going into background */ if(!testInterface(rtOpts->primaryIfaceName, rtOpts)) { ERROR("Error: Cannot use %s interface\n",rtOpts->primaryIfaceName); *ret = 1; goto configcheck; } if(rtOpts->backupIfaceEnabled && !testInterface(rtOpts->backupIfaceName, rtOpts)) { ERROR("Error: Cannot use %s interface as backup\n",rtOpts->backupIfaceName); *ret = 1; goto configcheck; } configcheck: /* * We've been told to check config only - clean exit before checking locks */ if(rtOpts->checkConfigOnly) { if(*ret != 0) { printf("Configuration has errors\n"); *ret = 1; } else printf("Configuration OK\n"); goto fail; } /* Previous errors - exit */ if(*ret !=0) goto fail; /* First lock check, just to be user-friendly to the operator */ if(!rtOpts->ignore_daemon_lock) { if(!writeLockFile(rtOpts)){ /* check and create Lock */ ERROR("Error: file lock failed (use -L or global:ignore_lock to ignore lock file)\n"); *ret = 3; goto fail; } /* check for potential conflicts when automatic lock files are used */ if(!checkOtherLocks(rtOpts)) { *ret = 3; goto fail; } } /* Manage log files: stats, log, status and quality file */ restartLogging(rtOpts); /* Allocate memory after we're done with other checks but before going into daemon */ ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock)); if (!ptpClock) { PERROR("Error: Failed to allocate memory for protocol engine data"); *ret = 2; goto fail; } else { DBG("allocated %d bytes for protocol engine data\n", (int)sizeof(PtpClock)); ptpClock->foreign = (ForeignMasterRecord *) calloc(rtOpts->max_foreign_records, sizeof(ForeignMasterRecord)); if (!ptpClock->foreign) { PERROR("failed to allocate memory for foreign " "master data"); *ret = 2; free(ptpClock); goto fail; } else { DBG("allocated %d bytes for foreign master data\n", (int)(rtOpts->max_foreign_records * sizeof(ForeignMasterRecord))); } } if(rtOpts->statisticsLog.logEnabled) ptpClock->resetStatisticsLog = TRUE; /* Init to 0 net buffer */ memset(ptpClock->msgIbuf, 0, PACKET_SIZE); memset(ptpClock->msgObuf, 0, PACKET_SIZE); /* Init outgoing management message */ ptpClock->outgoingManageTmp.tlv = NULL; /* DAEMON */ #ifdef PTPD_NO_DAEMON if(!rtOpts->nonDaemon){ rtOpts->nonDaemon=TRUE; } #endif if(!rtOpts->nonDaemon){ /* * fork to daemon - nochdir non-zero to preserve the working directory: * allows relative paths to be used for log files, config files etc. * Always redirect stdout/err to /dev/null */ if (daemon(1,0) == -1) { PERROR("Failed to start as daemon"); *ret = 3; goto fail; } INFO(" Info: Now running as a daemon\n"); /* * Wait for the parent process to terminate, but not forever. * On some systems this happened after we tried re-acquiring * the lock, so the lock would fail. Hence, we wait. */ for (i = 0; i < 1000000; i++) { /* Once we've been reaped by init, parent PID will be 1 */ if(getppid() == 1) break; usleep(1); } } /* Second lock check, to replace the contents with our own new PID and re-acquire the advisory lock */ if(!rtOpts->nonDaemon && !rtOpts->ignore_daemon_lock){ /* check and create Lock */ if(!writeLockFile(rtOpts)){ ERROR("Error: file lock failed (use -L or global:ignore_lock to ignore lock file)\n"); *ret = 3; goto fail; } } #if (defined(linux) && defined(HAVE_SCHED_H)) || defined(HAVE_SYS_CPUSET_H) || defined(__QNXNTO__) /* Try binding to a single CPU core if configured to do so */ if(rtOpts->cpuNumber > -1) { if(setCpuAffinity(rtOpts->cpuNumber) < 0) { ERROR("Could not bind to CPU core %d\n", rtOpts->cpuNumber); } else { INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", rtOpts->cpuNumber); } } #endif /* set up timers */ if(!timerSetup(ptpClock->timers)) { PERROR("failed to set up event timers"); *ret = 2; free(ptpClock); goto fail; } /* establish signal handlers */ signal(SIGINT, catchSignals); signal(SIGTERM, catchSignals); signal(SIGHUP, catchSignals); signal(SIGUSR1, catchSignals); signal(SIGUSR2, catchSignals); #if defined PTPD_SNMP /* Start SNMP subsystem */ if (rtOpts->snmp_enabled) snmpInit(rtOpts, ptpClock); #endif NOTICE(USER_DESCRIPTION" started successfully on %s using \"%s\" preset (PID %d)\n", rtOpts->ifaceName, (getPtpPreset(rtOpts->selectedPreset,rtOpts)).presetName, getpid()); ptpClock->resetStatisticsLog = TRUE; #ifdef PTPD_STATISTICS outlierFilterSetup(&ptpClock->oFilterMS); outlierFilterSetup(&ptpClock->oFilterSM); ptpClock->oFilterMS.init(&ptpClock->oFilterMS,&rtOpts->oFilterMSConfig, "delayMS"); ptpClock->oFilterSM.init(&ptpClock->oFilterSM,&rtOpts->oFilterSMConfig, "delaySM"); if(rtOpts->filterMSOpts.enabled) { ptpClock->filterMS = createDoubleMovingStatFilter(&rtOpts->filterMSOpts,"delayMS"); } if(rtOpts->filterSMOpts.enabled) { ptpClock->filterSM = createDoubleMovingStatFilter(&rtOpts->filterSMOpts, "delaySM"); } #endif #ifdef PTPD_PCAP ptpClock->netPath.pcapEventSock = -1; ptpClock->netPath.pcapGeneralSock = -1; #endif /* PTPD_PCAP */ ptpClock->netPath.generalSock = -1; ptpClock->netPath.eventSock = -1; *ret = 0; return ptpClock; fail: dictionary_del(&rtOpts->cliConfig); dictionary_del(&rtOpts->candidateConfig); dictionary_del(&rtOpts->currentConfig); return 0; }
/** * Main program entry point * * This function is the one called by the operating system to start Luna. * * This function sets {@link appArgc appArgc} and {@link appArgv appArgv}. * * @see appArgc * @see appArgv * * @param argc Number of command-line arguments * @param argv Pointer to list of char* of each of the arguments * * @return 0 = success, anything else = failure */ int main( int argc, char** argv) { appArgc = argc; appArgv = argv; std::set_terminate(generateGoodBacktraceTerminateHandler); g_thread_init(NULL); const char *renderMode; #if defined(TARGET_DEVICE) && defined(HAVE_OPENGL) ::setenv("QT_PLUGIN_PATH", "/usr/plugins", 1); renderMode = "HW egl"; #elif defined(TARGET_DEVICE) || defined(TARGET_EMULATOR) ::setenv("QT_PLUGIN_PATH", "/usr/plugins", 1); renderMode = "Software"; #elif defined(HAVE_OPENGL) renderMode = "HW OpenGL"; #else renderMode = "Software"; #endif WindowServer::markBootStart(); g_debug("SysMgr compiled against Qt %s, running on %s, %s render mode requested", QT_VERSION_STR, qVersion(), renderMode); // Command-Line options parseCommandlineOptions(argc, argv); if (s_debugTrapStr && 0 == strcasecmp(s_debugTrapStr, "on")) { debugCrashes = true; } if (s_mallocStatsFileStr) { setupMallocStats(s_mallocStatsFileStr); } sysmgrPid = getpid(); // Load Settings (first!) Settings* settings = Settings::LunaSettings(); // Initialize logging handler g_log_set_default_handler(logFilter, NULL); #if defined(TARGET_DESKTOP) // use terminal logging when running on desktop settings->logger_useTerminal = true; #endif // disable color logging using an environment variable. Useful when run from QtCreator const char* useColor = ::getenv("COLOR_LOGGING"); if (useColor) settings->logger_useColor = (useColor[0] != 0 && useColor[0] != '0'); HostBase* host = HostBase::instance(); // the resolution is just a hint, the actual // resolution may get picked up from the fb driver on arm host->init(settings->displayWidth, settings->displayHeight); #if defined(TARGET_DEVICE) pid_t animPid= spawnBootupAnimationProcess(); if(animPid < 0) { // failed to start the Animation process return -1; } #endif #if defined(TARGET_DEVICE) && defined(HAVE_OPENGL) && defined(HAVE_QPA) if (settings->forceSoftwareRendering) ::setenv("QT_QPA_PLATFORM", "palm-soft", 1); else ::setenv("QT_QPA_PLATFORM", "palm", 1); #endif #if defined(TARGET_DEVICE) && defined(HAVE_OPENGL) if (!settings->forceSoftwareRendering) ::setenv("QWS_DISPLAY", "egl", 1); #endif pid_t webKitPid= spawnWebKitProcess(); if(webKitPid < 0) { // failed to start the WebKit process return -1; } // Tie LunaSysMgr to Processor 0 setCpuAffinity(getpid(), 1); // Tie WebAppMgr to Processor 1 setCpuAffinity(webKitPid, 0); // Safe to create logging threads now logInit(); // Initialize Ipc Server (void) IpcServer::instance(); // Ipc Server is ready, so signal the WebAppMgr process (via pipe) to go ahead and connect ::write(WebAppMgrPipeFd, &msgOkToContinue, 1); ::close(WebAppMgrPipeFd); WebAppMgrPipeFd = -1; #if !defined(TARGET_DESKTOP) // Set "nice" property setpriority(PRIO_PROCESS,getpid(),-1); #endif #if !defined(TARGET_DESKTOP) && !defined(HAVE_QPA) QWSServer::setDefaultMouse("HiddTp"); QWSServer::setDefaultKeyboard("HiddKbd"); ::setenv("QWS_DBLCLICK_DISTANCE", QString("%0").arg(Settings::LunaSettings()->tapRadius).toAscii().constData(), 1); #endif qInstallMsgHandler(qtMsgHandler); QApplication app(argc, argv); QApplication::setStartDragDistance(settings->tapRadius); QApplication::setDoubleClickInterval (Settings::LunaSettings()->tapDoubleClickDuration); host->show(); initMallocStatsCb(HostBase::instance()->mainLoop(), s_mallocStatsInterval); // Initialize Preferences handler (void) Preferences::instance(); // Initialize Localization handler (void) Localization::instance(); //Register vibration/haptics support HapticsController::instance()->startService(); (void) DeviceInfo::instance(); // Initialize Security handler (void) Security::instance(); // Initialize the System Service SystemService::instance()->init(); // Initialize the application mgr ApplicationManager::instance()->init(); // Initialize the Application Installer ApplicationInstaller::instance(); // Start the window manager WindowServer *windowServer = WindowServer::instance(); windowServer->installEventFilter(windowServer); // Initialize the SysMgr MemoryMonitor MemoryMonitor::instance(); // load all set policies EASPolicyManager::instance()->load(); // Launching of the System UI launcher and headless apps has been moved to WebAppMgrProxy::connectWebAppMgr // Did user specify an app to launch if (s_appToLaunchStr) { WebAppMgrProxy::setAppToLaunchUponConnection(s_appToLaunchStr); } app.exec(); return 0; }
void applyConfig(dictionary *baseConfig, RunTimeOpts *rtOpts, PtpClock *ptpClock) { Boolean reloadSuccessful = TRUE; /* Load default config to fill in the blanks in the config file */ RunTimeOpts tmpOpts; loadDefaultSettings(&tmpOpts); /* Check the new configuration for errors, fill in the blanks from defaults */ if( ( rtOpts->candidateConfig = parseConfig(CFGOP_PARSE, NULL, baseConfig, &tmpOpts)) == NULL ) { WARNING("Configuration has errors, reload aborted\n"); return; } /* Check for changes between old and new configuration */ if(compareConfig(rtOpts->candidateConfig,rtOpts->currentConfig)) { INFO("Configuration unchanged\n"); goto cleanup; } /* * Mark which subsystems have to be restarted. Most of this will be picked up by doState() * If there are errors past config correctness (such as non-existent NIC, * or lock file clashes if automatic lock files used - abort the mission */ rtOpts->restartSubsystems = checkSubsystemRestart(rtOpts->candidateConfig, rtOpts->currentConfig, rtOpts); /* If we're told to re-check lock files, do it: tmpOpts already has what rtOpts should */ if( (rtOpts->restartSubsystems & PTPD_CHECK_LOCKS) && tmpOpts.autoLockFile && !checkOtherLocks(&tmpOpts)) { reloadSuccessful = FALSE; } /* If the network configuration has changed, check if the interface is OK */ if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) { INFO("Network configuration changed - checking interface(s)\n"); if(!testInterface(tmpOpts.primaryIfaceName, &tmpOpts)) { reloadSuccessful = FALSE; ERROR("Error: Cannot use %s interface\n",tmpOpts.primaryIfaceName); } if(rtOpts->backupIfaceEnabled && !testInterface(tmpOpts.backupIfaceName, &tmpOpts)) { rtOpts->restartSubsystems = -1; ERROR("Error: Cannot use %s interface as backup\n",tmpOpts.backupIfaceName); } } #if (defined(linux) && defined(HAVE_SCHED_H)) || defined(HAVE_SYS_CPUSET_H) || defined(__QNXNTO__) /* Changing the CPU affinity mask */ if(rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration: changing selected CPU core\n"); if(setCpuAffinity(tmpOpts.cpuNumber) < 0) { if(tmpOpts.cpuNumber == -1) { ERROR("Could not unbind from CPU core %d\n", rtOpts->cpuNumber); } else { ERROR("Could bind to CPU core %d\n", tmpOpts.cpuNumber); } reloadSuccessful = FALSE; } else { if(tmpOpts.cpuNumber > -1) INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); else INFO("Successfully unbound "PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } } #endif if(!reloadSuccessful) { ERROR("New configuration cannot be applied - aborting reload\n"); rtOpts->restartSubsystems = 0; goto cleanup; } /** * Commit changes to rtOpts and currentConfig * (this should never fail as the config has already been checked if we're here) * However if this DOES fail, some default has been specified out of range - * this is the only situation where parse will succeed but commit not: * disable quiet mode to show what went wrong, then die. */ if (rtOpts->currentConfig) { dictionary_del(&rtOpts->currentConfig); } if ( (rtOpts->currentConfig = parseConfig(CFGOP_PARSE_QUIET, NULL, rtOpts->candidateConfig,rtOpts)) == NULL) { CRITICAL("************ "PTPD_PROGNAME": parseConfig returned NULL during config commit" " - this is a BUG - report the following: \n"); if ((rtOpts->currentConfig = parseConfig(CFGOP_PARSE, NULL, rtOpts->candidateConfig,rtOpts)) == NULL) CRITICAL("*****************" PTPD_PROGNAME" shutting down **********************\n"); /* * Could be assert(), but this should be done any time this happens regardless of * compile options. Anyhow, if we're here, the daemon will no doubt segfault soon anyway */ abort(); } /* clean up */ cleanup: dictionary_del(&rtOpts->candidateConfig); }