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_guessing |
48 po::command_line_style::allow_long_disguise
53 } catch (const std::exception& e) {
54 std::cout << e.what() << '\n' << desc << '\n';
58 if (vm.count("help")) {
59 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
61 L"%s is a simple program to check the status of a service.\n"
62 L"You can use the following options to define its behaviour:\n\n", progName);
65 L"\nIt will then output a string looking something like this:\n\n"
66 L"\tSERVICE CRITICAL NOT_RUNNING | service=4;!4;!4;1;7\n\n"
67 L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
68 L"and \"1\" is the returned value.\n"
69 L"A service is either running (Code 0x04) or not running (any other).\n"
70 L"For more information consult the msdn on service state transitions.\n\n"
71 L"%s' exit codes denote the following:\n"
72 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
73 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
74 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
75 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
76 L"%s' thresholds work differently, since a service is either running or not\n"
77 L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
78 L"or critical state respectively.\n\n"
79 , progName, progName);
84 if (vm.count("version")) {
85 std::cout << "Version: " << VERSION << '\n';
89 if (!vm.count("service")) {
90 std::cout << "Argument \"service\" is required.\n" << desc << '\n';
94 printInfo.service = vm["service"].as<std::wstring>();
96 printInfo.warn = vm.count("warn");
98 l_Debug = vm.count("debug") > 0;
103 static int printOutput(const printInfoStruct& printInfo)
106 std::wcout << L"Constructing output string" << '\n';
111 if (!printInfo.ServiceState) {
112 std::wcout << L"SERVICE CRITICAL NOT FOUND | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
116 if (printInfo.ServiceState != 0x04)
117 printInfo.warn ? state = WARNING : state = CRITICAL;
121 std::wcout << L"SERVICE \"" << printInfo.service << "\" OK RUNNING | 'service'=4;;;1;7" << '\n';
124 std::wcout << L"SERVICE \"" << printInfo.service << "\" WARNING NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
127 std::wcout << L"SERVICE \"" << printInfo.service << "\" CRITICAL NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
134 static std::wstring getServiceByDescription(const std::wstring& description)
136 SC_HANDLE hSCM = NULL;
137 LPENUM_SERVICE_STATUSW lpServices = NULL;
140 DWORD lpServicesReturned = 0;
141 DWORD pcbBytesNeeded = 0;
142 DWORD lpResumeHandle = 0;;
145 std::wcout << L"Opening SC Manager" << '\n';
147 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
152 std::wcout << L"Determining initially required memory" << '\n';
154 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0,
155 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
157 /* This should always be ERROR_INSUFFICIENT_BUFFER... But for some reason it is sometimes ERROR_MORE_DATA
158 * See the MSDN on EnumServiceStatus for a glimpse of despair
161 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER && GetLastError() != ERROR_MORE_DATA)
164 lpServices = reinterpret_cast<LPENUM_SERVICE_STATUSW>(new BYTE[pcbBytesNeeded]);
167 std::wcout << L"Requesting Service Information. Entry point: " << lpResumeHandle << '\n';
169 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, lpServices, pcbBytesNeeded,
170 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
172 for (decltype(lpServicesReturned) index = 0; index < lpServicesReturned; index++) {
173 LPWSTR lpCurrent = lpServices[index].lpServiceName;
176 std::wcout << L"Opening Service \"" << lpServices[index].lpServiceName << L"\"\n";
179 SC_HANDLE hService = OpenService(hSCM, lpCurrent, SERVICE_QUERY_CONFIG);
183 DWORD dwBytesNeeded = 0;
185 std::wcout << "Accessing config\n";
187 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
190 LPSERVICE_DESCRIPTION lpsd = reinterpret_cast<LPSERVICE_DESCRIPTION>(new BYTE[dwBytesNeeded]);
192 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, dwBytesNeeded, &dwBytesNeeded))
195 if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, L"") != 0) {
196 std::wstring desc(lpsd->lpDescription);
198 std::wcout << "Got description:\n" << desc << '\n';
199 size_t p = desc.find(description);
200 if (desc.find(description) != desc.npos)
204 std::wcout << "No description found\n";
207 CloseServiceHandle(hSCM);
214 CloseServiceHandle(hSCM);
220 static DWORD getServiceStatus(const printInfoStruct& printInfo)
225 DWORD lpResumeHandle = 0;
229 std::wcout << L"Opening SC Manager" << '\n';
231 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
235 hService = OpenService(hSCM, printInfo.service.c_str(), SERVICE_QUERY_STATUS);
236 if (hService == NULL)
239 QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0, &cbBufSize);
240 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
243 lpBuf = new BYTE[cbBufSize];
244 if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, lpBuf, cbBufSize, &cbBufSize)) {
245 LPSERVICE_STATUS_PROCESS pInfo = (LPSERVICE_STATUS_PROCESS)lpBuf;
246 return pInfo->dwCurrentState;
252 CloseServiceHandle(hSCM);
254 CloseServiceHandle(hService);
261 int wmain(int argc, WCHAR **argv)
263 po::variables_map vm;
264 printInfoStruct printInfo;
266 int ret = parseArguments(argc, argv, vm, printInfo);
270 if (vm.count("description"))
271 printInfo.service = getServiceByDescription(vm["service"].as<std::wstring>());
273 if (printInfo.service.empty()) {
274 std::wcout << "Could not find service matching description\n";
278 printInfo.ServiceState = getServiceStatus(printInfo);
279 if (printInfo.ServiceState == -1)
282 return printOutput(printInfo);