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