1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "plugins/thresholds.hpp"
21 #include <boost/program_options.hpp>
28 namespace po = boost::program_options;
30 struct printInfoStruct
39 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
41 WCHAR namePath[MAX_PATH];
42 GetModuleFileName(NULL, namePath, MAX_PATH);
43 WCHAR *progName = PathFindFileName(namePath);
45 po::options_description desc;
48 ("help,h", "Print help message and exit")
49 ("version,V", "Print version and exit")
50 ("debug,D", "Verbose/Debug output")
51 ("service,s", po::wvalue<std::wstring>(), "Service name to check")
52 ("description,d", "Use \"service\" to match on description")
53 ("warn,w", "Return warning (1) instead of critical (2),\n when service is not running")
56 po::wcommand_line_parser parser(ac, av);
63 po::command_line_style::unix_style |
64 po::command_line_style::allow_long_disguise)
68 } catch (const std::exception& e) {
69 std::cout << e.what() << '\n' << desc << '\n';
73 if (vm.count("help")) {
74 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
76 L"%s is a simple program to check the status of a service.\n"
77 L"You can use the following options to define its behaviour:\n\n", progName);
80 L"\nIt will then output a string looking something like this:\n\n"
81 L"\tSERVICE CRITICAL NOT_RUNNING | service=4;!4;!4;1;7\n\n"
82 L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
83 L"and \"1\" is the returned value.\n"
84 L"A service is either running (Code 0x04) or not running (any other).\n"
85 L"For more information consult the msdn on service state transitions.\n\n"
86 L"%s' exit codes denote the following:\n"
87 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
88 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
89 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
90 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
91 L"%s' thresholds work differently, since a service is either running or not\n"
92 L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
93 L"or critical state respectively.\n\n"
94 , progName, progName);
99 if (vm.count("version")) {
100 std::cout << "Version: " << VERSION << '\n';
104 if (!vm.count("service")) {
105 std::cout << "Argument \"service\" is required.\n" << desc << '\n';
109 printInfo.service = vm["service"].as<std::wstring>();
111 printInfo.warn = vm.count("warn");
113 l_Debug = vm.count("debug") > 0;
118 static int printOutput(const printInfoStruct& printInfo)
121 std::wcout << L"Constructing output string" << '\n';
126 if (!printInfo.ServiceState) {
127 std::wcout << L"SERVICE CRITICAL NOT FOUND | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
131 if (printInfo.ServiceState != 0x04)
132 printInfo.warn ? state = WARNING : state = CRITICAL;
136 std::wcout << L"SERVICE \"" << printInfo.service << "\" OK RUNNING | 'service'=4;;;1;7" << '\n';
139 std::wcout << L"SERVICE \"" << printInfo.service << "\" WARNING NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
142 std::wcout << L"SERVICE \"" << printInfo.service << "\" CRITICAL NOT RUNNING | 'service'=" << printInfo.ServiceState << ";;;1;7" << '\n';
149 static std::wstring getServiceByDescription(const std::wstring& description)
151 SC_HANDLE hSCM = NULL;
152 LPENUM_SERVICE_STATUSW lpServices = NULL;
155 DWORD lpServicesReturned = 0;
156 DWORD pcbBytesNeeded = 0;
157 DWORD lpResumeHandle = 0;;
160 std::wcout << L"Opening SC Manager" << '\n';
162 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
167 std::wcout << L"Determining initially required memory" << '\n';
169 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0,
170 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
172 /* This should always be ERROR_INSUFFICIENT_BUFFER... But for some reason it is sometimes ERROR_MORE_DATA
173 * See the MSDN on EnumServiceStatus for a glimpse of despair
176 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER && GetLastError() != ERROR_MORE_DATA)
179 lpServices = reinterpret_cast<LPENUM_SERVICE_STATUSW>(new BYTE[pcbBytesNeeded]);
182 std::wcout << L"Requesting Service Information. Entry point: " << lpResumeHandle << '\n';
184 EnumServicesStatus(hSCM, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, lpServices, pcbBytesNeeded,
185 &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle);
187 for (int index = 0; index < lpServicesReturned; index++) {
188 LPWSTR lpCurrent = lpServices[index].lpServiceName;
191 std::wcout << L"Opening Service \"" << lpServices[index].lpServiceName << L"\"\n";
194 SC_HANDLE hService = OpenService(hSCM, lpCurrent, SERVICE_QUERY_CONFIG);
198 DWORD dwBytesNeeded = 0;
200 std::wcout << "Accessing config\n";
202 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
205 LPSERVICE_DESCRIPTION lpsd = reinterpret_cast<LPSERVICE_DESCRIPTION>(new BYTE[dwBytesNeeded]);
207 if (!QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, dwBytesNeeded, &dwBytesNeeded))
210 if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, L"") != 0) {
211 std::wstring desc(lpsd->lpDescription);
213 std::wcout << "Got description:\n" << desc << '\n';
214 size_t p = desc.find(description);
215 if (desc.find(description) != desc.npos)
219 std::wcout << "No description found\n";
222 CloseServiceHandle(hSCM);
229 CloseServiceHandle(hSCM);
235 static DWORD getServiceStatus(const printInfoStruct& printInfo)
240 DWORD lpResumeHandle = 0;
244 std::wcout << L"Opening SC Manager" << '\n';
246 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
250 hService = OpenService(hSCM, printInfo.service.c_str(), SERVICE_QUERY_STATUS);
251 if (hService == NULL)
254 QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0, &cbBufSize);
255 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
258 lpBuf = new BYTE[cbBufSize];
259 if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, lpBuf, cbBufSize, &cbBufSize)) {
260 LPSERVICE_STATUS_PROCESS pInfo = (LPSERVICE_STATUS_PROCESS)lpBuf;
261 return pInfo->dwCurrentState;
267 CloseServiceHandle(hSCM);
269 CloseServiceHandle(hService);
276 int wmain(int argc, WCHAR **argv)
278 po::variables_map vm;
279 printInfoStruct printInfo;
281 int ret = parseArguments(argc, argv, vm, printInfo);
285 if (vm.count("description"))
286 printInfo.service = getServiceByDescription(vm["service"].as<std::wstring>());
288 if (printInfo.service.empty()) {
289 std::wcout << "Could not find service matching description\n";
293 printInfo.ServiceState = getServiceStatus(printInfo);
294 if (printInfo.ServiceState == -1)
297 return printOutput(printInfo);