]> granicus.if.org Git - icinga2/blob - plugins/check_swap.cpp
Make UnameHelper() efficient
[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
200         if (printInfo.crit.rend(currentValue, printInfo.tSwap))
201                 state = CRITICAL;
202
203         std::wcout << stateToString(state) << " ";
204
205         if (!printInfo.showUsed)
206                 std::wcout << printInfo.percentFree << L"% free ";
207         else
208                 std::wcout << 100 - printInfo.percentFree << L"% used ";
209
210         std::wcout << "| 'swap'=" << currentValue << BunitStr(printInfo.unit) << L";"
211                 << printInfo.warn.pString(printInfo.tSwap) << L";" << printInfo.crit.pString(printInfo.tSwap)
212                 << L";0;" << printInfo.tSwap << '\n';
213
214         return state;
215 }
216
217 static int check_swap(printInfoStruct& printInfo)
218 {
219         PENUM_PAGE_FILE_CALLBACK pageFileCallback = &EnumPageFilesProc;
220         std::vector<pageFileInfo> pageFiles;
221
222         if(!EnumPageFiles(pageFileCallback, &pageFiles)) {
223                 printErrorInfo();
224                 return 3;
225         }
226
227         for (int i = 0; i < pageFiles.size(); i++) {
228                 printInfo.tSwap += round(pageFiles.at(i).totalSwap / pow(1024.0, printInfo.unit));
229                 printInfo.aSwap += round(pageFiles.at(i).availableSpwap / pow(1024.0, printInfo.unit));
230         }
231
232         printInfo.percentFree = 100.0 * printInfo.aSwap / printInfo.tSwap;
233
234         return -1;
235 }
236
237 int wmain(int argc, WCHAR **argv)
238 {
239         printInfoStruct printInfo = { };
240         po::variables_map vm;
241
242         int ret = parseArguments(argc, argv, vm, printInfo);
243         if (ret != -1)
244                 return ret;
245
246         ret = check_swap(printInfo);
247         if (ret != -1)
248                 return ret;
249
250         return printOutput(printInfo);
251 }