1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://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>
29 namespace po = boost::program_options;
31 struct printInfoStruct
40 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
42 WCHAR namePath[MAX_PATH];
43 GetModuleFileName(NULL, namePath, MAX_PATH);
44 WCHAR *progName = PathFindFileName(namePath);
46 po::options_description desc;
49 ("help,h", "Print help message and exit")
50 ("version,V", "Print version and exit")
51 ("debug,d", "Verbose/Debug output")
52 ("user,u", po::wvalue<std::wstring>(), "Count only processes of user")
53 ("warning,w", po::wvalue<std::wstring>(), "Warning threshold")
54 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
57 po::wcommand_line_parser parser(ac, av);
64 po::command_line_style::unix_style |
65 po::command_line_style::allow_long_disguise)
69 } catch (const std::exception& e) {
70 std::cout << e.what() << '\n' << desc << '\n';
74 if (vm.count("help")) {
75 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
77 L"%s is a simple program to check a machines processes.\n"
78 L"You can use the following options to define its behaviour:\n\n", progName);
81 L"\nIt will then output a string looking something like this:\n\n"
82 L"\tPROCS WARNING 67 | load=67;50;90;0\n\n"
83 L"\"PROCS\" being the type of the check, \"WARNING\" the returned status\n"
84 L"and \"67\" is the returned value.\n"
85 L"The performance data is found behind the \"|\", in order:\n"
86 L"returned value, warning threshold, critical threshold, minimal value and,\n"
87 L"if applicable, the maximal value. Performance data will only be displayed when\n"
88 L"you set at least one threshold\n\n"
89 L"For \"-user\" option keep in mind you need root to see other users processes\n\n"
90 L"%s' exit codes denote the following:\n"
91 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
92 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
93 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
94 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
95 L"Threshold syntax:\n\n"
97 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
98 L"(unless stated differently)\n\n"
100 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
102 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
104 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
106 L"if the plugin accepts percentage based thresholds those will be used.\n"
107 L"Does nothing if the plugin does not accept percentages, or only uses\n"
108 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
109 L"to end with a percentage sign.\n\n"
110 L"All of these options work with the critical threshold \"-c\" too."
116 if (vm.count("version")) {
117 std::wcout << "Version: " << VERSION << '\n';
121 if (vm.count("warning")) {
123 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
124 } catch (const std::invalid_argument& e) {
125 std::cout << e.what() << '\n';
129 if (vm.count("critical")) {
131 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
132 } catch (const std::invalid_argument& e) {
133 std::cout << e.what() << '\n';
138 if (vm.count("user"))
139 printInfo.user = vm["user"].as<std::wstring>();
141 l_Debug = vm.count("debug") > 0;
146 static int printOutput(const int numProcs, printInfoStruct& printInfo)
149 std::wcout << L"Constructing output string" << '\n';
153 if (printInfo.warn.rend(numProcs))
156 if (printInfo.crit.rend(numProcs))
160 if (!printInfo.user.empty())
161 user = L" processes of user " + printInfo.user;
163 std::wcout << L"PROCS ";
170 std::wcout << L"WARNING";
173 std::wcout << L"CRITICAL";
177 std::wcout << L" " << numProcs << user << L" | procs=" << numProcs << L";"
178 << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n';
183 static int countProcs()
186 std::wcout << L"Counting all processes" << '\n';
189 std::wcout << L"Creating snapshot" << '\n';
191 HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
192 if (hProcessSnap == INVALID_HANDLE_VALUE)
196 pe32.dwSize = sizeof(PROCESSENTRY32);
199 std::wcout << L"Grabbing first proccess" << '\n';
201 if (!Process32First(hProcessSnap, &pe32)) {
202 CloseHandle(hProcessSnap);
207 std::wcout << L"Counting processes..." << '\n';
213 } while (Process32Next(hProcessSnap, &pe32));
216 std::wcout << L"Found " << numProcs << L" processes. Cleaning up udn returning" << '\n';
218 CloseHandle(hProcessSnap);
223 static int countProcs(const std::wstring& user)
226 std::wcout << L"Counting all processes of user" << user << '\n';
228 const WCHAR *wuser = user.c_str();
231 HANDLE hProcessSnap, hProcess = NULL, hToken = NULL;
233 DWORD dwReturnLength, dwAcctName, dwDomainName;
234 PTOKEN_USER pSIDTokenUser = NULL;
235 SID_NAME_USE sidNameUse;
236 LPWSTR AcctName, DomainName;
239 std::wcout << L"Creating snapshot" << '\n';
241 hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
242 if (hProcessSnap == INVALID_HANDLE_VALUE)
245 pe32.dwSize = sizeof(PROCESSENTRY32);
248 std::wcout << L"Grabbing first proccess" << '\n';
250 if (!Process32First(hProcessSnap, &pe32))
254 std::wcout << L"Counting processes..." << '\n';
258 std::wcout << L"Getting process token" << '\n';
261 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
262 if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
263 //Won't count pid 0 (system idle) and 4/8 (Sytem)
266 //Get dwReturnLength in first call
268 if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength)
269 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
272 pSIDTokenUser = reinterpret_cast<PTOKEN_USER>(new BYTE[dwReturnLength]);
273 memset(pSIDTokenUser, 0, dwReturnLength);
276 std::wcout << L"Received token, saving information" << '\n';
278 //write Info in pSIDTokenUser
279 if (!GetTokenInformation(hToken, TokenUser, pSIDTokenUser, dwReturnLength, NULL))
288 std::wcout << L"Looking up SID" << '\n';
290 //get dwAcctName and dwDomainName size
291 if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
292 (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse)
293 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
296 AcctName = reinterpret_cast<LPWSTR>(new WCHAR[dwAcctName]);
297 DomainName = reinterpret_cast<LPWSTR>(new WCHAR[dwDomainName]);
299 if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
300 (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse))
304 std::wcout << L"Comparing " << AcctName << L" to " << wuser << '\n';
305 if (!wcscmp(AcctName, wuser)) {
308 std::wcout << L"Is process of " << wuser << L" (" << numProcs << L")" << '\n';
311 delete[] reinterpret_cast<LPWSTR>(AcctName);
312 delete[] reinterpret_cast<LPWSTR>(DomainName);
314 } while (Process32Next(hProcessSnap, &pe32));
318 CloseHandle(hProcessSnap);
320 CloseHandle(hProcess);
324 delete[] reinterpret_cast<PTOKEN_USER>(pSIDTokenUser);
328 int wmain(int argc, WCHAR **argv)
330 po::variables_map vm;
331 printInfoStruct printInfo = { };
333 int r = parseArguments(argc, argv, vm, printInfo);
338 if (!printInfo.user.empty())
339 return printOutput(countProcs(printInfo.user), printInfo);
341 return printOutput(countProcs(), printInfo);