//////////////////////////////////////////////////////////////////////////////// /// @brief application server skeleton /// /// @file /// /// DISCLAIMER /// /// Copyright 2004-2012 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2009-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include "BasicsC/win-utils.h" #endif #include "ApplicationServer.h" #ifdef TRI_HAVE_POSIX_PWD_GRP #include #include #endif #include "ApplicationServer/ApplicationFeature.h" #include "Basics/FileUtils.h" #include "Basics/RandomGenerator.h" #include "Basics/StringUtils.h" #include "Basics/delete_object.h" #include "BasicsC/conversions.h" #include "Logger/Logger.h" #include "build.h" using namespace triagens::basics; using namespace triagens::rest; using namespace std; // ----------------------------------------------------------------------------- // --SECTION-- public constants // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ApplicationServer /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief Command Line Options //////////////////////////////////////////////////////////////////////////////// string const ApplicationServer::OPTIONS_CMDLINE = "Command Line Options"; //////////////////////////////////////////////////////////////////////////////// /// @brief Hidden Options //////////////////////////////////////////////////////////////////////////////// string const ApplicationServer::OPTIONS_HIDDEN = "Hidden Options"; //////////////////////////////////////////////////////////////////////////////// /// @brief Limit Options //////////////////////////////////////////////////////////////////////////////// string const ApplicationServer::OPTIONS_LIMITS = "Limit Options"; //////////////////////////////////////////////////////////////////////////////// /// @brief Logger Options //////////////////////////////////////////////////////////////////////////////// string const ApplicationServer::OPTIONS_LOGGER = "Logging Options"; //////////////////////////////////////////////////////////////////////////////// /// @brief Server Options //////////////////////////////////////////////////////////////////////////////// string const ApplicationServer::OPTIONS_SERVER = "Server Options"; //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ApplicationServer /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 ApplicationServer::ApplicationServer (std::string const& name, std::string const& title, std::string const& version) : _options(), _description(), _descriptionFile(), _arguments(), _features(), _exitOnParentDeath(false), _watchParent(0), _stopping(0), _name(name), _title(title), _version(version), _configFile(), _userConfigFile(), _systemConfigFile(), _systemConfigPath(), _uid(), _realUid(0), _effectiveUid(0), _gid(), _realGid(0), _effectiveGid(0), _logApplicationName("triagens"), _logHostName("-"), _logFacility("-"), _logLevel("info"), _logFormat(), _logSeverity("human"), _logFile("+"), _logPrefix(), _logSyslog(), _logThreadId(false), _logLineNumber(false), _randomGenerator(5) { } #else ApplicationServer::ApplicationServer (std::string const& name, std::string const& title, std::string const& version) : _options(), _description(), _descriptionFile(), _arguments(), _features(), _exitOnParentDeath(false), _watchParent(0), _stopping(0), _name(name), _title(title), _version(version), _configFile(), _userConfigFile(), _systemConfigFile(), _systemConfigPath(), _uid(), _realUid(0), _effectiveUid(0), _gid(), _realGid(0), _effectiveGid(0), _logApplicationName("triagens"), _logHostName("-"), _logFacility("-"), _logLevel("info"), _logFormat(), _logSeverity("human"), _logFile("+"), _logPrefix(), _logSyslog(), _logThreadId(false), _logLineNumber(false), _randomGenerator(3) { } #endif //////////////////////////////////////////////////////////////////////////////// /// @brief destructor //////////////////////////////////////////////////////////////////////////////// ApplicationServer::~ApplicationServer () { Random::shutdown(); for_each(_features.begin(), _features.end(), DeleteObjectAny()); } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ApplicationServer /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief adds a new feature //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::addFeature (ApplicationFeature* feature) { _features.push_back(feature); } //////////////////////////////////////////////////////////////////////////////// /// @brief sets the name of the system config file with a path //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::setSystemConfigFile (std::string const& name, std::string const& path) { _systemConfigFile = name; _systemConfigPath = path; } //////////////////////////////////////////////////////////////////////////////// /// @brief sets the name of the system config file without a path //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::setSystemConfigFile (std::string const& name) { return setSystemConfigFile(name, ""); } //////////////////////////////////////////////////////////////////////////////// /// @brief sets the name of the user config file //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::setUserConfigFile (std::string const& name) { _userConfigFile = name; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the name of the application //////////////////////////////////////////////////////////////////////////////// string const& ApplicationServer::getName () const { return _name; } //////////////////////////////////////////////////////////////////////////////// /// @brief sets up the logging //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::setupLogging () { bool threaded = TRI_ShutdownLogging(); TRI_InitialiseLogging(threaded); Logger::setApplicationName(_logApplicationName); Logger::setHostName(_logHostName); Logger::setFacility(_logFacility); if (! _logFormat.empty()) { Logger::setLogFormat(_logFormat); } if (_options.has("log.thread")) { _logThreadId = true; } if (_options.has("log.line-number")) { _logLineNumber = true; } TRI_SetLineNumberLogging(_logLineNumber); TRI_SetLogLevelLogging(_logLevel); TRI_SetLogSeverityLogging(_logSeverity); TRI_SetPrefixLogging(_logPrefix); TRI_SetThreadIdentifierLogging(_logThreadId); for (vector::iterator i = _logFilter.begin(); i != _logFilter.end(); ++i) { TRI_SetFileToLog(i->c_str()); } if (NULL == TRI_CreateLogAppenderFile(_logFile.c_str())) { if (_logFile.length() > 0) { // the user specified a log file to use but it could not be created. bail out std::cerr << "failed to create logfile '" << _logFile << "'. Please check the path and permissions." << std::endl; exit(EXIT_FAILURE); } } #ifdef TRI_ENABLE_SYSLOG if (_logSyslog != "") { TRI_CreateLogAppenderSyslog(_logPrefix.c_str(), _logSyslog.c_str()); } #endif } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the command line options //////////////////////////////////////////////////////////////////////////////// ProgramOptions& ApplicationServer::programOptions () { return _options; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the command line arguments //////////////////////////////////////////////////////////////////////////////// vector ApplicationServer::programArguments () { return _arguments; } //////////////////////////////////////////////////////////////////////////////// /// @brief parses the arguments with empty options description //////////////////////////////////////////////////////////////////////////////// bool ApplicationServer::parse (int argc, char* argv[]) { map none; return parse(argc, argv, none); } //////////////////////////////////////////////////////////////////////////////// /// @brief parses the arguments //////////////////////////////////////////////////////////////////////////////// bool ApplicationServer::parse (int argc, char* argv[], std::map opts) { // ............................................................................. // setup the options // ............................................................................. setupOptions(opts); for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { (*i)->setupOptions(opts); } // construct options description for (map::iterator i = opts.begin(); i != opts.end(); ++i) { string name = i->first; ProgramOptionsDescription sectionDescription = i->second; sectionDescription.setName(name); // and add to the global options _description(sectionDescription, name == OPTIONS_HIDDEN); if (name != OPTIONS_CMDLINE) { _descriptionFile(sectionDescription, name == OPTIONS_HIDDEN); } } _description.arguments(&_arguments); // ............................................................................. // parse command line // ............................................................................. bool ok = _options.parse(_description, argc, argv); if (! ok) { cout << "cannot parse command line: " << _options.lastError() << endl; return false; } // check for help set help = _options.needHelp("help"); if (! help.empty()) { cout << argv[0] << " " << _title << "\n\n" << _description.usage(help) << endl; exit(EXIT_SUCCESS); } // check for version request if (_options.has("version")) { cout << _version << endl; exit(EXIT_SUCCESS); } // ............................................................................. // UID and GID // ............................................................................. storeRealPrivileges(); extractPrivileges(); dropPrivileges(); // ............................................................................. // setup logging // ............................................................................. setupLogging(); // ............................................................................. // parse phase 1 // ............................................................................. for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { ok = (*i)->parsePhase1(_options); if (! ok) { return false; } } // ............................................................................. // check configuration file // ............................................................................. ok = readConfigurationFile(); if (! ok) { return false; } // re-set logging using the additional config file entries setupLogging(); // ............................................................................. // parse phase 2 // ............................................................................. try { switch (_randomGenerator) { case 1: { Random::selectVersion(Random::RAND_MERSENNE); break; } case 2: { Random::selectVersion(Random::RAND_RANDOM); break; } case 3: { Random::selectVersion(Random::RAND_URANDOM); break; } case 4: { Random::selectVersion(Random::RAND_COMBINED); break; } case 5: { Random::selectVersion(Random::RAND_WIN32); break; } default: { break; } } } catch (...) { LOGGER_FATAL << "cannot select random generator, giving up"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { ok = (*i)->parsePhase2(_options); if (! ok) { return false; } } return true; } //////////////////////////////////////////////////////////////////////////////// /// @brief prepares the server //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::prepare () { // prepare all features - why reverse? // reason: features might depend on each other. by creating them in reverse order and shutting them // down in forward order, we ensure that the features created last are destroyed first, i.e.: LIFO for (vector::reverse_iterator i = _features.rbegin(); i != _features.rend(); ++i) { ApplicationFeature* feature = *i; LOGGER_DEBUG << "preparing server feature '" << feature->getName() << "'"; bool ok = feature->prepare(); if (! ok) { LOGGER_FATAL << "failed to prepare server feature '" << feature->getName() <<"'"; TRI_FlushLogging(); exit(EXIT_FAILURE); } LOGGER_TRACE << "prepared server feature '" << feature->getName() << "'"; } } //////////////////////////////////////////////////////////////////////////////// /// @brief prepares the server //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::prepare2 () { // prepare all features for (vector::reverse_iterator i = _features.rbegin(); i != _features.rend(); ++i) { ApplicationFeature* feature = *i; LOGGER_DEBUG << "preparing server feature '" << feature->getName() << "'"; bool ok = feature->prepare2(); if (! ok) { LOGGER_FATAL << "failed to prepare server feature '" << feature->getName() <<"'"; TRI_FlushLogging(); exit(EXIT_FAILURE); } LOGGER_TRACE << "prepared server feature '" << feature->getName() << "'"; } } //////////////////////////////////////////////////////////////////////////////// /// @brief starts the server //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::start () { LOGGER_DEBUG << "ApplicationServer version " << TRIAGENS_VERSION; #ifdef TRI_HAVE_POSIX_THREADS sigset_t all; sigfillset(&all); pthread_sigmask(SIG_SETMASK, &all, 0); #endif raisePrivileges(); // start all startable features for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { ApplicationFeature* feature = *i; bool ok = feature->start(); if (! ok) { LOGGER_FATAL << "failed to start server feature '" << feature->getName() <<"'"; TRI_FlushLogging(); exit(EXIT_FAILURE); } LOGGER_DEBUG << "started server feature '" << feature->getName() << "'"; } // now open all features for (vector::reverse_iterator i = _features.rbegin(); i != _features.rend(); ++i) { ApplicationFeature* feature = *i; LOGGER_DEBUG << "opening server feature '" << feature->getName() << "'"; bool ok = feature->open(); if (! ok) { LOGGER_FATAL << "failed to open server feature '" << feature->getName() <<"'"; TRI_FlushLogging(); exit(EXIT_FAILURE); } LOGGER_TRACE << "opened server feature '" << feature->getName() << "'"; } dropPrivilegesPermanently(); } //////////////////////////////////////////////////////////////////////////////// /// @brief waits for shutdown //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::wait () { bool running = true; // wait until we receive a stop signal while (running && _stopping == 0) { // check the parent and wait for a second if (! checkParent()) { running = false; break; } sleep(1); } } //////////////////////////////////////////////////////////////////////////////// /// @brief begins shutdown sequence //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::beginShutdown () { if (_stopping != 0) { return; } _stopping = 1; } //////////////////////////////////////////////////////////////////////////////// /// @brief stops everything //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::stop () { beginShutdown(); // close all features for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { ApplicationFeature* feature = *i; feature->close(); LOGGER_TRACE << "closed server feature '" << feature->getName() << "'"; } // stop all features for (vector::reverse_iterator i = _features.rbegin(); i != _features.rend(); ++i) { ApplicationFeature* feature = *i; LOGGER_DEBUG << "shutting down server feature '" << feature->getName() << "'"; feature->stop(); LOGGER_TRACE << "shut down server feature '" << feature->getName() << "'"; } } //////////////////////////////////////////////////////////////////////////////// /// @brief raise the privileges //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::raisePrivileges () { #ifdef TRI_HAVE_SETGID if (_effectiveGid != _realGid) { int res = setegid(_realGid); if (res != 0) { LOGGER_FATAL << "cannot set gid '" << _effectiveGid << "', because " << strerror(errno); TRI_ShutdownLogging(); exit(EXIT_FAILURE); } } #endif #ifdef TRI_HAVE_SETUID if (_effectiveUid != _realUid) { int res = seteuid(_realUid); if (res != 0) { LOGGER_FATAL << "cannot set uid '" << _uid << "', because " << strerror(errno); TRI_ShutdownLogging(); exit(EXIT_FAILURE); } } #endif } //////////////////////////////////////////////////////////////////////////////// /// @brief drops the privileges //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::dropPrivileges () { #ifdef TRI_HAVE_SETGID if (_effectiveGid != _realGid) { int res = setegid(_effectiveGid); if (res != 0) { LOGGER_FATAL << "cannot set gid '" << _effectiveGid << "', because " << strerror(errno); cerr << "cannot set gid '" << _effectiveGid << "', because " << strerror(errno) << endl; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } } #endif #ifdef TRI_HAVE_SETUID if (_effectiveUid != _realUid) { int res = seteuid(_effectiveUid); if (res != 0) { LOGGER_FATAL << "cannot set uid '" << _uid << "', because " << strerror(errno); cerr << "cannot set uid '" << _uid << "', because " << strerror(errno) << endl; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } } #endif } //////////////////////////////////////////////////////////////////////////////// /// @brief drops the privileges permanently //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::dropPrivilegesPermanently () { raisePrivileges(); #ifdef TRI_HAVE_SETGID if (_effectiveGid != _realGid) { LOGGER_INFO << "permanently changing the gid to '" << _effectiveGid << "'"; int res = setgid(_effectiveGid); if (res != 0) { LOGGER_FATAL << "cannot set gid '" << _effectiveGid << "', because " << strerror(errno); cerr << "cannot set gid '" << _effectiveGid << "', because " << strerror(errno) << endl; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } _realGid = _effectiveGid; } #endif #ifdef TRI_HAVE_SETUID if (_effectiveUid != _realUid) { LOGGER_INFO << "permanently changing the uid to '" << _effectiveUid << "'"; int res = setuid(_effectiveUid); if (res != 0) { LOGGER_FATAL << "cannot set uid '" << _uid << "', because " << strerror(errno); cerr << "cannot set uid '" << _uid << "', because " << strerror(errno) << endl; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } _realUid = _effectiveUid; } #endif } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- protected methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ApplicationServer /// @{ //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::setupOptions (map& options) { // ............................................................................. // command line options // ............................................................................. options[OPTIONS_CMDLINE] ("version,v", "print version string and exit") ("help,h", "produce a usage message and exit") ("configuration,c", &_configFile, "read configuration file") ; #if defined(TRI_HAVE_SETUID) || defined(TRI_HAVE_SETGID) options[OPTIONS_CMDLINE + ":help-extended"] #ifdef TRI_HAVE_SETUID ("uid", &_uid, "switch to user-id after reading config files") #endif #ifdef TRI_HAVE_SETGID ("gid", &_gid, "switch to group-id after reading config files") #endif #ifdef TRI_HAVE_GETPPID ("exit-on-parent-death", &_exitOnParentDeath, "exit if parent dies") #endif ("watch-process", &_watchParent, "exit if process with given PID dies") ; #endif // ............................................................................. // logger options // ............................................................................. options[OPTIONS_LOGGER] ("log.file", &_logFile, "log to file") ("log.level,l", &_logLevel, "log level for severity 'human'") ; options[OPTIONS_LOGGER + ":help-log"] ("log.application", &_logApplicationName, "application name") ("log.facility", &_logFacility, "facility name") ("log.filter", &_logFilter, "filter for debug and trace") ("log.format", &_logFormat, "log format") ("log.hostname", &_logHostName, "host name") ("log.line-number", "always log file and line number") ("log.prefix", &_logPrefix, "prefix log") ("log.severity", &_logSeverity, "log severities") ("log.syslog", &_logSyslog, "use syslog facility") ("log.thread", "log the thread identifier for severity 'human'") ; options[OPTIONS_HIDDEN] ("log", &_logLevel, "log level for severity 'human'") ; // ............................................................................. // application server options // ............................................................................. options[OPTIONS_SERVER + ":help-extended"] ("random.no-seed", "do not seed the random generator") ("random.generator", &_randomGenerator, "1 = mersenne, 2 = random, 3 = urandom, 4 = combined") ; } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ApplicationServer /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief checks if the parent is still alive //////////////////////////////////////////////////////////////////////////////// bool ApplicationServer::checkParent () { // check our parent, if it died given up #ifdef TRI_HAVE_GETPPID if (_exitOnParentDeath && getppid() == 1) { LOGGER_INFO << "parent has died"; return false; } #endif // unfortunately even though windows has , there is no // kill method defined. Notice that the kill below is not to terminate // the process. #ifdef TRI_HAVE_SIGNAL_H if (_watchParent != 0) { #ifdef TRI_HAVE_POSIX int res = kill(_watchParent, 0); #else int res = -1; #endif if (res != 0) { LOGGER_INFO << "parent " << _watchParent << " has died"; return false; } } #endif return true; } //////////////////////////////////////////////////////////////////////////////// /// @brief reads the configuration files //////////////////////////////////////////////////////////////////////////////// bool ApplicationServer::readConfigurationFile () { // something has been specified on the command line regarding configuration file if (! _configFile.empty()) { // do not use init files if (StringUtils::tolower(_configFile) == string("none")) { LOGGER_INFO << "using no init file at all"; return true; } LOGGER_INFO << "using init file '" << _configFile << "'"; bool ok = _options.parse(_descriptionFile, _configFile); // Observe that this is treated as an error - the configuration file exists // but for some reason can not be parsed. Best to report an error. if (! ok) { cout << "cannot parse config file '" << _configFile << "': " << _options.lastError() << endl; } return ok; } else { LOGGER_DEBUG << "no init file has been specified"; } // nothing has been specified on the command line regarding the user's configuration file if (! _userConfigFile.empty()) { // ......................................................................... // first attempt to obtain a default configuration file from the users home directory // ......................................................................... // ......................................................................... // Under windows there is no 'HOME' directory as such so getenv("HOME") // may return NULL -- which it does under windows // A safer approach below // ......................................................................... string homeDir; string homeEnv; const char* envResult; #ifdef _WIN32 string homeDrive; string homePath; homeEnv = string("%HOMEDRIVE% and/or %HOMEPATH%"); envResult = getenv("HOMEDRIVE"); if (envResult != 0) { homeDrive = string(envResult); } envResult = getenv("HOMEPATH"); if (envResult != 0) { homePath = string(envResult); } if (! homeDrive.empty() && ! homePath.empty()) { homeDir = homeDrive + homePath; } else { homeDir = string(""); } #else homeEnv = string("$HOME"); envResult = getenv("HOME"); if (envResult != 0) { homeDir = string(envResult); } else { homeDir = string(""); } #endif if (! homeDir.empty()) { if (homeDir[homeDir.size() - 1] != TRI_DIR_SEPARATOR_CHAR) { homeDir += TRI_DIR_SEPARATOR_CHAR + _userConfigFile; } else { homeDir += _userConfigFile; } // check and see if file exists if (FileUtils::exists(homeDir)) { LOGGER_INFO << "using user init file '" << homeDir << "'"; bool ok = _options.parse(_descriptionFile, homeDir); // Observe that this is treated as an error - the configuration file exists // but for some reason can not be parsed. Best to report an error. if (! ok) { cout << "cannot parse config file '" << homeDir << "': " << _options.lastError() << endl; } return ok; } else { LOGGER_INFO << "no user init file '" << homeDir << "' found"; } } else { LOGGER_DEBUG << "no user init file, " << homeEnv << " is empty"; } } if (_systemConfigPath.empty()) { #ifdef _SYSCONFDIR_ // try the configuration file in the system directory - if there is one // Please note that the system directory changes depending on // where the user installed the application server. if (! _systemConfigFile.empty()) { string sysDir = string(_SYSCONFDIR_); if (! sysDir.empty()) { if (sysDir[sysDir.size() - 1] != '/') { sysDir += "/" + _systemConfigFile; } else { sysDir += _systemConfigFile; } // check and see if file exists if (FileUtils::exists(sysDir)) { LOGGER_INFO << "using init file '" << sysDir << "'"; bool ok = _options.parse(_descriptionFile, sysDir); // Observe that this is treated as an error - the configuration file exists // but for some reason can not be parsed. Best to report an error. if (! ok) { cout << "cannot parse config file '" << sysDir << "': " << _options.lastError() << endl; } return ok; } else { LOGGER_INFO << "no system init file '" << sysDir << "' found"; } } else { LOGGER_DEBUG << "no system init file, not system directory is known"; } } #endif } else { if (! _systemConfigFile.empty()) { string sysDir = _systemConfigPath + "/" + _systemConfigFile; // check and see if file exists if (FileUtils::exists(sysDir)) { LOGGER_INFO << "using init file '" << sysDir << "'"; bool ok = _options.parse(_descriptionFile, sysDir); // Observe that this is treated as an error - the configuration file exists // but for some reason can not be parsed. Best to report an error. if (! ok) { cout << "cannot parse config file '" << sysDir << "': " << _options.lastError() << endl; } return ok; } else { LOGGER_INFO << "no system init file '" << sysDir << "' found"; } } else { LOGGER_DEBUG << "no system init file specified"; } } return true; } //////////////////////////////////////////////////////////////////////////////// /// @brief extract the privileges to use //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::extractPrivileges() { #ifdef TRI_HAVE_SETGID if (_gid.empty()) { _effectiveGid = getgid(); } else { int gidNumber = TRI_Int32String(_gid.c_str()); if (TRI_errno() == TRI_ERROR_NO_ERROR) { #ifdef TRI_HAVE_GETGRGID group* g = getgrgid(gidNumber); if (g == 0) { cerr << "unknown numeric gid '" << _gid << "'" << endl; LOGGER_FATAL << "unknown numeric gid '" << _gid << "'"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } #endif } else { #ifdef TRI_HAVE_GETGRNAM string name = _gid; group* g = getgrnam(name.c_str()); if (g != 0) { gidNumber = g->gr_gid; } else { cerr << "cannot convert groupname '" << _gid << "' to numeric gid" << endl; LOGGER_FATAL << "cannot convert groupname '" << _gid << "' to numeric gid"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } #else cerr << "cannot convert groupname '" << _gid << "' to numeric gid" << endl; LOGGER_FATAL << "cannot convert groupname '" << _gid << "' to numeric gid"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); #endif } _effectiveGid = gidNumber; } #endif #ifdef TRI_HAVE_SETUID if (_uid.empty()) { _effectiveUid = getuid(); } else { int uidNumber = TRI_Int32String(_uid.c_str()); if (TRI_errno() == TRI_ERROR_NO_ERROR) { #ifdef TRI_HAVE_GETPWUID passwd* p = getpwuid(uidNumber); if (p == 0) { cerr << "unknown numeric uid '" << _uid << "'" << endl; LOGGER_FATAL << "unknown numeric uid '" << _uid << "'"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } #endif } else { #ifdef TRI_HAVE_GETPWNAM string name = _uid; passwd* p = getpwnam(name.c_str()); if (p != 0) { uidNumber = p->pw_uid; } else { cerr << "cannot convert username '" << _uid << "' to numeric uid" << endl; LOGGER_FATAL << "cannot convert username '" << _uid << "' to numeric uid"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); } #else cerr << "cannot convert username '" << _uid << "' to numeric uid" << endl; LOGGER_FATAL << "cannot convert username '" << _uid << "' to numeric uid"; TRI_ShutdownLogging(); exit(EXIT_FAILURE); #endif } _effectiveUid = uidNumber; } #endif } //////////////////////////////////////////////////////////////////////////////// /// @brief saves the logging privileges //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::storeRealPrivileges () { #ifdef TRI_HAVE_SETGID _realGid = getgid(); #endif #ifdef TRI_HAVE_SETUID _realUid = getuid(); #endif } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- // Local Variables: // mode: outline-minor // outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)" // End: