]> granicus.if.org Git - icinga2/blob - plugins/check_service.cpp
Fix sending notifications for volatile checks on OK->OK changes
[icinga2] / plugins / check_service.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
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.                     *
9  *                                                                            *
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.                               *
14  *                                                                            *
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  ******************************************************************************/
19 #include <Windows.h>
20 #include <Shlwapi.h>
21 #include <iostream>
22
23 #include "thresholds.h"
24
25 #include "boost/program_options.hpp"
26
27 #define VERSION 1.0
28
29 namespace po = boost::program_options;
30
31 using std::wcout; using std::endl;
32 using std::cout; using std::wstring;
33
34 struct printInfoStruct 
35 {
36         bool warn;
37         int ServiceState;
38         wstring service;
39 };
40
41 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
42 static int printOutput(const printInfoStruct&);
43 static int ServiceStatus(const printInfoStruct&);
44
45 int wmain(int argc, wchar_t **argv)
46 {
47         po::variables_map vm;
48         printInfoStruct printInfo = { false, 0, L"" };
49
50         int ret = parseArguments(argc, argv, vm, printInfo);
51         if (ret != -1)
52                 return ret;
53
54         printInfo.ServiceState = ServiceStatus(printInfo);
55         if (printInfo.ServiceState == -1)
56                 return 3;
57
58         return printOutput(printInfo);
59 }
60
61 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) 
62 {
63         wchar_t namePath[MAX_PATH];
64         GetModuleFileName(NULL, namePath, MAX_PATH);
65         wchar_t *progName = PathFindFileName(namePath);
66
67         po::options_description desc;
68
69         desc.add_options()
70                 ("help,h", "print help message and exit")
71                 ("version,V", "print version and exit")
72                 ("service,s", po::wvalue<wstring>(), "service to check (required)")
73                 ("warn,w", "return warning (1) instead of critical (2),\n when service is not running")
74                 ;
75
76         po::basic_command_line_parser<wchar_t> parser(ac, av);
77
78         try {
79                 po::store(
80                         parser
81                         .options(desc)
82                         .style(
83                         po::command_line_style::unix_style |
84                         po::command_line_style::allow_long_disguise)
85                         .run(),
86                         vm);
87                 vm.notify();
88         } catch (std::exception& e) {
89                 cout << e.what() << endl << desc << endl;
90                 return 3;
91         }
92
93         if (vm.count("help")) {
94                 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
95                 wprintf(
96                         L"%s is a simple program to check the status of a service.\n"
97                         L"You can use the following options to define its behaviour:\n\n", progName);
98                 cout << desc;
99                 wprintf(
100                         L"\nIt will then output a string looking something like this:\n\n"
101                         L"\tSERVICE CRITICAL NOT_RUNNING|service=4;!4;!4;1;7\n\n"
102                         L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
103                         L"and \"1\" is the returned value.\n"
104                         L"A service is either running (Code 0x04) or not running (any other).\n"
105                         L"For more information consult the msdn on service state transitions.\n\n"
106                         L"%s' exit codes denote the following:\n"
107                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
108                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
109                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
110                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
111                         L"%s' thresholds work differently, since a service is either running or not\n"
112                         L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
113                         L"or critical state respectively.\n"
114                         , progName, progName);
115                 cout << endl;
116                 return 0;
117         }
118     
119          if (vm.count("version")) {
120                 cout << "Version: " << VERSION << endl;
121                 return 0;
122         } 
123     
124     if (!vm.count("service")) {
125                 cout << "Missing argument: service" << endl << desc << endl;
126                 return 3;
127         }
128
129         if (vm.count("warn"))
130                 printInfo.warn = true;
131         
132         printInfo.service = vm["service"].as<wstring>();
133         
134         return -1;
135 }
136
137 int printOutput(const printInfoStruct& printInfo) 
138 {
139         wstring perf;
140         state state = OK;
141
142         if (!printInfo.ServiceState) {
143                 wcout << L"SERVICE CRITICAL NOT_FOUND | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
144                 return 3;
145         }
146
147         if (printInfo.ServiceState != 0x04) 
148                 printInfo.warn ? state = WARNING : state = CRITICAL;
149
150         switch (state) {
151         case OK:
152                 wcout << L"SERVICE OK RUNNING | service=4;!4;!4;1;7" << endl;
153                 break;
154         case WARNING:
155                 wcout << L"SERVICE WARNING NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
156                 break;
157         case CRITICAL:
158                 wcout << L"SERVICE CRITICAL NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
159                 break;
160         }
161     
162         return state;
163 }
164
165 int ServiceStatus(const printInfoStruct& printInfo) 
166 {
167         SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
168         if (service_api == NULL)
169                 goto die;
170
171         LPBYTE lpServices = NULL;
172         DWORD cbBufSize = 0;
173         DWORD pcbBytesNeeded = NULL, ServicesReturned = NULL, ResumeHandle = NULL;
174
175         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
176                 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL)
177                 && GetLastError() != ERROR_MORE_DATA) 
178                 goto die;
179
180         lpServices = reinterpret_cast<LPBYTE>(new BYTE[pcbBytesNeeded]);
181         cbBufSize = pcbBytesNeeded;
182
183         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
184                 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL))
185                 goto die;
186
187         LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
188     
189         for (DWORD i = 0; i < ServicesReturned; i++) {
190                 if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName)) {
191                         int state = pInfo[i].ServiceStatusProcess.dwCurrentState;
192                         delete lpServices;
193                         return state;
194                 }
195         }
196         return 0;
197         delete[] reinterpret_cast<LPBYTE>(lpServices);
198         return -1;
199
200 die:
201         die();
202         if (lpServices)
203                 delete[] reinterpret_cast<LPBYTE>(lpServices);
204         return -1;
205 }