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