]> granicus.if.org Git - icinga2/blob - plugins/check_procs.cpp
Add summarized performance data to check_network
[icinga2] / plugins / check_procs.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "plugins/thresholds.hpp"
4 #include <boost/program_options.hpp>
5 #include <iostream>
6 #include <windows.h>
7 #include <shlwapi.h>
8 #include <tlhelp32.h>
9
10 #define VERSION 1.0
11
12 namespace po = boost::program_options;
13
14 struct printInfoStruct
15 {
16         threshold warn;
17         threshold crit;
18         std::wstring user;
19 };
20
21 static bool l_Debug;
22
23 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
24 {
25         WCHAR namePath[MAX_PATH];
26         GetModuleFileName(NULL, namePath, MAX_PATH);
27         WCHAR *progName = PathFindFileName(namePath);
28
29         po::options_description desc;
30
31         desc.add_options()
32                 ("help,h", "Print help message and exit")
33                 ("version,V", "Print version and exit")
34                 ("debug,d", "Verbose/Debug output")
35                 ("user,u", po::wvalue<std::wstring>(), "Count only processes of user")
36                 ("warning,w", po::wvalue<std::wstring>(), "Warning threshold")
37                 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
38                 ;
39
40         po::wcommand_line_parser parser(ac, av);
41
42         try {
43                 po::store(
44                         parser
45                         .options(desc)
46                         .style(
47                                 po::command_line_style::unix_style |
48                                 po::command_line_style::allow_long_disguise)
49                         .run(),
50                         vm);
51                 vm.notify();
52         } catch (const std::exception& e) {
53                 std::cout << e.what() << '\n' << desc << '\n';
54                 return 3;
55         }
56
57         if (vm.count("help")) {
58                 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
59                 wprintf(
60                         L"%s is a simple program to check a machines processes.\n"
61                         L"You can use the following options to define its behaviour:\n\n", progName);
62                 std::cout << desc;
63                 wprintf(
64                         L"\nIt will then output a string looking something like this:\n\n"
65                         L"\tPROCS WARNING 67 | load=67;50;90;0\n\n"
66                         L"\"PROCS\" being the type of the check, \"WARNING\" the returned status\n"
67                         L"and \"67\" is the returned value.\n"
68                         L"The performance data is found behind the \"|\", in order:\n"
69                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
70                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
71                         L"you set at least one threshold\n\n"
72                         L"For \"-user\" option keep in mind you need root to see other users processes\n\n"
73                         L"%s' exit codes denote the following:\n"
74                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
75                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
76                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
77                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
78                         L"Threshold syntax:\n\n"
79                         L"-w THRESHOLD\n"
80                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
81                         L"(unless stated differently)\n\n"
82                         L"-w !THRESHOLD\n"
83                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
84                         L"-w [THR1-THR2]\n"
85                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
86                         L"-w ![THR1-THR2]\n"
87                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
88                         L"-w THRESHOLD%%\n"
89                         L"if the plugin accepts percentage based thresholds those will be used.\n"
90                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
91                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
92                         L"to end with a percentage sign.\n\n"
93                         L"All of these options work with the critical threshold \"-c\" too."
94                         , progName);
95                 std::cout << '\n';
96                 return 0;
97         }
98
99         if (vm.count("version")) {
100                 std::wcout << "Version: " << VERSION << '\n';
101                 return 0;
102         }
103
104         if (vm.count("warning")) {
105                 try {
106                         printInfo.warn = threshold(vm["warning"].as<std::wstring>());
107                 } catch (const std::invalid_argument& e) {
108                         std::cout << e.what() << '\n';
109                         return 3;
110                 }
111         }
112         if (vm.count("critical")) {
113                 try {
114                         printInfo.crit = threshold(vm["critical"].as<std::wstring>());
115                 } catch (const std::invalid_argument& e) {
116                         std::cout << e.what() << '\n';
117                         return 3;
118                 }
119         }
120
121         if (vm.count("user"))
122                 printInfo.user = vm["user"].as<std::wstring>();
123
124         l_Debug = vm.count("debug") > 0;
125
126         return -1;
127 }
128
129 static int printOutput(const int numProcs, printInfoStruct& printInfo)
130 {
131         if (l_Debug)
132                 std::wcout << L"Constructing output string" << '\n';
133
134         state state = OK;
135
136         if (printInfo.warn.rend(numProcs))
137                 state = WARNING;
138
139         if (printInfo.crit.rend(numProcs))
140                 state = CRITICAL;
141
142         std::wstring user;
143         if (!printInfo.user.empty())
144                 user = L" processes of user " + printInfo.user;
145
146         std::wcout << L"PROCS ";
147
148         switch (state) {
149         case OK:
150                 std::wcout << L"OK";
151                 break;
152         case WARNING:
153                 std::wcout << L"WARNING";
154                 break;
155         case CRITICAL:
156                 std::wcout << L"CRITICAL";
157                 break;
158         }
159
160         std::wcout << L" " << numProcs << user << L" | procs=" << numProcs << L";"
161                 << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n';
162
163         return state;
164 }
165
166 static int countProcs()
167 {
168         if (l_Debug)
169                 std::wcout << L"Counting all processes" << '\n';
170
171         if (l_Debug)
172                 std::wcout << L"Creating snapshot" << '\n';
173
174         HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
175         if (hProcessSnap == INVALID_HANDLE_VALUE)
176                 return -1;
177
178         PROCESSENTRY32 pe32;
179         pe32.dwSize = sizeof(PROCESSENTRY32);
180
181         if (l_Debug)
182                 std::wcout << L"Grabbing first proccess" << '\n';
183
184         if (!Process32First(hProcessSnap, &pe32)) {
185                 CloseHandle(hProcessSnap);
186                 return -1;
187         }
188
189         if (l_Debug)
190                 std::wcout << L"Counting processes..." << '\n';
191
192         int numProcs = 0;
193
194         do {
195                 ++numProcs;
196         } while (Process32Next(hProcessSnap, &pe32));
197
198         if (l_Debug)
199                 std::wcout << L"Found " << numProcs << L" processes. Cleaning up udn returning" << '\n';
200
201         CloseHandle(hProcessSnap);
202
203         return numProcs;
204 }
205
206 static int countProcs(const std::wstring& user)
207 {
208         if (l_Debug)
209                 std::wcout << L"Counting all processes of user" << user << '\n';
210
211         const WCHAR *wuser = user.c_str();
212         int numProcs = 0;
213
214         HANDLE hProcessSnap, hProcess = NULL, hToken = NULL;
215         PROCESSENTRY32 pe32;
216         DWORD dwReturnLength, dwAcctName, dwDomainName;
217         PTOKEN_USER pSIDTokenUser = NULL;
218         SID_NAME_USE sidNameUse;
219         LPWSTR AcctName, DomainName;
220
221         if (l_Debug)
222                 std::wcout << L"Creating snapshot" << '\n';
223
224         hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
225         if (hProcessSnap == INVALID_HANDLE_VALUE)
226                 goto die;
227
228         pe32.dwSize = sizeof(PROCESSENTRY32);
229
230         if (l_Debug)
231                 std::wcout << L"Grabbing first proccess" << '\n';
232
233         if (!Process32First(hProcessSnap, &pe32))
234                 goto die;
235
236         if (l_Debug)
237                 std::wcout << L"Counting processes..." << '\n';
238
239         do {
240                 if (l_Debug)
241                         std::wcout << L"Getting process token" << '\n';
242
243                 //get ProcessToken
244                 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
245                 if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
246                         //Won't count pid 0 (system idle) and 4/8 (Sytem)
247                         continue;
248
249                 //Get dwReturnLength in first call
250                 dwReturnLength = 1;
251                 if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength)
252                         && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
253                         continue;
254
255                 pSIDTokenUser = reinterpret_cast<PTOKEN_USER>(new BYTE[dwReturnLength]);
256                 memset(pSIDTokenUser, 0, dwReturnLength);
257
258                 if (l_Debug)
259                         std::wcout << L"Received token, saving information" << '\n';
260
261                 //write Info in pSIDTokenUser
262                 if (!GetTokenInformation(hToken, TokenUser, pSIDTokenUser, dwReturnLength, NULL))
263                         continue;
264
265                 AcctName = NULL;
266                 DomainName = NULL;
267                 dwAcctName = 1;
268                 dwDomainName = 1;
269
270                 if (l_Debug)
271                         std::wcout << L"Looking up SID" << '\n';
272
273                 //get dwAcctName and dwDomainName size
274                 if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
275                         (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse)
276                         && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
277                         continue;
278
279                 AcctName = reinterpret_cast<LPWSTR>(new WCHAR[dwAcctName]);
280                 DomainName = reinterpret_cast<LPWSTR>(new WCHAR[dwDomainName]);
281
282                 if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
283                         (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse))
284                         continue;
285
286                 if (l_Debug)
287                         std::wcout << L"Comparing " << AcctName << L" to " << wuser << '\n';
288                 if (!wcscmp(AcctName, wuser)) {
289                         ++numProcs;
290                         if (l_Debug)
291                                 std::wcout << L"Is process of " << wuser << L" (" << numProcs << L")" << '\n';
292                 }
293
294                 delete[] reinterpret_cast<LPWSTR>(AcctName);
295                 delete[] reinterpret_cast<LPWSTR>(DomainName);
296
297         } while (Process32Next(hProcessSnap, &pe32));
298
299 die:
300         if (hProcessSnap)
301                 CloseHandle(hProcessSnap);
302         if (hProcess)
303                 CloseHandle(hProcess);
304         if (hToken)
305                 CloseHandle(hToken);
306         if (pSIDTokenUser)
307                 delete[] reinterpret_cast<PTOKEN_USER>(pSIDTokenUser);
308         return numProcs;
309 }
310
311 int wmain(int argc, WCHAR **argv)
312 {
313         po::variables_map vm;
314         printInfoStruct printInfo = { };
315
316         int r = parseArguments(argc, argv, vm, printInfo);
317
318         if (r != -1)
319                 return r;
320
321         if (!printInfo.user.empty())
322                 return printOutput(countProcs(printInfo.user), printInfo);
323
324         return printOutput(countProcs(), printInfo);
325 }