1 /******************************************************************************
3 * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
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 ******************************************************************************/
23 #include "thresholds.h"
25 #include "boost/program_options.hpp"
29 namespace po = boost::program_options;
31 using std::wcout; using std::endl;
32 using std::cout; using std::wstring;
36 struct printInfoStruct
43 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
44 static int printOutput(const printInfoStruct&);
45 static int ServiceStatus(const printInfoStruct&);
47 int wmain(int argc, wchar_t **argv)
50 printInfoStruct printInfo = { false, 0, L"" };
52 int ret = parseArguments(argc, argv, vm, printInfo);
56 printInfo.ServiceState = ServiceStatus(printInfo);
57 if (printInfo.ServiceState == -1)
60 return printOutput(printInfo);
63 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo)
65 wchar_t namePath[MAX_PATH];
66 GetModuleFileName(NULL, namePath, MAX_PATH);
67 wchar_t *progName = PathFindFileName(namePath);
69 po::options_description desc;
72 ("help,h", "print help message and exit")
73 ("version,V", "print version and exit")
74 ("debug,d", "Verbose/Debug output")
75 ("service,s", po::wvalue<wstring>(), "service to check (required)")
76 ("warn,w", "return warning (1) instead of critical (2),\n when service is not running")
79 po::basic_command_line_parser<wchar_t> parser(ac, av);
86 po::command_line_style::unix_style |
87 po::command_line_style::allow_long_disguise)
91 } catch (std::exception& e) {
92 cout << e.what() << endl << desc << endl;
96 if (vm.count("help")) {
97 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
99 L"%s is a simple program to check the status of a service.\n"
100 L"You can use the following options to define its behaviour:\n\n", progName);
103 L"\nIt will then output a string looking something like this:\n\n"
104 L"\tSERVICE CRITICAL NOT_RUNNING|service=4;!4;!4;1;7\n\n"
105 L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
106 L"and \"1\" is the returned value.\n"
107 L"A service is either running (Code 0x04) or not running (any other).\n"
108 L"For more information consult the msdn on service state transitions.\n\n"
109 L"%s' exit codes denote the following:\n"
110 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
111 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
112 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
113 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
114 L"%s' thresholds work differently, since a service is either running or not\n"
115 L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
116 L"or critical state respectively.\n\n"
117 L"Known issue: Since icinga2 runs as NETWORK SERVICE it can't access the access control lists\n"
118 L"it will not be able to find a service like NTDS. To fix this add ACL read permissions to icinga2.\n"
119 , progName, progName);
124 if (vm.count("version")) {
125 cout << "Version: " << VERSION << endl;
129 if (!vm.count("service")) {
130 cout << "Missing argument: service" << endl << desc << endl;
134 if (vm.count("warn"))
135 printInfo.warn = true;
137 printInfo.service = vm["service"].as<wstring>();
139 if (vm.count("debug"))
145 int printOutput(const printInfoStruct& printInfo)
148 wcout << L"Constructing output string" << endl;
153 if (!printInfo.ServiceState) {
154 wcout << L"SERVICE CRITICAL NOT_FOUND | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
158 if (printInfo.ServiceState != 0x04)
159 printInfo.warn ? state = WARNING : state = CRITICAL;
163 wcout << L"SERVICE OK RUNNING | service=4;!4;!4;1;7" << endl;
166 wcout << L"SERVICE WARNING NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
169 wcout << L"SERVICE CRITICAL NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
176 int ServiceStatus(const printInfoStruct& printInfo)
179 wcout << L"Opening SC Manager" << endl;
181 SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
182 if (service_api == NULL)
185 LPBYTE lpServices = NULL;
187 DWORD pcbBytesNeeded = NULL, ServicesReturned = NULL, ResumeHandle = NULL;
190 wcout << L"Creating service info structure" << endl;
192 if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
193 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL)
194 && GetLastError() != ERROR_MORE_DATA)
197 lpServices = reinterpret_cast<LPBYTE>(new BYTE[pcbBytesNeeded]);
198 cbBufSize = pcbBytesNeeded;
200 if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
201 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL))
204 LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
207 wcout << L"Traversing services" << endl;
209 for (DWORD i = 0; i < ServicesReturned; i++) {
211 wcout << L"Comparing " << pInfo[i].lpServiceName << L" to " << printInfo.service << endl;
213 if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName)) {
215 wcout << L"Service " << pInfo[i].lpServiceName << L" = " << printInfo.service << ". Returning" << endl;
217 int state = pInfo[i].ServiceStatusProcess.dwCurrentState;
222 delete[] reinterpret_cast<LPBYTE>(lpServices);
228 delete[] reinterpret_cast<LPBYTE>(lpServices);