]> granicus.if.org Git - icinga2/blob - plugins/check_swap.cpp
Merge pull request #6718 from Icinga/bugfix/ssl-shutdown
[icinga2] / plugins / check_swap.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://icinga.com/)      *
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
20 #include "plugins/thresholds.hpp"
21 #include <boost/program_options.hpp>
22 #include <iostream>
23 #include <shlwapi.h>
24 #include <Psapi.h>
25 #include <vector>
26
27 #define VERSION 1.0
28
29 namespace po = boost::program_options;
30
31 struct printInfoStruct
32 {
33         threshold warn;
34         threshold crit;
35         double tSwap;
36         double aSwap;
37         double percentFree;
38         Bunit unit = BunitMB;
39         bool showUsed;
40 };
41
42 struct pageFileInfo
43 {
44         SIZE_T totalSwap;
45         SIZE_T availableSpwap;
46 };
47
48 static bool l_Debug;
49
50 BOOL EnumPageFilesProc(LPVOID pContext, PENUM_PAGE_FILE_INFORMATION pPageFileInfo, LPCTSTR lpFilename) {
51         std::vector<pageFileInfo>* pageFile = static_cast<std::vector<pageFileInfo>*>(pContext);
52         SYSTEM_INFO systemInfo;
53
54         GetSystemInfo(&systemInfo);
55
56         // pPageFileInfo output is in pages, we need to multiply it by the page size
57         pageFile->push_back({ pPageFileInfo->TotalSize * systemInfo.dwPageSize, (pPageFileInfo->TotalSize - pPageFileInfo->TotalInUse) * systemInfo.dwPageSize });
58
59         return TRUE;
60 }
61
62 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
63 {
64         WCHAR namePath[MAX_PATH];
65         GetModuleFileName(NULL, namePath, MAX_PATH);
66         WCHAR *progName = PathFindFileName(namePath);
67
68         po::options_description desc;
69
70         desc.add_options()
71                 ("help,h", "Print help message and exit")
72                 ("version,V", "Print version and exit")
73                 ("debug,d", "Verbose/Debug output")
74                 ("warning,w", po::wvalue<std::wstring>(), "Warning threshold")
75                 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
76                 ("unit,u", po::wvalue<std::wstring>(), "The unit to use for display (default MB)")
77                 ("show-used,U", "Show used swap instead of the free swap")
78                 ;
79
80         po::wcommand_line_parser parser(ac, av);
81
82         try {
83                 po::store(
84                         parser
85                         .options(desc)
86                         .style(
87                                 po::command_line_style::unix_style |
88                                 po::command_line_style::allow_long_disguise)
89                         .run(),
90                         vm);
91                 vm.notify();
92         } catch (const std::exception& e) {
93                 std::cout << e.what() << '\n' << desc << '\n';
94                 return 3;
95         }
96
97         if (vm.count("help")) {
98                 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
99                 wprintf(
100                         L"%s is a simple program to check a machines swap in percent.\n"
101                         L"You can use the following options to define its behaviour:\n\n", progName);
102                 std::cout << desc;
103                 wprintf(
104                         L"\nIt will then output a string looking something like this:\n\n"
105                         L"\tSWAP WARNING - 20%% free | swap=2000B;3000;500;0;10000\n\n"
106                         L"\"SWAP\" being the type of the check, \"WARNING\" the returned status\n"
107                         L"and \"20%%\" is the returned value.\n"
108                         L"The performance data is found behind the \"|\", in order:\n"
109                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
110                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
111                         L"you set at least one threshold\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"Threshold syntax:\n\n"
118                         L"-w THRESHOLD\n"
119                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
120                         L"(unless stated differently)\n\n"
121                         L"-w !THRESHOLD\n"
122                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
123                         L"-w [THR1-THR2]\n"
124                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
125                         L"-w ![THR1-THR2]\n"
126                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
127                         L"-w THRESHOLD%%\n"
128                         L"if the plugin accepts percentage based thresholds those will be used.\n"
129                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
130                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
131                         L"to end with a percentage sign.\n\n"
132                         L"All of these options work with the critical threshold \"-c\" too.\n"
133                         , progName);
134                 std::cout << '\n';
135                 return 0;
136         }
137
138         if (vm.count("version"))
139                 std::wcout << L"Version: " << VERSION << '\n';
140
141         if (vm.count("warning")) {
142                 try {
143                         printInfo.warn = threshold(vm["warning"].as<std::wstring>());
144                 } catch (const std::invalid_argument& e) {
145                         std::cout << e.what() << '\n';
146                         return 3;
147                 }
148                 printInfo.warn.legal = !printInfo.warn.legal;
149         }
150
151         if (vm.count("critical")) {
152                 try {
153                         printInfo.crit = threshold(vm["critical"].as<std::wstring>());
154                 } catch (const std::invalid_argument& e) {
155                         std::cout << e.what() << '\n';
156                         return 3;
157                 }
158                 printInfo.crit.legal = !printInfo.crit.legal;
159         }
160
161         l_Debug = vm.count("debug") > 0;
162
163         if (vm.count("unit")) {
164                 try {
165                         printInfo.unit = parseBUnit(vm["unit"].as<std::wstring>());
166                 } catch (const std::invalid_argument& e) {
167                         std::cout << e.what() << '\n';
168                         return 3;
169                 }
170         }
171
172         if (vm.count("show-used")) {
173                 printInfo.showUsed = true;
174                 printInfo.warn.legal = true;
175                 printInfo.crit.legal = true;
176         }
177
178         return -1;
179 }
180
181 static int printOutput(printInfoStruct& printInfo)
182 {
183         if (l_Debug)
184                 std::wcout << L"Constructing output string" << '\n';
185
186         state state = OK;
187
188         std::wcout << L"SWAP ";
189
190         double currentValue;
191
192         if (!printInfo.showUsed)
193                 currentValue = printInfo.aSwap;
194         else
195                 currentValue = printInfo.tSwap - printInfo.aSwap;
196
197         if (printInfo.warn.rend(currentValue, printInfo.tSwap)) {
198                 state = WARNING;
199                 std::wcout << L"WARNING - ";
200         } else if (printInfo.crit.rend(currentValue, printInfo.tSwap)) {
201                 state = CRITICAL;
202                 std::wcout << L"CRITICAL - ";
203         } else {
204                 state = OK;
205                 std::wcout << L"OK - ";
206         }
207
208         if (!printInfo.showUsed)
209                 std::wcout << printInfo.percentFree << L"% free ";
210         else
211                 std::wcout << 100 - printInfo.percentFree << L"% used ";
212
213         std::wcout << "| 'swap'=" << currentValue << BunitStr(printInfo.unit) << L";"
214                 << printInfo.warn.pString(printInfo.tSwap) << L";" << printInfo.crit.pString(printInfo.tSwap)
215                 << L";0;" << printInfo.tSwap << '\n';
216
217         return state;
218 }
219
220 static int check_swap(printInfoStruct& printInfo)
221 {
222         PENUM_PAGE_FILE_CALLBACK pageFileCallback = &EnumPageFilesProc;
223         std::vector<pageFileInfo> pageFiles;
224
225         if(!EnumPageFiles(pageFileCallback, &pageFiles)) {
226                 printErrorInfo();
227                 return 3;
228         }
229
230         for (int i = 0; i < pageFiles.size(); i++) {
231                 printInfo.tSwap += round(pageFiles.at(i).totalSwap / pow(1024.0, printInfo.unit));
232                 printInfo.aSwap += round(pageFiles.at(i).availableSpwap / pow(1024.0, printInfo.unit));
233         }
234
235         printInfo.percentFree = 100.0 * printInfo.aSwap / printInfo.tSwap;
236
237         return -1;
238 }
239
240 int wmain(int argc, WCHAR **argv)
241 {
242         printInfoStruct printInfo = { };
243         po::variables_map vm;
244
245         int ret = parseArguments(argc, argv, vm, printInfo);
246         if (ret != -1)
247                 return ret;
248
249         ret = check_swap(printInfo);
250         if (ret != -1)
251                 return ret;
252
253         return printOutput(printInfo);
254 }