icinga2/plugins/check_service.cpp

181 lines
5.4 KiB
C++
Raw Normal View History

2014-11-06 15:17:08 +01:00
#include <Windows.h>
#include <Shlwapi.h>
#include <iostream>
#include "thresholds.h"
#include "boost\program_options.hpp"
#define VERSION 1.0
namespace po = boost::program_options;
using std::wcout; using std::endl;
using std::cout; using std::wstring;
struct printInfoStruct {
bool warn;
int ServiceState;
wstring service;
};
static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
static int printOutput(const printInfoStruct&);
static int ServiceStatus(const printInfoStruct&);
int wmain(int argc, wchar_t **argv)
{
po::variables_map vm;
printInfoStruct printInfo = { false, 0, L"" };
int ret = parseArguments(argc, argv, vm, printInfo);
if (ret != -1)
return ret;
printInfo.ServiceState = ServiceStatus(printInfo);
if (printInfo.ServiceState == -1)
return 3;
return printOutput(printInfo);
}
int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
wchar_t namePath[MAX_PATH];
GetModuleFileName(NULL, namePath, MAX_PATH);
wchar_t *progName = PathFindFileName(namePath);
po::options_description desc;
desc.add_options()
(",h", "print help message and exit")
("help", "print verbose help and exit")
("version,v", "print version and exit")
("service,s", po::wvalue<wstring>(), "service to check (required)")
("warn,w", "return warning (1) instead of critical (2)\n when service is not running")
;
po::basic_command_line_parser<wchar_t> parser(ac, av);
try {
po::store(
parser
.options(desc)
.style(
po::command_line_style::unix_style |
po::command_line_style::allow_long_disguise)
.run(),
vm);
vm.notify();
} catch (std::exception& e) {
cout << e.what() << endl << desc << endl;
return 3;
}
if (vm.count("h")) {
cout << desc << endl;
return 0;
}
if (vm.count("help")) {
wcout << progName << " Help\n\tVersion: " << VERSION << endl;
wprintf(
L"%s is a simple program to check the status of a service.\n"
L"You can use the following options to define its behaviour:\n\n", progName);
cout << desc;
wprintf(
L"\nIt will then output a string looking something like this:\n\n"
L"\tSERVICE CRITICAL NOT_RUNNING|service=1;-1;!4;1;7\n\n"
L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
L"and \"1\" is the returned value.\n"
L"The performance data is found behind the \"|\", in order:\n"
L"returned value, warning threshold, critical threshold, minimal value and,\n"
L"if applicable, the maximal value.\n"
L"A service is either running (Code 0x04) or not running (any other).\n"
L"For more information consult the msdn on service state transitions.\n\n"
L"%s' exit codes denote the following:\n"
L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
L"%s' thresholds work differently, since a service is either running or not\n"
L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
L"or critical state respectively.\n"
, progName);
cout << endl;
return 0;
}
if (vm.count("version")) {
cout << "Version: " << VERSION << endl;
return 0;
} if (!vm.count("service")) {
cout << "Missing argument: service" << endl << desc << endl;
return 3;
}
if (vm.count("warn"))
printInfo.warn = true;
printInfo.service = vm["service"].as<wstring>();
return -1;
}
int printOutput(const printInfoStruct& printInfo) {
wstring perf;
state state = OK;
if (printInfo.ServiceState != 0x04)
printInfo.warn ? state = WARNING : state = CRITICAL;
printInfo.warn ? perf.append(L"!4;-1;1;7") : perf.append(L"-1;!4;1;7");
switch (state) {
case OK:
wcout << L"SERVICE OK RUNNING|service=4;" << perf << endl;
break;
case WARNING:
wcout << L"SERVICE WARNING NOT_RUNNING|service=" << printInfo.ServiceState << perf << endl;
break;
case CRITICAL:
wcout << L"SERVICE CRITICAL NOT_RUNNING|service=" << printInfo.ServiceState << perf << endl;
break;
}
return state;
}
int ServiceStatus(const printInfoStruct& printInfo) {
SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (service_api == NULL)
goto die;
LPBYTE lpServices = NULL;
DWORD cbBufSize = 0;
DWORD *pcbBytesNeeded = (LPDWORD)malloc(sizeof(DWORD));
DWORD *lpServicesReturned = (LPDWORD)malloc(sizeof(DWORD));
DWORD *lpResumeHandle = (LPDWORD)malloc(sizeof(DWORD));
*lpResumeHandle = 0;
if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL)
&& GetLastError() != ERROR_MORE_DATA)
goto die;
lpServices = (LPBYTE)malloc(*pcbBytesNeeded);
cbBufSize = *pcbBytesNeeded;
if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL))
goto die;
LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
for (DWORD i = 0; i< *lpServicesReturned; i++)
{
if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName))
return pInfo[i].ServiceStatusProcess.dwCurrentState;
}
die:
wcout << L"Service " << printInfo.service << L" could not be found" << endl;
return -1;
}