1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "plugins/thresholds.hpp"
4 #include <boost/program_options.hpp>
11 namespace po = boost::program_options;
13 struct printInfoStruct
22 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
24 WCHAR namePath[MAX_PATH];
25 GetModuleFileName(NULL, namePath, MAX_PATH);
26 WCHAR *progName = PathFindFileName(namePath);
28 po::options_description desc;
31 ("help,h", "Print help message and exit")
32 ("version,V", "Print version and exit")
33 ("debug,D", "Verbose/Debug output")
34 ("service,s", po::wvalue<std::wstring>(), "Service name to check")
35 ("description,d", "Use \"service\" to match on description")
36 ("warn,w", "Return warning (1) instead of critical (2),\n when service is not running")
39 po::wcommand_line_parser parser(ac, av);
46 po::command_line_style::unix_style |
47 po::command_line_style::allow_long_disguise)
51 } catch (const std::exception& e) {
52 std::cout << e.what() << '\n' << desc << '\n';
56 if (vm.count("help")) {
57 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
59 L"%s is a simple program to check the status of a service.\n"
60 L"You can use the following options to define its behaviour:\n\n", progName);
63 L"\nIt will then output a string looking something like this:\n\n"
64 L"\tSERVICE CRITICAL NOT_RUNNING | service=4;!4;!4;1;7\n\n"
65 L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
66 L"and \"1\" is the returned value.\n"
67 L"A service is either running (Code 0x04) or not running (any other).\n"
68 L"For more information consult the msdn on service state transitions.\n\n"
69 L"%s' exit codes denote the following:\n"
70 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
71 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
72 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
73 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
74 L"%s' thresholds work differently, since a service is either running or not\n"
75 L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
76 L"or critical state respectively.\n\n"
77 , progName, progName);
82 if (vm.count("version")) {
83 std::cout << "Version: " << VERSION << '\n';
87 if (!vm.count("service")) {
88 std::cout << "Argument \"service\" is required.\n" << desc << '\n';
92 printInfo.service = vm["service"].as<std::wstring>();
94 printInfo.warn = vm.count("warn");
96 l_Debug = vm.count("debug") > 0;
101 static int printOutput(const printInfoStruct& printInfo)
104 std::wcout << L"Constructing output string" << '\n';
109 if (!printInfo.ServiceState) {
110 std::wcout << L"SERVICE CRITICAL NOT FOUND | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
114 if (printInfo.ServiceState != 0x04)
115 printInfo.warn ? state = WARNING : state = CRITICAL;
119 std::wcout << L"SERVICE \"" << printInfo.service << "\" OK RUNNING | 'service'=4;;;1;7" << '\n';
122 std::wcout << L"SERVICE \"" << printInfo.service << "\" WARNING NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
125 std::wcout << L"SERVICE \"" << printInfo.service << "\" CRITICAL NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
132 static std::wstring getServiceByDescription(const std::wstring& description)
134 SC_HANDLE hSCM = NULL;
135 LPENUM_SERVICE_STATUSW lpServices = NULL;
138 DWORD lpServicesReturned = 0;
139 DWORD pcbBytesNeeded = 0;
140 DWORD lpResumeHandle = 0;;
143 std::wcout << L"Opening SC Manager" << '\n';
145 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
150 std::wcout << L"Determining initially required memory" << '\n';
152 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0,
153 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
155 /* This should always be ERROR_INSUFFICIENT_BUFFER... But for some reason it is sometimes ERROR_MORE_DATA
156 * See the MSDN on EnumServiceStatus for a glimpse of despair
159 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER && GetLastError() != ERROR_MORE_DATA)
162 lpServices = reinterpret_cast<LPENUM_SERVICE_STATUSW>(new BYTE[pcbBytesNeeded]);
165 std::wcout << L"Requesting Service Information. Entry point: " << lpResumeHandle << '\n';
167 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, lpServices, pcbBytesNeeded,
168 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
170 for (decltype(lpServicesReturned) index = 0; index < lpServicesReturned; index++) {
171 LPWSTR lpCurrent = lpServices[index].lpServiceName;
174 std::wcout << L"Opening Service \"" << lpServices[index].lpServiceName << L"\"\n";
177 SC_HANDLE hService = OpenService(hSCM, lpCurrent, SERVICE_QUERY_CONFIG);
181 DWORD dwBytesNeeded = 0;
183 std::wcout << "Accessing config\n";
185 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
188 LPSERVICE_DESCRIPTION lpsd = reinterpret_cast<LPSERVICE_DESCRIPTION>(new BYTE[dwBytesNeeded]);
190 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, dwBytesNeeded, &dwBytesNeeded))
193 if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, L"") != 0) {
194 std::wstring desc(lpsd->lpDescription);
196 std::wcout << "Got description:\n" << desc << '\n';
197 size_t p = desc.find(description);
198 if (desc.find(description) != desc.npos)
202 std::wcout << "No description found\n";
205 CloseServiceHandle(hSCM);
212 CloseServiceHandle(hSCM);
218 static DWORD getServiceStatus(const printInfoStruct& printInfo)
223 DWORD lpResumeHandle = 0;
227 std::wcout << L"Opening SC Manager" << '\n';
229 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
233 hService = OpenService(hSCM, printInfo.service.c_str(), SERVICE_QUERY_STATUS);
234 if (hService == NULL)
237 QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0, &cbBufSize);
238 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
241 lpBuf = new BYTE[cbBufSize];
242 if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, lpBuf, cbBufSize, &cbBufSize)) {
243 LPSERVICE_STATUS_PROCESS pInfo = (LPSERVICE_STATUS_PROCESS)lpBuf;
244 return pInfo->dwCurrentState;
250 CloseServiceHandle(hSCM);
252 CloseServiceHandle(hService);
259 int wmain(int argc, WCHAR **argv)
261 po::variables_map vm;
262 printInfoStruct printInfo;
264 int ret = parseArguments(argc, argv, vm, printInfo);
268 if (vm.count("description"))
269 printInfo.service = getServiceByDescription(vm["service"].as<std::wstring>());
271 if (printInfo.service.empty()) {
272 std::wcout << "Could not find service matching description\n";
276 printInfo.ServiceState = getServiceStatus(printInfo);
277 if (printInfo.ServiceState == -1)
280 return printOutput(printInfo);