mirror of https://github.com/Icinga/icinga2.git
parent
a68bfea737
commit
a4081f1445
|
@ -53,7 +53,7 @@ check_run () {
|
|||
}
|
||||
|
||||
check_config () {
|
||||
$DAEMON --validate -u "$DAEMON_USER" -g "$DAEMON_GROUP" -c "$DAEMON_CONFIG"
|
||||
$DAEMON run --validate -u "$DAEMON_USER" -g "$DAEMON_GROUP" -c "$DAEMON_CONFIG"
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -69,7 +69,7 @@ do_start()
|
|||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
-c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" -d $DAEMON_ARGS \
|
||||
run -c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" -d $DAEMON_ARGS \
|
||||
|| return 2
|
||||
# Add code here, if necessary, that waits for the process to be ready
|
||||
# to handle requests from services started subsequently which depend
|
||||
|
@ -84,7 +84,7 @@ do_foreground()
|
|||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test \
|
||||
|| return 1
|
||||
start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
-c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" $DAEMON_ARGS \
|
||||
run -c "$DAEMON_CONFIG" -u "$DAEMON_USER" -g "$DAEMON_GROUP" $DAEMON_ARGS \
|
||||
|| return 2
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
debian/config/apt.conf etc/icinga2/conf.d/hosts/localhost
|
||||
debian/tmp/etc/icinga2
|
||||
debian/tmp/etc/logrotate.d
|
||||
debian/tmp/etc/bash_completion.d
|
||||
tools/syntax/* usr/share/icinga2-common/syntax
|
||||
usr/bin/icinga2-build*
|
||||
usr/bin/icinga2-sign-key
|
||||
|
|
|
@ -68,6 +68,11 @@ if(NOT WIN32)
|
|||
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/checker.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/checker.conf\")")
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/notification.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/notification.conf\")")
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/mainlog.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/mainlog.conf\")")
|
||||
|
||||
install(
|
||||
FILES bash_completion.d/icinga2
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/bash_completion.d
|
||||
)
|
||||
else()
|
||||
install(
|
||||
FILES icinga2/features-enabled/checker.conf icinga2/features-enabled/notification.conf
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
_icinga2()
|
||||
{
|
||||
local cur opts
|
||||
opts="${COMP_WORDS[*]}"
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(icinga2 --autocomplete ${COMP_WORDS[*]:1} < /dev/null))
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _icinga2 icinga2
|
||||
|
|
@ -48,7 +48,7 @@ start() {
|
|||
printf "Starting Icinga 2: "
|
||||
@CMAKE_INSTALL_FULL_SBINDIR@/icinga2-prepare-dirs $SYSCONFIGFILE
|
||||
|
||||
if ! $DAEMON -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
|
||||
if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
|
||||
echo "Error starting Icinga. Check '$ICINGA2_STARTUP_LOG' for details."
|
||||
exit 1
|
||||
else
|
||||
|
@ -111,7 +111,7 @@ reload() {
|
|||
checkconfig() {
|
||||
printf "Checking configuration: "
|
||||
|
||||
if ! $DAEMON -c $ICINGA2_CONFIG_FILE -C -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
|
||||
if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C -u $ICINGA2_USER -g $ICINGA2_GROUP > $ICINGA2_STARTUP_LOG 2>&1; then
|
||||
if [ "x$1" = "x" ]; then
|
||||
cat $ICINGA2_STARTUP_LOG
|
||||
echo "Icinga 2 detected configuration errors. Check '$ICINGA2_STARTUP_LOG' for details."
|
||||
|
|
|
@ -6,7 +6,7 @@ After=syslog.target postgresql.service mariadb.service carbon-cache.service
|
|||
Type=forking
|
||||
EnvironmentFile=@ICINGA2_SYSCONFIGFILE@
|
||||
ExecStartPre=@CMAKE_INSTALL_FULL_SBINDIR@/icinga2-prepare-dirs @ICINGA2_SYSCONFIGFILE@
|
||||
ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/icinga2 -c ${ICINGA2_CONFIG_FILE} -d -e ${ICINGA2_ERROR_LOG} -u ${ICINGA2_USER} -g ${ICINGA2_GROUP}
|
||||
ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/icinga2 daemon -c ${ICINGA2_CONFIG_FILE} -d -e ${ICINGA2_ERROR_LOG} -u ${ICINGA2_USER} -g ${ICINGA2_GROUP}
|
||||
PIDFile=@ICINGA2_RUNDIR@/icinga2/icinga2.pid
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
|
|
|
@ -28,249 +28,20 @@
|
|||
#include "base/convert.hpp"
|
||||
#include "base/scriptvariable.hpp"
|
||||
#include "base/context.hpp"
|
||||
#include "base/clicommand.hpp"
|
||||
#include "config.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/types.h>
|
||||
# include <pwd.h>
|
||||
# include <grp.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
using namespace icinga;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
static po::variables_map g_AppParams;
|
||||
|
||||
#ifdef _WIN32
|
||||
SERVICE_STATUS l_SvcStatus;
|
||||
SERVICE_STATUS_HANDLE l_SvcStatusHandle;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static String LoadAppType(const String& typeSpec)
|
||||
{
|
||||
Log(LogInformation, "icinga-app", "Loading application type: " + typeSpec);
|
||||
|
||||
String::SizeType index = typeSpec.FindFirstOf('/');
|
||||
|
||||
if (index == String::NPos)
|
||||
return typeSpec;
|
||||
|
||||
String library = typeSpec.SubStr(0, index);
|
||||
|
||||
(void) Utility::LoadExtensionLibrary(library);
|
||||
|
||||
return typeSpec.SubStr(index + 1);
|
||||
}
|
||||
|
||||
static void IncludeZoneDirRecursive(const String& path)
|
||||
{
|
||||
String zoneName = Utility::BaseName(path);
|
||||
Utility::GlobRecursive(path, "*.conf", boost::bind(&ConfigCompiler::CompileFile, _1, zoneName), GlobFile);
|
||||
}
|
||||
|
||||
static void IncludeNonLocalZone(const String& zonePath)
|
||||
{
|
||||
String etcPath = Application::GetZonesDir() + "/" + Utility::BaseName(zonePath);
|
||||
|
||||
if (Utility::PathExists(etcPath))
|
||||
return;
|
||||
|
||||
IncludeZoneDirRecursive(zonePath);
|
||||
}
|
||||
|
||||
static bool LoadConfigFiles(const String& appType, const String& objectsFile = String())
|
||||
{
|
||||
ConfigCompilerContext::GetInstance()->Reset();
|
||||
|
||||
if (g_AppParams.count("config") > 0) {
|
||||
BOOST_FOREACH(const String& configPath, g_AppParams["config"].as<std::vector<std::string> >()) {
|
||||
ConfigCompiler::CompileFile(configPath);
|
||||
}
|
||||
} else if (!g_AppParams.count("no-config"))
|
||||
ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
|
||||
|
||||
/* Load cluster config files - this should probably be in libremote but
|
||||
* unfortunately moving it there is somewhat non-trivial. */
|
||||
String zonesEtcDir = Application::GetZonesDir();
|
||||
if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir))
|
||||
Utility::Glob(zonesEtcDir + "/*", &IncludeZoneDirRecursive, GlobDirectory);
|
||||
|
||||
String zonesVarDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
|
||||
if (Utility::PathExists(zonesVarDir))
|
||||
Utility::Glob(zonesVarDir + "/*", &IncludeNonLocalZone, GlobDirectory);
|
||||
|
||||
String name, fragment;
|
||||
BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
|
||||
ConfigCompiler::CompileText(name, fragment);
|
||||
}
|
||||
|
||||
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>();
|
||||
builder->SetType(appType);
|
||||
builder->SetName("application");
|
||||
ConfigItem::Ptr item = builder->Compile();
|
||||
item->Register();
|
||||
|
||||
bool result = ConfigItem::ValidateItems(objectsFile);
|
||||
|
||||
int warnings = 0, errors = 0;
|
||||
|
||||
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
|
||||
std::ostringstream locbuf;
|
||||
ShowCodeFragment(locbuf, message.Location, true);
|
||||
String location = locbuf.str();
|
||||
|
||||
String logmsg;
|
||||
|
||||
if (!location.IsEmpty())
|
||||
logmsg = "Location:\n" + location;
|
||||
|
||||
logmsg += String("\nConfig ") + (message.Error ? "error" : "warning") + ": " + message.Text;
|
||||
|
||||
if (message.Error) {
|
||||
Log(LogCritical, "config", logmsg);
|
||||
errors++;
|
||||
} else {
|
||||
Log(LogWarning, "config", logmsg);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings > 0 || errors > 0) {
|
||||
LogSeverity severity;
|
||||
|
||||
if (errors == 0)
|
||||
severity = LogWarning;
|
||||
else
|
||||
severity = LogCritical;
|
||||
|
||||
Log(severity, "config", Convert::ToString(errors) + " errors, " + Convert::ToString(warnings) + " warnings.");
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static void SigHupHandler(int)
|
||||
{
|
||||
Application::RequestRestart();
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static bool Daemonize(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
// systemd requires that the pidfile of the daemon is written before the forking
|
||||
// process terminates. So wait till either the forked daemon has written a pidfile or died.
|
||||
|
||||
int status;
|
||||
int ret;
|
||||
pid_t readpid;
|
||||
do {
|
||||
Utility::Sleep(0.1);
|
||||
|
||||
readpid = Application::ReadPidFile(Application::GetPidPath());
|
||||
ret = waitpid(pid, &status, WNOHANG);
|
||||
} while (readpid != pid && ret == 0);
|
||||
|
||||
if (ret == pid) {
|
||||
Log(LogCritical, "icinga-app", "The daemon could not be started. See log output for details.");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (ret == -1) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "waitpid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetDaemonIO(const String& stderrFile)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
int fdnull = open("/dev/null", O_RDWR);
|
||||
if (fdnull >= 0) {
|
||||
if (fdnull != 0)
|
||||
dup2(fdnull, 0);
|
||||
|
||||
if (fdnull != 1)
|
||||
dup2(fdnull, 1);
|
||||
|
||||
if (fdnull > 1)
|
||||
close(fdnull);
|
||||
}
|
||||
|
||||
const char *errPath = "/dev/null";
|
||||
|
||||
if (!stderrFile.IsEmpty())
|
||||
errPath = stderrFile.CStr();
|
||||
|
||||
int fderr = open(errPath, O_WRONLY | O_APPEND);
|
||||
|
||||
if (fderr < 0 && errno == ENOENT)
|
||||
fderr = open(errPath, O_CREAT | O_WRONLY | O_APPEND, 0600);
|
||||
|
||||
if (fderr > 0) {
|
||||
if (fderr != 2)
|
||||
dup2(fderr, 2);
|
||||
|
||||
if (fderr > 2)
|
||||
close(fderr);
|
||||
}
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid == -1) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate another process and wait till it has ended
|
||||
*
|
||||
* @params target PID of the process to end
|
||||
*/
|
||||
static void TerminateAndWaitForEnd(pid_t target)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// allow 30 seconds timeout
|
||||
double timeout = Utility::GetTime() + 30;
|
||||
|
||||
int ret = kill(target, SIGTERM);
|
||||
|
||||
while (Utility::GetTime() < timeout && (ret == 0 || errno != ESRCH)) {
|
||||
Utility::Sleep(0.1);
|
||||
ret = kill(target, 0);
|
||||
}
|
||||
|
||||
// timeout and the process still seems to live: kill it
|
||||
if (ret == 0 || errno != ESRCH)
|
||||
kill(target, SIGKILL);
|
||||
|
||||
#else
|
||||
// TODO: implement this for Win32
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
|
||||
int Main(void)
|
||||
{
|
||||
int argc = Application::GetArgC();
|
||||
|
@ -329,46 +100,39 @@ int Main(void)
|
|||
Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d");
|
||||
Application::DeclareApplicationType("icinga/IcingaApplication");
|
||||
|
||||
po::options_description desc("Supported options");
|
||||
LogSeverity logLevel = Logger::GetConsoleLogSeverity();
|
||||
Logger::SetConsoleLogSeverity(LogWarning);
|
||||
|
||||
Utility::LoadExtensionLibrary("cli");
|
||||
|
||||
po::options_description desc("Global options");
|
||||
|
||||
desc.add_options()
|
||||
("help", "show this help message")
|
||||
("version,V", "show version information")
|
||||
("define,D", po::value<std::vector<std::string> >(), "define a constant")
|
||||
("library,l", po::value<std::vector<std::string> >(), "load a library")
|
||||
("include,I", po::value<std::vector<std::string> >(), "add include search directory")
|
||||
("define,D", po::value<std::vector<std::string> >(), "define a constant")
|
||||
("config,c", po::value<std::vector<std::string> >(), "parse a configuration file")
|
||||
("no-config,z", "start without a configuration file")
|
||||
("validate,C", "exit after validating the configuration")
|
||||
("log-level,x", po::value<std::string>(), "specify the log level for the console log")
|
||||
("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)")
|
||||
#ifndef _WIN32
|
||||
("reload-internal", po::value<int>(), "used internally to implement config reload: do not call manually, send SIGHUP instead")
|
||||
("daemonize,d", "detach from the controlling terminal")
|
||||
("user,u", po::value<std::string>(), "user to run Icinga as")
|
||||
("group,g", po::value<std::string>(), "group to run Icinga as")
|
||||
# ifdef RLIMIT_STACK
|
||||
("no-stack-rlimit", "don't attempt to set RLIMIT_STACK")
|
||||
# endif /* RLIMIT_STACK */
|
||||
#else /* _WIN32 */
|
||||
("scm", "run as a Windows service (must be the first argument if specified)")
|
||||
("scm-install", "installs Icinga 2 as a Windows service (must be the first argument if specified")
|
||||
("scm-uninstall", "uninstalls the Icinga 2 Windows service (must be the first argument if specified")
|
||||
#endif /* _WIN32 */
|
||||
;
|
||||
("no-stack-rlimit", "used internally, do not specify manually")
|
||||
("autocomplete", "auto-complete arguments");
|
||||
|
||||
String cmdname;
|
||||
CLICommand::Ptr command;
|
||||
bool autocomplete;
|
||||
po::variables_map vm;
|
||||
|
||||
try {
|
||||
po::store(po::parse_command_line(argc, argv, desc), g_AppParams);
|
||||
CLICommand::ParseCommand(argc, argv, desc, vm, cmdname, command, autocomplete);
|
||||
} catch (const std::exception& ex) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Error while parsing command-line options: " << ex.what();
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
Log(LogCritical, "cli_daemon", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
po::notify(g_AppParams);
|
||||
|
||||
if (g_AppParams.count("define")) {
|
||||
BOOST_FOREACH(const String& define, g_AppParams["define"].as<std::vector<std::string> >()) {
|
||||
if (vm.count("define")) {
|
||||
BOOST_FOREACH(const String& define, vm["define"].as<std::vector<std::string> >()) {
|
||||
String key, value;
|
||||
size_t pos = define.FindFirstOf('=');
|
||||
if (pos != String::NPos) {
|
||||
|
@ -386,209 +150,104 @@ int Main(void)
|
|||
Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.debug");
|
||||
Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid");
|
||||
|
||||
#ifndef _WIN32
|
||||
if (g_AppParams.count("group")) {
|
||||
String group = g_AppParams["group"].as<std::string>();
|
||||
|
||||
errno = 0;
|
||||
struct group *gr = getgrnam(group.CStr());
|
||||
|
||||
if (!gr) {
|
||||
if (errno == 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Invalid group specified: " + group;
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_AppParams.count("reload-internal") && setgroups(0, NULL) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (setgid(gr->gr_gid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_AppParams.count("user")) {
|
||||
String user = g_AppParams["user"].as<std::string>();
|
||||
|
||||
errno = 0;
|
||||
struct passwd *pw = getpwnam(user.CStr());
|
||||
|
||||
if (!pw) {
|
||||
if (errno == 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Invalid user specified: " + user;
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// also activate the additional groups the configured user is member of
|
||||
if (!g_AppParams.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (setuid(pw->pw_uid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "icinga-app", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (g_AppParams.count("log-level")) {
|
||||
String severity = g_AppParams["log-level"].as<std::string>();
|
||||
|
||||
LogSeverity logLevel = LogInformation;
|
||||
try {
|
||||
logLevel = Logger::StringToSeverity(severity);
|
||||
} catch (std::exception&) {
|
||||
/* use the default */
|
||||
Log(LogWarning, "icinga", "Invalid log level set. Using default 'information'.");
|
||||
}
|
||||
|
||||
Logger::SetConsoleLogSeverity(logLevel);
|
||||
}
|
||||
|
||||
if (g_AppParams.count("help") || g_AppParams.count("version")) {
|
||||
String appName = Utility::BaseName(argv[0]);
|
||||
|
||||
if (appName.GetLength() > 3 && appName.SubStr(0, 3) == "lt-")
|
||||
appName = appName.SubStr(3, appName.GetLength() - 3);
|
||||
|
||||
std::cout << appName << " " << "- The Icinga 2 network monitoring daemon.";
|
||||
|
||||
if (g_AppParams.count("version")) {
|
||||
std::cout << " (Version: " << Application::GetVersion() << ")";
|
||||
std::cout << std::endl
|
||||
<< "Copyright (c) 2012-2014 Icinga Development Team (http://www.icinga.org)" << std::endl
|
||||
<< "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl2.html>" << std::endl
|
||||
<< "This is free software: you are free to change and redistribute it." << std::endl
|
||||
<< "There is NO WARRANTY, to the extent permitted by law.";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
if (g_AppParams.count("version")) {
|
||||
std::cout << std::endl;
|
||||
|
||||
Application::DisplayInfoMessage(true);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_AppParams.count("help")) {
|
||||
std::cout << std::endl
|
||||
<< desc << std::endl
|
||||
<< "Report bugs at <https://dev.icinga.org/>" << std::endl
|
||||
<< "Icinga home page: <http://www.icinga.org/>" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
ScriptVariable::Set("UseVfork", true, false, true);
|
||||
|
||||
Application::MakeVariablesConstant();
|
||||
|
||||
Log(LogInformation, "icinga-app", "Icinga application loader (version: " + Application::GetVersion() + ")");
|
||||
|
||||
String appType = LoadAppType(Application::GetApplicationType());
|
||||
|
||||
if (g_AppParams.count("library")) {
|
||||
BOOST_FOREACH(const String& libraryName, g_AppParams["library"].as<std::vector<std::string> >()) {
|
||||
(void)Utility::LoadExtensionLibrary(libraryName);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigCompiler::AddIncludeSearchDir(Application::GetIncludeConfDir());
|
||||
|
||||
if (g_AppParams.count("include")) {
|
||||
BOOST_FOREACH(const String& includePath, g_AppParams["include"].as<std::vector<std::string> >()) {
|
||||
if (!autocomplete && vm.count("include")) {
|
||||
BOOST_FOREACH(const String& includePath, vm["include"].as<std::vector<std::string> >()) {
|
||||
ConfigCompiler::AddIncludeSearchDir(includePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_AppParams.count("validate") && !g_AppParams.count("reload-internal")) {
|
||||
pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
|
||||
if (runningpid > 0) {
|
||||
Log(LogCritical, "icinga-app", "Another instance of Icinga already running with PID " + Convert::ToString(runningpid));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
Logger::SetConsoleLogSeverity(logLevel);
|
||||
|
||||
if (!LoadConfigFiles(appType, Application::GetObjectsPath()))
|
||||
return EXIT_FAILURE;
|
||||
if (!autocomplete) {
|
||||
if (vm.count("log-level")) {
|
||||
String severity = vm["log-level"].as<std::string>();
|
||||
|
||||
if (g_AppParams.count("validate")) {
|
||||
Log(LogInformation, "icinga-app", "Finished validating the configuration file(s).");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if(g_AppParams.count("reload-internal")) {
|
||||
int parentpid = g_AppParams["reload-internal"].as<int>();
|
||||
Log(LogInformation, "icinga-app", "Terminating previous instance of Icinga (PID " + Convert::ToString(parentpid) + ")");
|
||||
TerminateAndWaitForEnd(parentpid);
|
||||
Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now.");
|
||||
}
|
||||
|
||||
if (g_AppParams.count("daemonize")) {
|
||||
if (!g_AppParams.count("reload-internal")) {
|
||||
// no additional fork neccessary on reload
|
||||
LogSeverity logLevel = LogInformation;
|
||||
try {
|
||||
Daemonize();
|
||||
logLevel = Logger::StringToSeverity(severity);
|
||||
} catch (std::exception&) {
|
||||
Log(LogCritical, "icinga-app", "Daemonize failed. Exiting.");
|
||||
return EXIT_FAILURE;
|
||||
/* use the default */
|
||||
Log(LogWarning, "icinga", "Invalid log level set. Using default 'information'.");
|
||||
}
|
||||
|
||||
Logger::SetConsoleLogSeverity(logLevel);
|
||||
}
|
||||
|
||||
if (vm.count("library")) {
|
||||
BOOST_FOREACH(const String& libraryName, vm["library"].as<std::vector<std::string> >()) {
|
||||
(void)Utility::LoadExtensionLibrary(libraryName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!command || vm.count("help") || vm.count("version")) {
|
||||
String appName = Utility::BaseName(Application::GetArgV()[0]);
|
||||
|
||||
if (appName.GetLength() > 3 && appName.SubStr(0, 3) == "lt-")
|
||||
appName = appName.SubStr(3, appName.GetLength() - 3);
|
||||
|
||||
std::cout << appName << " " << "- The Icinga 2 network monitoring daemon.";
|
||||
|
||||
if (!command || vm.count("help")) {
|
||||
std::cout << std::endl << std::endl
|
||||
<< "Usage:" << std::endl
|
||||
<< " " << argv[0] << " ";
|
||||
|
||||
if (cmdname.IsEmpty())
|
||||
std::cout << "<command>";
|
||||
else
|
||||
std::cout << cmdname;
|
||||
|
||||
std::cout << " [<arguments>]";
|
||||
|
||||
if (command) {
|
||||
std::cout << std::endl << std::endl
|
||||
<< command->GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.count("version")) {
|
||||
std::cout << " (Version: " << Application::GetVersion() << ")";
|
||||
std::cout << std::endl
|
||||
<< "Copyright (c) 2012-2014 Icinga Development Team (http://www.icinga.org)" << std::endl
|
||||
<< "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl2.html>" << std::endl
|
||||
<< "This is free software: you are free to change and redistribute it." << std::endl
|
||||
<< "There is NO WARRANTY, to the extent permitted by law.";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
if (vm.count("version")) {
|
||||
std::cout << std::endl;
|
||||
|
||||
Application::DisplayInfoMessage(true);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!command || vm.count("help")) {
|
||||
if (!command) {
|
||||
std::cout << std::endl;
|
||||
CLICommand::ShowCommands(argc, argv, NULL, false);
|
||||
}
|
||||
|
||||
std::cout << std::endl
|
||||
<< desc << std::endl
|
||||
<< "Report bugs at <https://dev.icinga.org/>" << std::endl
|
||||
<< "Icinga home page: <http://www.icinga.org/>" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// activate config only after daemonization: it starts threads and that is not compatible with fork()
|
||||
if (!ConfigItem::ActivateItems()) {
|
||||
Log(LogCritical, "icinga-app", "Error activating configuration.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int rc = 1;
|
||||
|
||||
if (g_AppParams.count("daemonize")) {
|
||||
String errorLog;
|
||||
if (g_AppParams.count("errorlog"))
|
||||
errorLog = g_AppParams["errorlog"].as<std::string>();
|
||||
|
||||
SetDaemonIO(errorLog);
|
||||
Logger::DisableConsoleLog();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = &SigHupHandler;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
int rc = Application::GetInstance()->Run();
|
||||
if (autocomplete) {
|
||||
CLICommand::ShowCommands(argc, argv, &desc, true);
|
||||
rc = 0;
|
||||
} else if (command)
|
||||
rc = command->Run(vm);
|
||||
|
||||
#ifndef _DEBUG
|
||||
Application::Exit(rc);
|
||||
|
|
|
@ -506,6 +506,7 @@ exit 0
|
|||
%doc COPYING COPYING.Exceptions README.md NEWS AUTHORS ChangeLog tools/syntax
|
||||
%attr(0750,%{icinga_user},%{icingacmd_group}) %dir %{_localstatedir}/log/%{name}
|
||||
%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
|
||||
%{_sysconfdir}/bash_completion.d/%{name}
|
||||
%attr(0750,%{icinga_user},%{icinga_group}) %dir %{_localstatedir}/spool/%{name}
|
||||
%attr(0750,%{icinga_user},%{icinga_group}) %dir %{_localstatedir}/spool/%{name}/perfdata
|
||||
%attr(0750,%{icinga_user},%{icinga_group}) %dir %{_localstatedir}/spool/%{name}/tmp
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(cli)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(icinga)
|
||||
add_subdirectory(db_ido)
|
||||
|
|
|
@ -23,7 +23,7 @@ mkclass_target(streamlogger.ti streamlogger.thpp)
|
|||
mkclass_target(sysloglogger.ti sysloglogger.thpp)
|
||||
|
||||
set(base_SOURCES
|
||||
application.cpp application.thpp array.cpp configerror.cpp context.cpp
|
||||
application.cpp application.thpp array.cpp clicommand.cpp configerror.cpp context.cpp
|
||||
convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
|
||||
exception.cpp fifo.cpp filelogger.cpp filelogger.thpp logger.cpp logger.thpp
|
||||
netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp
|
||||
|
|
|
@ -135,8 +135,10 @@ void Application::InitializeBase(void)
|
|||
maxfds = 65536;
|
||||
|
||||
for (rlim_t i = 3; i < maxfds; i++) {
|
||||
#ifdef _DEBUG
|
||||
if (close(i) >= 0)
|
||||
std::cerr << "Closed FD " << i << " which we inherited from our parent process." << std::endl;
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/clicommand.hpp"
|
||||
#include "base/logger_fwd.hpp"
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icinga;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
boost::mutex l_RegistryMutex;
|
||||
std::map<std::vector<String>, CLICommand::Ptr> l_Registry;
|
||||
|
||||
CLICommand::Ptr CLICommand::GetByName(const std::vector<String>& name)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_RegistryMutex);
|
||||
|
||||
std::map<std::vector<String>, CLICommand::Ptr>::const_iterator it = l_Registry.find(name);
|
||||
|
||||
if (it == l_Registry.end())
|
||||
return CLICommand::Ptr();
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void CLICommand::Register(const std::vector<String>& name, const CLICommand::Ptr& function)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_RegistryMutex);
|
||||
l_Registry[name] = function;
|
||||
}
|
||||
|
||||
void CLICommand::Unregister(const std::vector<String>& name)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_RegistryMutex);
|
||||
l_Registry.erase(name);
|
||||
}
|
||||
|
||||
RegisterCLICommandHelper::RegisterCLICommandHelper(const String& name, const CLICommand::Ptr& command)
|
||||
{
|
||||
std::vector<String> vname;
|
||||
boost::algorithm::split(vname, name, boost::is_any_of("/"));
|
||||
CLICommand::Register(vname, command);
|
||||
}
|
||||
|
||||
bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& desc, po::variables_map& vm,
|
||||
String& cmdname, CLICommand::Ptr& command, bool& autocomplete)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_RegistryMutex);
|
||||
|
||||
typedef std::map<std::vector<String>, CLICommand::Ptr>::value_type CLIKeyValue;
|
||||
|
||||
std::vector<String> best_match;
|
||||
int arg_end = 1;
|
||||
|
||||
BOOST_FOREACH(const CLIKeyValue& kv, l_Registry) {
|
||||
const std::vector<String>& vname = kv.first;
|
||||
|
||||
for (int i = 0, k = 1; i < vname.size() && k < argc; i++, k++) {
|
||||
if (strcmp(argv[k], "--no-stack-rlimit") == 0 || strcmp(argv[k], "--autocomplete") == 0) {
|
||||
if (strcmp(argv[k], "--autocomplete") == 0) {
|
||||
autocomplete = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vname[i] != argv[k])
|
||||
break;
|
||||
|
||||
if (i >= best_match.size())
|
||||
best_match.push_back(vname[i]);
|
||||
|
||||
if (i == vname.size() - 1) {
|
||||
cmdname = boost::algorithm::join(vname, " ");
|
||||
command = kv.second;
|
||||
arg_end = k;
|
||||
goto found_command;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found_command:
|
||||
lock.unlock();
|
||||
|
||||
po::options_description ldesc("Command options");
|
||||
|
||||
if (command)
|
||||
command->InitParameters(ldesc);
|
||||
|
||||
desc.add(ldesc);
|
||||
|
||||
po::store(po::parse_command_line(argc - arg_end, argv + arg_end, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLICommand::ShowCommands(int argc, char **argv, po::options_description *desc, bool autocomplete)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(l_RegistryMutex);
|
||||
|
||||
typedef std::map<std::vector<String>, CLICommand::Ptr>::value_type CLIKeyValue;
|
||||
|
||||
std::vector<String> best_match;
|
||||
int arg_begin = 0;
|
||||
CLICommand::Ptr command;
|
||||
|
||||
BOOST_FOREACH(const CLIKeyValue& kv, l_Registry) {
|
||||
const std::vector<String>& vname = kv.first;
|
||||
|
||||
arg_begin = 0;
|
||||
|
||||
for (int i = 0, k = 1; i < vname.size() && k < argc; i++, k++) {
|
||||
if (strcmp(argv[k], "--no-stack-rlimit") == 0 || strcmp(argv[k], "--autocomplete") == 0) {
|
||||
i--;
|
||||
arg_begin++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vname[i] != argv[k])
|
||||
break;
|
||||
|
||||
if (i >= best_match.size()) {
|
||||
best_match.push_back(vname[i]);
|
||||
}
|
||||
|
||||
if (i == vname.size() - 1) {
|
||||
command = kv.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!autocomplete)
|
||||
std::cout << "Supported commands: " << std::endl;
|
||||
|
||||
BOOST_FOREACH(const CLIKeyValue& kv, l_Registry) {
|
||||
const std::vector<String>& vname = kv.first;
|
||||
|
||||
if (vname.size() < best_match.size())
|
||||
continue;
|
||||
|
||||
bool match = true;
|
||||
|
||||
for (int i = 0; i < best_match.size(); i++) {
|
||||
if (vname[i] != best_match[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
continue;
|
||||
|
||||
if (autocomplete) {
|
||||
if (best_match.size() < vname.size()) {
|
||||
String cname = vname[best_match.size()];
|
||||
String pname;
|
||||
|
||||
if (arg_begin + best_match.size() + 1 < argc)
|
||||
pname = argv[arg_begin + best_match.size() + 1];
|
||||
|
||||
if (cname.Find(pname) == 0)
|
||||
std::cout << vname[best_match.size()] << " ";
|
||||
}
|
||||
} else
|
||||
std::cout << " * " << boost::algorithm::join(vname, " ") << " (" << kv.second->GetShortDescription() << ")" << std::endl;
|
||||
}
|
||||
|
||||
if (command && autocomplete) {
|
||||
po::options_description ldesc("Command options");
|
||||
|
||||
if (command)
|
||||
command->InitParameters(ldesc);
|
||||
|
||||
desc->add(ldesc);
|
||||
|
||||
BOOST_FOREACH(const shared_ptr<po::option_description>& odesc, desc->options()) {
|
||||
String cname = "--" + odesc->long_name();
|
||||
String pname = argv[argc - 1];
|
||||
|
||||
if (cname.Find(pname) == 0)
|
||||
std::cout << cname << " ";
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CLICOMMAND_H
|
||||
#define CLICOMMAND_H
|
||||
|
||||
#include "base/i2-base.hpp"
|
||||
#include "base/value.hpp"
|
||||
#include "base/utility.hpp"
|
||||
#include <vector>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* A CLI command.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_BASE_API CLICommand : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(CLICommand);
|
||||
|
||||
virtual String GetDescription(void) const = 0;
|
||||
virtual String GetShortDescription(void) const = 0;
|
||||
virtual void InitParameters(boost::program_options::options_description& desc) const = 0;
|
||||
virtual int Run(const boost::program_options::variables_map& vm) const = 0;
|
||||
|
||||
static CLICommand::Ptr GetByName(const std::vector<String>& name);
|
||||
static void Register(const std::vector<String>& name, const CLICommand::Ptr& command);
|
||||
static void Unregister(const std::vector<String>& name);
|
||||
|
||||
static bool ParseCommand(int argc, char **argv, boost::program_options::options_description& desc,
|
||||
boost::program_options::variables_map& vm, String& cmdname, CLICommand::Ptr& command, bool& autocomplete);
|
||||
static void ShowCommands(int argc, char **argv, boost::program_options::options_description *desc, bool autocomplete);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for registering CLICommand implementation classes.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_BASE_API RegisterCLICommandHelper
|
||||
{
|
||||
public:
|
||||
RegisterCLICommandHelper(const String& name, const CLICommand::Ptr& command);
|
||||
};
|
||||
|
||||
#define REGISTER_CLICOMMAND(name, klass) \
|
||||
namespace { namespace UNIQUE_NAME(cli) { \
|
||||
I2_EXPORT icinga::RegisterCLICommandHelper l_RegisterCLICommand(name, make_shared<klass>()); \
|
||||
} }
|
||||
|
||||
}
|
||||
|
||||
#endif /* CLICOMMAND_H */
|
|
@ -1001,7 +1001,7 @@ String Utility::GetFQDN(void)
|
|||
addrinfo *result;
|
||||
int rc = getaddrinfo(hostname.CStr(), NULL, &hints, &result);
|
||||
|
||||
if (rc < 0)
|
||||
if (rc != 0)
|
||||
result = NULL;
|
||||
|
||||
String canonicalName;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Icinga 2
|
||||
# Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
set(cli_SOURCES
|
||||
cainitcommand.cpp daemoncommand.cpp
|
||||
)
|
||||
|
||||
if(ICINGA2_UNITY_BUILD)
|
||||
mkunity_target(cli cli_SOURCES)
|
||||
endif()
|
||||
|
||||
add_library(cli SHARED ${cli_SOURCES})
|
||||
|
||||
target_link_libraries(cli ${Boost_LIBRARIES} base config)
|
||||
|
||||
set_target_properties (
|
||||
cli PROPERTIES
|
||||
INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
|
||||
FOLDER Lib
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS cli
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cli/cainitcommand.hpp"
|
||||
#include "base/logger_fwd.hpp"
|
||||
#include "base/clicommand.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_CLICOMMAND("ca/init", CAInitCommand);
|
||||
|
||||
String CAInitCommand::GetDescription(void) const
|
||||
{
|
||||
return "Sets up a new Certificate Authority.";
|
||||
}
|
||||
|
||||
String CAInitCommand::GetShortDescription(void) const
|
||||
{
|
||||
return "sets up a new CA";
|
||||
}
|
||||
|
||||
void CAInitCommand::InitParameters(boost::program_options::options_description& desc) const
|
||||
{
|
||||
/* Command doesn't support any parameters. */
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the "ca init" CLI command.
|
||||
*
|
||||
* @returns An exit status.
|
||||
*/
|
||||
int CAInitCommand::Run(const boost::program_options::variables_map& vm) const
|
||||
{
|
||||
Log(LogNotice, "cli", "Test!");
|
||||
Log(LogInformation, "cli", "Hello World!");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CAINITCOMMAND_H
|
||||
#define CAINITCOMMAND_H
|
||||
|
||||
#include "base/qstring.hpp"
|
||||
#include "base/clicommand.hpp"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* The "ca init" command.
|
||||
*
|
||||
* @ingroup cli
|
||||
*/
|
||||
class CAInitCommand : public CLICommand
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(CAInitCommand);
|
||||
|
||||
virtual String GetDescription(void) const;
|
||||
virtual String GetShortDescription(void) const;
|
||||
virtual void InitParameters(boost::program_options::options_description& desc) const;
|
||||
virtual int Run(const boost::program_options::variables_map& vm) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CAINITCOMMAND_H */
|
|
@ -0,0 +1,446 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cli/daemoncommand.hpp"
|
||||
#include "config/configcompilercontext.hpp"
|
||||
#include "config/configcompiler.hpp"
|
||||
#include "config/configitembuilder.hpp"
|
||||
#include "base/logger_fwd.hpp"
|
||||
#include "base/clicommand.hpp"
|
||||
#include "base/application.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/timer.hpp"
|
||||
#include "base/utility.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include "base/scriptvariable.hpp"
|
||||
#include "base/context.hpp"
|
||||
#include "config.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/types.h>
|
||||
# include <pwd.h>
|
||||
# include <grp.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
using namespace icinga;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
static po::variables_map g_AppParams;
|
||||
|
||||
REGISTER_CLICOMMAND("daemon", DaemonCommand);
|
||||
|
||||
static String LoadAppType(const String& typeSpec)
|
||||
{
|
||||
Log(LogInformation, "cli", "Loading application type: " + typeSpec);
|
||||
|
||||
String::SizeType index = typeSpec.FindFirstOf('/');
|
||||
|
||||
if (index == String::NPos)
|
||||
return typeSpec;
|
||||
|
||||
String library = typeSpec.SubStr(0, index);
|
||||
|
||||
(void) Utility::LoadExtensionLibrary(library);
|
||||
|
||||
return typeSpec.SubStr(index + 1);
|
||||
}
|
||||
|
||||
static void IncludeZoneDirRecursive(const String& path)
|
||||
{
|
||||
String zoneName = Utility::BaseName(path);
|
||||
Utility::GlobRecursive(path, "*.conf", boost::bind(&ConfigCompiler::CompileFile, _1, zoneName), GlobFile);
|
||||
}
|
||||
|
||||
static void IncludeNonLocalZone(const String& zonePath)
|
||||
{
|
||||
String etcPath = Application::GetZonesDir() + "/" + Utility::BaseName(zonePath);
|
||||
|
||||
if (Utility::PathExists(etcPath))
|
||||
return;
|
||||
|
||||
IncludeZoneDirRecursive(zonePath);
|
||||
}
|
||||
|
||||
static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType, const String& objectsFile = String())
|
||||
{
|
||||
ConfigCompilerContext::GetInstance()->Reset();
|
||||
|
||||
if (vm.count("config") > 0) {
|
||||
BOOST_FOREACH(const String& configPath, vm["config"].as<std::vector<std::string> >()) {
|
||||
ConfigCompiler::CompileFile(configPath);
|
||||
}
|
||||
} else if (!vm.count("no-config"))
|
||||
ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
|
||||
|
||||
/* Load cluster config files - this should probably be in libremote but
|
||||
* unfortunately moving it there is somewhat non-trivial. */
|
||||
String zonesEtcDir = Application::GetZonesDir();
|
||||
if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir))
|
||||
Utility::Glob(zonesEtcDir + "/*", &IncludeZoneDirRecursive, GlobDirectory);
|
||||
|
||||
String zonesVarDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
|
||||
if (Utility::PathExists(zonesVarDir))
|
||||
Utility::Glob(zonesVarDir + "/*", &IncludeNonLocalZone, GlobDirectory);
|
||||
|
||||
String name, fragment;
|
||||
BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
|
||||
ConfigCompiler::CompileText(name, fragment);
|
||||
}
|
||||
|
||||
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>();
|
||||
builder->SetType(appType);
|
||||
builder->SetName("application");
|
||||
ConfigItem::Ptr item = builder->Compile();
|
||||
item->Register();
|
||||
|
||||
bool result = ConfigItem::ValidateItems(objectsFile);
|
||||
|
||||
int warnings = 0, errors = 0;
|
||||
|
||||
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
|
||||
std::ostringstream locbuf;
|
||||
ShowCodeFragment(locbuf, message.Location, true);
|
||||
String location = locbuf.str();
|
||||
|
||||
String logmsg;
|
||||
|
||||
if (!location.IsEmpty())
|
||||
logmsg = "Location:\n" + location;
|
||||
|
||||
logmsg += String("\nConfig ") + (message.Error ? "error" : "warning") + ": " + message.Text;
|
||||
|
||||
if (message.Error) {
|
||||
Log(LogCritical, "config", logmsg);
|
||||
errors++;
|
||||
} else {
|
||||
Log(LogWarning, "config", logmsg);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings > 0 || errors > 0) {
|
||||
LogSeverity severity;
|
||||
|
||||
if (errors == 0)
|
||||
severity = LogWarning;
|
||||
else
|
||||
severity = LogCritical;
|
||||
|
||||
Log(severity, "config", Convert::ToString(errors) + " errors, " + Convert::ToString(warnings) + " warnings.");
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static void SigHupHandler(int)
|
||||
{
|
||||
Application::RequestRestart();
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static bool Daemonize(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
// systemd requires that the pidfile of the daemon is written before the forking
|
||||
// process terminates. So wait till either the forked daemon has written a pidfile or died.
|
||||
|
||||
int status;
|
||||
int ret;
|
||||
pid_t readpid;
|
||||
do {
|
||||
Utility::Sleep(0.1);
|
||||
|
||||
readpid = Application::ReadPidFile(Application::GetPidPath());
|
||||
ret = waitpid(pid, &status, WNOHANG);
|
||||
} while (readpid != pid && ret == 0);
|
||||
|
||||
if (ret == pid) {
|
||||
Log(LogCritical, "cli", "The daemon could not be started. See log output for details.");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (ret == -1) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "waitpid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetDaemonIO(const String& stderrFile)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
int fdnull = open("/dev/null", O_RDWR);
|
||||
if (fdnull >= 0) {
|
||||
if (fdnull != 0)
|
||||
dup2(fdnull, 0);
|
||||
|
||||
if (fdnull != 1)
|
||||
dup2(fdnull, 1);
|
||||
|
||||
if (fdnull > 1)
|
||||
close(fdnull);
|
||||
}
|
||||
|
||||
const char *errPath = "/dev/null";
|
||||
|
||||
if (!stderrFile.IsEmpty())
|
||||
errPath = stderrFile.CStr();
|
||||
|
||||
int fderr = open(errPath, O_WRONLY | O_APPEND);
|
||||
|
||||
if (fderr < 0 && errno == ENOENT)
|
||||
fderr = open(errPath, O_CREAT | O_WRONLY | O_APPEND, 0600);
|
||||
|
||||
if (fderr > 0) {
|
||||
if (fderr != 2)
|
||||
dup2(fderr, 2);
|
||||
|
||||
if (fderr > 2)
|
||||
close(fderr);
|
||||
}
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid == -1) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate another process and wait till it has ended
|
||||
*
|
||||
* @params target PID of the process to end
|
||||
*/
|
||||
static void TerminateAndWaitForEnd(pid_t target)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// allow 30 seconds timeout
|
||||
double timeout = Utility::GetTime() + 30;
|
||||
|
||||
int ret = kill(target, SIGTERM);
|
||||
|
||||
while (Utility::GetTime() < timeout && (ret == 0 || errno != ESRCH)) {
|
||||
Utility::Sleep(0.1);
|
||||
ret = kill(target, 0);
|
||||
}
|
||||
|
||||
// timeout and the process still seems to live: kill it
|
||||
if (ret == 0 || errno != ESRCH)
|
||||
kill(target, SIGKILL);
|
||||
|
||||
#else
|
||||
// TODO: implement this for Win32
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
|
||||
String DaemonCommand::GetDescription(void) const
|
||||
{
|
||||
return "Starts Icinga 2.";
|
||||
}
|
||||
|
||||
String DaemonCommand::GetShortDescription(void) const
|
||||
{
|
||||
return "starts Icinga 2";
|
||||
}
|
||||
|
||||
void DaemonCommand::InitParameters(boost::program_options::options_description& desc) const
|
||||
{
|
||||
desc.add_options()
|
||||
("config,c", po::value<std::vector<std::string> >(), "parse a configuration file")
|
||||
("no-config,z", "start without a configuration file")
|
||||
("validate,C", "exit after validating the configuration")
|
||||
("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)")
|
||||
#ifndef _WIN32
|
||||
("reload-internal", po::value<int>(), "used internally to implement config reload: do not call manually, send SIGHUP instead")
|
||||
("daemonize,d", "detach from the controlling terminal")
|
||||
("user,u", po::value<std::string>(), "user to run Icinga as")
|
||||
("group,g", po::value<std::string>(), "group to run Icinga as")
|
||||
#endif /* _WIN32 */
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the "daemon" CLI command.
|
||||
*
|
||||
* @returns An exit status.
|
||||
*/
|
||||
int DaemonCommand::Run(const po::variables_map& vm) const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
if (vm.count("group")) {
|
||||
String group = vm["group"].as<std::string>();
|
||||
|
||||
errno = 0;
|
||||
struct group *gr = getgrnam(group.CStr());
|
||||
|
||||
if (!gr) {
|
||||
if (errno == 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Invalid group specified: " + group;
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (setgid(gr->gr_gid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.count("user")) {
|
||||
String user = vm["user"].as<std::string>();
|
||||
|
||||
errno = 0;
|
||||
struct passwd *pw = getpwnam(user.CStr());
|
||||
|
||||
if (!pw) {
|
||||
if (errno == 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Invalid user specified: " + user;
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// also activate the additional groups the configured user is member of
|
||||
if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (setuid(pw->pw_uid) < 0) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||
Log(LogCritical, "cli", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
ScriptVariable::Set("UseVfork", true, false, true);
|
||||
|
||||
Application::MakeVariablesConstant();
|
||||
|
||||
Log(LogInformation, "cli", "Icinga application loader (version: " + Application::GetVersion() + ")");
|
||||
|
||||
String appType = LoadAppType(Application::GetApplicationType());
|
||||
|
||||
if (!vm.count("validate") && !vm.count("reload-internal")) {
|
||||
pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
|
||||
if (runningpid > 0) {
|
||||
Log(LogCritical, "cli", "Another instance of Icinga already running with PID " + Convert::ToString(runningpid));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!LoadConfigFiles(vm, appType, Application::GetObjectsPath()))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (vm.count("validate")) {
|
||||
Log(LogInformation, "cli", "Finished validating the configuration file(s).");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if(vm.count("reload-internal")) {
|
||||
int parentpid = vm["reload-internal"].as<int>();
|
||||
Log(LogInformation, "cli", "Terminating previous instance of Icinga (PID " + Convert::ToString(parentpid) + ")");
|
||||
TerminateAndWaitForEnd(parentpid);
|
||||
Log(LogInformation, "cli", "Previous instance has ended, taking over now.");
|
||||
}
|
||||
|
||||
if (vm.count("daemonize")) {
|
||||
if (!vm.count("reload-internal")) {
|
||||
// no additional fork neccessary on reload
|
||||
try {
|
||||
Daemonize();
|
||||
} catch (std::exception&) {
|
||||
Log(LogCritical, "cli", "Daemonize failed. Exiting.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// activate config only after daemonization: it starts threads and that is not compatible with fork()
|
||||
if (!ConfigItem::ActivateItems()) {
|
||||
Log(LogCritical, "cli", "Error activating configuration.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (vm.count("daemonize")) {
|
||||
String errorLog;
|
||||
if (vm.count("errorlog"))
|
||||
errorLog = vm["errorlog"].as<std::string>();
|
||||
|
||||
SetDaemonIO(errorLog);
|
||||
Logger::DisableConsoleLog();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = &SigHupHandler;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return Application::GetInstance()->Run();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DAEMONCOMMAND_H
|
||||
#define DAEMONCOMMAND_H
|
||||
|
||||
#include "base/clicommand.hpp"
|
||||
#include "base/qstring.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* The "daemon" CLI command.
|
||||
*
|
||||
* @ingroup cli
|
||||
*/
|
||||
class DaemonCommand : public CLICommand
|
||||
{
|
||||
public:
|
||||
DECLARE_PTR_TYPEDEFS(DaemonCommand);
|
||||
|
||||
virtual String GetDescription(void) const;
|
||||
virtual String GetShortDescription(void) const;
|
||||
virtual void InitParameters(boost::program_options::options_description& desc) const;
|
||||
virtual int Run(const boost::program_options::variables_map& vm) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DAEMONCOMMAND_H */
|
Loading…
Reference in New Issue