]> granicus.if.org Git - icinga2/blob - plugins/check_service.cpp
Clean up check_services
[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                 (",h", "print help message and exit")
71                 ("help", "print verbose help and exit")
72                 ("version,v", "print version and exit")
73                 ("service,s", po::wvalue<wstring>(), "service to check (required)")
74                 ("warn,w", "return warning (1) instead of critical (2),\n when service is not running")
75                 ;
76
77         po::basic_command_line_parser<wchar_t> parser(ac, av);
78
79         try {
80                 po::store(
81                         parser
82                         .options(desc)
83                         .style(
84                         po::command_line_style::unix_style |
85                         po::command_line_style::allow_long_disguise)
86                         .run(),
87                         vm);
88                 vm.notify();
89         } catch (std::exception& e) {
90                 cout << e.what() << endl << desc << endl;
91                 return 3;
92         }
93     
94         if (vm.count("h")) {
95                 cout << desc << endl;
96                 return 0;
97         } 
98     
99         if (vm.count("help")) {
100                 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
101                 wprintf(
102                         L"%s is a simple program to check the status of a service.\n"
103                         L"You can use the following options to define its behaviour:\n\n", progName);
104                 cout << desc;
105                 wprintf(
106                         L"\nIt will then output a string looking something like this:\n\n"
107                         L"\tSERVICE CRITICAL NOT_RUNNING|service=4;!4;!4;1;7\n\n"
108                         L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
109                         L"and \"1\" is the returned value.\n"
110                         L"A service is either running (Code 0x04) or not running (any other).\n"
111                         L"For more information consult the msdn on service state transitions.\n\n"
112                         L"%s' exit codes denote the following:\n"
113                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
114                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
115                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
116                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
117                         L"%s' thresholds work differently, since a service is either running or not\n"
118                         L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
119                         L"or critical state respectively.\n"
120                         , progName, progName);
121                 cout << endl;
122                 return 0;
123         }
124     
125          if (vm.count("version")) {
126                 cout << "Version: " << VERSION << endl;
127                 return 0;
128         } 
129     
130     if (!vm.count("service")) {
131                 cout << "Missing argument: service" << endl << desc << endl;
132                 return 3;
133         }
134
135         if (vm.count("warn"))
136                 printInfo.warn = true;
137         
138         printInfo.service = vm["service"].as<wstring>();
139         
140         return -1;
141 }
142
143 int printOutput(const printInfoStruct& printInfo) 
144 {
145         wstring perf;
146         state state = OK;
147
148         if (printInfo.ServiceState != 0x04) 
149                 printInfo.warn ? state = WARNING : state = CRITICAL;
150
151         switch (state) {
152         case OK:
153                 wcout << L"SERVICE OK RUNNING|service=4;!4;!4;1;7" << endl;
154                 break;
155         case WARNING:
156                 wcout << L"SERVICE WARNING NOT_RUNNING|service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
157                 break;
158         case CRITICAL:
159                 wcout << L"SERVICE CRITICAL NOT_RUNNING|service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
160                 break;
161         }
162     
163         return state;
164 }
165
166 int ServiceStatus(const printInfoStruct& printInfo) 
167 {
168         SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
169         if (service_api == NULL)
170                 goto die;
171
172         LPBYTE lpServices = NULL;
173         DWORD cbBufSize = 0;
174         DWORD *pcbBytesNeeded = NULL, *lpServicesReturned = NULL, *lpResumeHandle = NULL;
175
176         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
177                 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL)
178                 && GetLastError() != ERROR_MORE_DATA) 
179                 goto die;
180
181         lpServices = new BYTE[*pcbBytesNeeded];
182         cbBufSize = *pcbBytesNeeded;
183
184         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
185                 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL))
186                 goto die;
187
188         LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
189     
190         for (DWORD i = 0; i< *lpServicesReturned; i++) {
191                 if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName)) {
192                         delete lpServices;
193                         return pInfo[i].ServiceStatusProcess.dwCurrentState;
194                 }
195         }
196
197 die:
198         if (lpServices)
199                 delete lpServices;
200         wcout << L"Service " << printInfo.service << L" could not be found" << endl;
201         return -1;
202 }