1 /******************************************************************************
3 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
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 ******************************************************************************/
26 #include "thresholds.h"
28 #include "boost/program_options.hpp"
32 namespace po = boost::program_options;
34 using std::cout; using std::endl; using std::set;
35 using std::vector; using std::wstring; using std::wcout;
46 struct printInfoStruct
49 vector<wstring> drives;
53 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
54 static int printOutput(printInfoStruct&, vector<drive>&);
55 static int check_drives(vector<drive>&);
56 static int check_drives(vector<drive>&, printInfoStruct&);
57 static bool getFreeAndCap(drive&, const Bunit&);
59 int wmain(int argc, wchar_t **argv)
61 vector<drive> vDrives;
62 printInfoStruct printInfo{ false, false};
67 ret = parseArguments(argc, argv, vm, printInfo);
71 if (printInfo.drives.empty())
72 ret = check_drives(vDrives);
74 ret = check_drives(vDrives, printInfo);
79 for (vector<drive>::iterator it = vDrives.begin(); it != vDrives.end(); ++it) {
80 if (!getFreeAndCap(*it, printInfo.unit))
84 return printOutput(printInfo, vDrives);
87 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo)
89 wchar_t namePath[MAX_PATH];
90 GetModuleFileName(NULL, namePath, MAX_PATH);
91 wchar_t *progName = PathFindFileName(namePath);
93 po::options_description desc("Options");
96 (",h", "print usage message and exit")
97 ("help", "print help message and exit")
98 ("version,v", "print version and exit")
99 ("warning,w", po::wvalue<wstring>(), "warning threshold")
100 ("critical,c", po::wvalue<wstring>(), "critical threshold")
101 ("path,p", po::wvalue<vector<std::wstring>>()->multitoken(), "declare explicitly which drives to check (default checks all)")
102 ("unit,u", po::wvalue<wstring>(), "assign unit possible are: B, kB, MB, GB, TB")
105 po::basic_command_line_parser<wchar_t> parser(ac, av);
112 po::command_line_style::unix_style |
113 po::command_line_style::allow_long_disguise)
117 } catch (std::exception& e) {
118 cout << e.what() << endl << desc << endl;
122 if (vm.count("help")) {
123 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
125 L"%s is a simple program to check a machines free disk space.\n"
126 L"You can use the following options to define its behaviour:\n\n", progName);
129 L"\nIt will then output a string looking something like this:\n\n"
130 L"\tDISK WARNING 29GB|disk=29GB;50%%;5;0;120\n\n"
131 L"\"DISK\" being the type of the check, \"WARNING\" the returned status\n"
132 L"and \"23.8304%%\" is the returned value.\n"
133 L"The performance data is found behind the \"|\", in order:\n"
134 L"returned value, warning threshold, critical threshold, minimal value and,\n"
135 L"if applicable, the maximal value. Performance data will only be displayed when\n"
136 L"you set at least one threshold\n"
137 L"This program will also print out additional performance data disk by disk\n\n"
138 L"%s' exit codes denote the following:\n\n"
139 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
140 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
141 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
142 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
143 L"Threshold syntax:\n\n"
145 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
146 L"(unless stated differently)\n\n"
148 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
150 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
152 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
154 L"if the plugin accepts percentage based thresholds those will be used.\n"
155 L"Does nothing if the plugin does not accept percentages, or only uses\n"
156 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
157 L"to end with a percentage sign.\n\n"
158 L"All of these options work with the critical threshold \"-c\" too."
165 cout << desc << endl;
169 if (vm.count("version"))
170 cout << "Version: " << VERSION << endl;
172 if (vm.count("warning")) {
174 printInfo.warn = threshold(vm["warning"].as<wstring>());
175 } catch (std::invalid_argument& e) {
176 cout << e.what() << endl;
180 if (vm.count("critical")) {
182 printInfo.crit = threshold(vm["critical"].as<wstring>());
183 } catch (std::invalid_argument& e) {
184 cout << e.what() << endl;
189 if (vm.count("path"))
190 printInfo.drives = vm["path"].as<vector<wstring>>();
192 if (vm.count("unit")) {
194 printInfo.unit = parseBUnit(vm["unit"].as<wstring>());
195 } catch (std::invalid_argument) {
196 wcout << L"Unknown unit Type " << vm["unit"].as<wstring>() << endl;
200 printInfo.unit = BunitB;
205 int printOutput(printInfoStruct& printInfo, vector<drive>& vDrives)
208 double tCap = 0, tFree = 0;
209 std::wstringstream perf, prePerf;
210 wstring unit = BunitStr(printInfo.unit);
212 for (vector<drive>::iterator it = vDrives.begin(); it != vDrives.end(); ++it) {
213 tCap += it->cap; tFree += it->free;
214 perf << L" drive=\"" << it->name << L"\";cap=" << it->cap << unit << L";free=" << it->free << unit;
217 prePerf << L"|disk=" << tFree << unit << L";" << printInfo.warn.pString() << L";"
218 << printInfo.crit.pString() << L";0;" << tCap;
220 if (printInfo.warn.perc) {
221 if (printInfo.warn.rend((tFree / tCap) * 100.0))
224 if (printInfo.warn.rend(tFree))
228 if (printInfo.crit.perc) {
229 if (printInfo.crit.rend((tFree / tCap) * 100.0))
232 if (printInfo.crit.rend(tFree))
238 wcout << L"DISK OK " << tFree << unit << prePerf.str() << perf.str() << endl;
241 wcout << L"DISK WARNING " << tFree << unit << prePerf.str() << perf.str() << endl;
244 wcout << L"DISK CRITICAL " << tFree << unit << prePerf.str() << perf.str() << endl;
251 int check_drives(vector<drive>& vDrives)
253 DWORD dwResult, dwSize = 0, dwVolumePathNamesLen = MAX_PATH + 1;
254 wchar_t szLogicalDrives[MAX_PATH], szVolumeName[MAX_PATH], *szVolumePathNames;
256 wstring wsLogicalDrives;
257 size_t volumeNameEnd = 0;
259 set<wstring> sDrives;
261 dwResult = GetLogicalDriveStrings(MAX_PATH, szLogicalDrives);
262 if (dwResult < 0 || dwResult > MAX_PATH)
265 LPTSTR szSingleDrive = szLogicalDrives;
266 while (*szSingleDrive) {
267 wstring drname = szSingleDrive;
268 sDrives.insert(drname);
269 szSingleDrive += wcslen(szSingleDrive) + 1;
272 hVolume = FindFirstVolume(szVolumeName, MAX_PATH);
273 if (hVolume == INVALID_HANDLE_VALUE)
276 while (GetLastError() != ERROR_NO_MORE_FILES) {
277 volumeNameEnd = wcslen(szVolumeName) - 1;
278 szVolumePathNames = reinterpret_cast<wchar_t*>(new WCHAR[dwVolumePathNamesLen]);
280 while (!GetVolumePathNamesForVolumeName(szVolumeName, szVolumePathNames, dwVolumePathNamesLen, &dwVolumePathNamesLen)) {
281 if (GetLastError() != ERROR_MORE_DATA)
283 delete[] reinterpret_cast<wchar_t*>(szVolumePathNames);
284 szVolumePathNames = reinterpret_cast<wchar_t*>(new WCHAR[dwVolumePathNamesLen]);
288 sDrives.insert(wstring(szVolumePathNames));
289 FindNextVolume(hVolume, szVolumeName, MAX_PATH);
292 for (set<wstring>::iterator it = sDrives.begin(); it != sDrives.end(); ++it) {
293 UINT type = GetDriveType(it->c_str());
294 if (type == DRIVE_FIXED || type == DRIVE_REMOTE) {
295 vDrives.push_back(drive(*it));
302 FindVolumeClose(hVolume);
307 int check_drives(vector<drive>& vDrives, printInfoStruct& printInfo)
309 wchar_t *slash = L"\\";
311 for (vector<wstring>::iterator it = printInfo.drives.begin();
312 it != printInfo.drives.end(); ++it) {
313 if (it->at(it->length() - 1) != *slash)
316 vDrives.push_back(drive(*it));
321 bool getFreeAndCap(drive& drive, const Bunit& unit)
323 ULARGE_INTEGER tempFree, tempTotal;
324 if (!GetDiskFreeSpaceEx(drive.name.c_str(), NULL, &tempTotal, &tempFree)) {
328 drive.cap = (tempTotal.QuadPart / pow(1024.0, unit));
329 drive.free = (tempFree.QuadPart / pow(1024.0, unit));