]> granicus.if.org Git - icinga2/commitdiff
Add Windows plugins
authorJean Flach <jean-marcel.flach@netways.de>
Thu, 6 Nov 2014 14:17:08 +0000 (15:17 +0100)
committerJean Flach <jean-marcel.flach@netways.de>
Thu, 6 Nov 2014 14:17:08 +0000 (15:17 +0100)
refs #7242

14 files changed:
CMakeLists.txt
plugins/CMakeLists.txt [new file with mode: 0644]
plugins/README.md [new file with mode: 0644]
plugins/check_disk.cpp [new file with mode: 0644]
plugins/check_load.cpp [new file with mode: 0644]
plugins/check_network.cpp [new file with mode: 0644]
plugins/check_procs.cpp [new file with mode: 0644]
plugins/check_service.cpp [new file with mode: 0644]
plugins/check_swap.cpp [new file with mode: 0644]
plugins/check_update.cpp [new file with mode: 0644]
plugins/check_uptime.cpp [new file with mode: 0644]
plugins/check_users.cpp [new file with mode: 0644]
plugins/thresholds.cpp [new file with mode: 0644]
plugins/thresholds.h [new file with mode: 0644]

index 4946db376214ce4408a169aa19233f6743aba76f..d1055456b733c959e7d1704b702612a4677ad006 100644 (file)
@@ -171,6 +171,7 @@ add_subdirectory(itl)
 add_subdirectory(doc)
 add_subdirectory(test)
 add_subdirectory(agent)
+add_subdirectory(plugins)
 
 set(CPACK_PACKAGE_NAME "Icinga2")
 set(CPACK_PACKAGE_VENDOR "Icinga Development Team")
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644 (file)
index 0000000..098424e
--- /dev/null
@@ -0,0 +1,91 @@
+if(WIN32)
+  add_definitions(-DUNICODE -D_UNICODE)
+
+  add_library(thresholds thresholds)
+
+  add_executable(check_disk check_disk.cpp)
+  target_link_libraries(check_disk thresholds Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_disk PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+
+  add_executable(check_load check_load.cpp)
+  target_link_libraries(check_load thresholds Pdh.lib Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_load PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_network check_network.cpp)
+  target_link_libraries(check_network thresholds Pdh.lib Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_network PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_procs check_procs.cpp)
+  target_link_libraries(check_procs thresholds Pdh.lib Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_procs PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_service check_service.cpp)
+  target_link_libraries(check_service thresholds Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_service PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_swap check_swap.cpp)
+  target_link_libraries(check_swap thresholds Pdh.lib Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_swap PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_update check_update.cpp)
+  target_link_libraries(check_update thresholds Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_update PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_uptime check_uptime.cpp)
+  target_link_libraries(check_uptime thresholds ${Boost_SYSTEM_LIBRARY} Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+  set_target_properties (
+    check_uptime PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+  add_executable(check_users check_users.cpp)
+  target_link_libraries(check_users thresholds wtsapi32.lib Shlwapi.lib ${Boost_PROGRAM_OPTIONS_LIBRARY})
+         set_target_properties (
+    check_users PROPERTIES
+    INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+    DEFINE_SYMBOL I2_PLUGINS_BUILD
+    FOLDER Plugins
+  )
+       
+       install(
+    TARGETS check_disk check_load check_network check_procs check_service check_swap check_update check_uptime check_users
+    RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
+  )    
+endif()
\ No newline at end of file
diff --git a/plugins/README.md b/plugins/README.md
new file mode 100644 (file)
index 0000000..32380c0
--- /dev/null
@@ -0,0 +1,17 @@
+##icinga 2 plugins for Windows##
+Thhis collection of plugins is intended to provide basic functinality checks on windows machines. They (mostly) conform to the [nagios developer guidelines](https://nagios-plugins.org/doc/guidelines.html), returning adequate exit codes and printing a pertinent string with performance data.
+
+###Intallation###
+//TODO
+
+###Requirements###
+- Boost 1.41.0
+- Windows Vista, Windows Server 2008 or newer
+- C99 ?
+
+###Usage###
+Call a plugin with the "--help" option to recive information about its usage.
+
+###License###
+gnu stuff
+//todo
\ No newline at end of file
diff --git a/plugins/check_disk.cpp b/plugins/check_disk.cpp
new file mode 100644 (file)
index 0000000..c9eed31
--- /dev/null
@@ -0,0 +1,315 @@
+#include <Windows.h>
+#include <set>
+#include <Shlwapi.h>
+#include <vector>
+#include <iostream>
+#include <math.h>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::cout; using std::endl; using std::set;
+using std::vector; using std::wstring; using std::wcout;
+
+struct drive {
+       wstring name;
+       double cap, free;
+       drive(wstring p)
+               : name(p)
+       {}
+};
+
+struct printInfoStruct {
+       threshold warn, crit;
+       vector<wstring> drives;
+       Bunit unit;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&, vector<drive>&);
+static int check_drives(vector<drive>&);
+static int check_drives(vector<drive>&, printInfoStruct&);
+static bool getFreeAndCap(drive&, const Bunit&);
+static void die();
+
+int wmain(int argc, wchar_t **argv) 
+{
+       vector<drive> vDrives;
+       printInfoStruct printInfo{ false, false};
+       po::variables_map vm;
+
+       int ret;
+
+       ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       if (printInfo.drives.empty())
+               ret = check_drives(vDrives);
+       else
+               ret = check_drives(vDrives, printInfo);
+       
+       if (ret != -1)
+               return ret;
+
+       for (vector<drive>::iterator it = vDrives.begin(); it != vDrives.end(); ++it) {
+               if (!getFreeAndCap(*it, printInfo.unit)) {
+                       return 3;
+               }
+       }
+
+       return printOutput(printInfo, vDrives);
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) 
+{
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc("Options");
+
+       desc.add_options()
+               (",h", "print usage message and exit")
+               ("help", "print help message and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning threshold")
+               ("critical,c", po::wvalue<wstring>(), "critical threshold")
+               ("drives,d", po::wvalue<vector<std::wstring>>()->multitoken(), "declare explicitly which drives to check (default checks all)")
+               ("unit,u", po::wvalue<wstring>(), "assign unit possible are: B, kB, MB, GB, TB")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines free disk space.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tDISK WARNING 29GB|disk=29GB;50%%;5;0;120\n\n"
+                       L"\"DISK\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"23.8304%%\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value. Performance data will onl be displayed when\n"
+                       L"you set at least one threshold\n"
+                       L"This program will also print out additional performance data disk by disk\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too."
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+
+       if (vm.count("version"))
+               cout << "Version: " << VERSION << endl;
+
+       if (vm.count("warning")) 
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+       
+
+       if (vm.count("critical")) 
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+       
+       if (vm.count("drives")) 
+               printInfo.drives = vm["drives"].as<vector<wstring>>();
+
+       if (vm.count("unit"))
+               printInfo.unit = parseBUnit(vm["unit"].as<wstring>().c_str());
+       else {
+               printInfo.unit = BunitB;
+       }
+       return -1;
+}
+
+int printOutput(printInfoStruct& printInfo, vector<drive>& vDrives) 
+{
+       state state = OK;
+       double tCap = 0, tFree = 0;
+       std::wstringstream perf, prePerf;
+       wstring unit = BunitStr(printInfo.unit);
+
+       for (vector<drive>::iterator it = vDrives.begin(); it != vDrives.end(); ++it) {
+               tCap += it->cap; tFree += it->free;
+               perf << L" drive=\"" << it->name << L"\";cap=" << it->cap << unit << L";free=" << it->free << unit;
+       }
+
+       if (!printInfo.warn.set && !printInfo.crit.set) {
+               wcout << L"DISK OK " << tFree << unit << endl;
+       }
+
+       prePerf << L"|disk=" << tFree << unit << L";" << printInfo.warn.pString() << L";"
+               << printInfo.crit.pString() << L";0;" << tCap;
+
+       if (printInfo.warn.perc) {
+               if (printInfo.warn.rend((tFree / tCap) * 100.0))
+                       state = WARNING;
+       } else {
+               if (printInfo.warn.rend(tFree))
+                       state = WARNING;
+       }
+       if (printInfo.crit.perc) {
+               if (printInfo.crit.rend((tFree / tCap) * 100.0))
+                       state = CRITICAL;
+       } else {
+               if (printInfo.crit.rend(tFree))
+                       state = CRITICAL;
+       }
+
+
+
+       switch (state) {
+       case OK:
+               wcout << L"DISK OK " << tFree << unit << prePerf.str() << perf.str() << endl;
+               break;
+       case WARNING:
+               wcout << L"DISK WARNING " << tFree << unit << prePerf.str() << perf.str() << endl;
+               break;
+       case CRITICAL:
+               wcout << L"DISK CRITICAL " << tFree << unit << prePerf.str() << perf.str() << endl;
+               break;
+       }
+
+       return state;
+}
+
+int check_drives(vector<drive>& vDrives) 
+{
+       DWORD dwResult, dwSize = 0, dwVolumePathNamesLen = MAX_PATH + 1;
+       wchar_t szLogicalDrives[MAX_PATH], szVolumeName[MAX_PATH], *szVolumePathNames;
+       HANDLE hVolume;
+       wstring wsLogicalDrives;
+       size_t volumeNameEnd = 0;
+
+       set<wstring> sDrives;
+
+       dwResult = GetLogicalDriveStrings(MAX_PATH, szLogicalDrives);
+       if (dwResult < 0 || dwResult > MAX_PATH) 
+               goto die;
+       
+       LPTSTR szSingleDrive = szLogicalDrives;
+       while (*szSingleDrive) {
+               wstring drname = szSingleDrive;
+               sDrives.insert(drname);
+               szSingleDrive += wcslen(szSingleDrive) + 1;
+       }
+
+       hVolume = FindFirstVolume(szVolumeName, MAX_PATH);
+       if (hVolume == INVALID_HANDLE_VALUE)
+               goto die;
+
+       while (GetLastError() != ERROR_NO_MORE_FILES) {
+               volumeNameEnd = wcslen(szVolumeName) - 1;
+               szVolumePathNames = (PWCHAR) new BYTE[dwVolumePathNamesLen * sizeof(wchar_t)];
+
+               while (!GetVolumePathNamesForVolumeName(szVolumeName, szVolumePathNames, dwVolumePathNamesLen, &dwVolumePathNamesLen)) {
+                       if (GetLastError() != ERROR_MORE_DATA)
+                               break;
+                       delete[] szVolumePathNames;
+                       szVolumePathNames = (PWCHAR) new BYTE[dwVolumePathNamesLen * sizeof(wchar_t)];
+
+               }
+
+               sDrives.insert(wstring(szVolumePathNames));
+               FindNextVolume(hVolume, szVolumeName, MAX_PATH);
+       }
+
+       for (set<wstring>::iterator it = sDrives.begin(); it != sDrives.end(); ++it) {
+               UINT type = GetDriveType(it->c_str());
+               if (type == DRIVE_FIXED || type == DRIVE_REMOTE) {
+                       vDrives.push_back(drive(*it));
+               }
+       }
+       return -1;
+die:
+       if (hVolume)
+               FindVolumeClose(hVolume);
+       die();
+       return 3;
+}
+
+int check_drives(vector<drive>& vDrives, printInfoStruct& printInfo) 
+{
+       wchar_t *slash = L"\\";
+
+       for (vector<wstring>::iterator it = printInfo.drives.begin();
+                       it != printInfo.drives.end(); ++it) {
+               if (it->at(it->length() - 1) != *slash)
+                       it->append(slash);
+
+               vDrives.push_back(drive(*it));
+       }
+       return -1;
+}
+
+bool getFreeAndCap(drive& drive, const Bunit& unit) 
+{
+       ULARGE_INTEGER tempFree, tempTotal;
+       if (!GetDiskFreeSpaceEx(drive.name.c_str(), NULL, &tempTotal, &tempFree)) {
+               return FALSE;
+       }
+
+       drive.cap = (tempTotal.QuadPart / pow(1024.0, unit));
+       drive.free = (tempFree.QuadPart / pow(1024.0, unit));
+
+       return TRUE;
+}
+
+void die() 
+{
+       DWORD err = GetLastError();
+       LPWSTR mBuf = NULL;
+       size_t mS = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+           NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&mBuf, 0, NULL);
+       wcout << mBuf << endl;
+}
\ No newline at end of file
diff --git a/plugins/check_load.cpp b/plugins/check_load.cpp
new file mode 100644 (file)
index 0000000..1541462
--- /dev/null
@@ -0,0 +1,200 @@
+#include <Pdh.h>
+#include <Shlwapi.h>
+#include <pdhmsg.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::endl; using std::cout; using std::wstring;
+using std::wcout;
+
+struct printInfoStruct {
+       threshold warn, crit;
+       double load;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&);
+static int check_load(printInfoStruct&);
+
+int wmain(int argc, wchar_t **argv) {
+       printInfoStruct printInfo{ };
+       po::variables_map vm;
+
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       ret = check_load(printInfo);
+       if (ret != -1)
+               return ret;
+
+       printOutput(printInfo);
+       return 1;
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               (",h", "print usage message and exit")
+               ("help", "print help message and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning value (in percent)")
+               ("critical,c", po::wvalue<wstring>(), "critical value (in percent)")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines CPU load.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tLOAD WARNING 67%%|load=67%%;50%%;90%%;0;100\n\n"
+                       L"\"LOAD\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"67%%\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value. Performance data will onl be displayed when\n"
+                       L"you set at least one threshold\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too."
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+
+       if (vm.count("version"))
+               cout << "Version: " << VERSION << endl;
+
+       if (vm.count("warning")) 
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical"))
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+
+       return -1;
+}
+
+int printOutput(printInfoStruct& printInfo) {
+       state state = OK;
+       
+       if (!printInfo.warn.set && !printInfo.crit.set) {
+               wcout << L"LOAD OK " << printInfo.load << endl;
+       }
+
+       if (printInfo.warn.rend(printInfo.load))
+               state = WARNING;
+
+       if (printInfo.crit.rend(printInfo.load))
+               state = CRITICAL;
+
+       std::wstringstream perf;
+       perf << L"%|load=" << printInfo.load << L"%;" << printInfo.warn.pString() << L";" 
+               << printInfo.crit.pString() << L";0;100" << endl;
+
+       switch (state) {
+       case OK:
+               wcout << L"LOAD OK " << printInfo.load << perf.str();
+               break;
+       case WARNING:
+               wcout << L"LOAD WARNING " << printInfo.load << perf.str();
+               break;
+       case CRITICAL:
+               wcout << L"LOAD CRITICAL " << printInfo.load << perf.str();
+               break;
+       }
+
+       return state;
+}
+
+int check_load(printInfoStruct& printInfo) {
+       PDH_HQUERY phQuery;
+       PDH_HCOUNTER phCounter;
+       DWORD dwBufferSize = 0;
+       DWORD CounterType;
+       PDH_FMT_COUNTERVALUE DisplayValue;
+
+       LPCWSTR path = L"\\Processor(_Total)\\% Idle Time";
+
+       if (PdhOpenQuery(NULL, NULL, &phQuery) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhAddEnglishCounter(phQuery, path, NULL, &phCounter) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhCollectQueryData(phQuery) != ERROR_SUCCESS)
+               goto cleanup;
+
+       Sleep(1000);
+
+       if (PdhCollectQueryData(phQuery) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhGetFormattedCounterValue(phCounter, PDH_FMT_DOUBLE, &CounterType, &DisplayValue) == ERROR_SUCCESS) {
+               if (DisplayValue.CStatus == PDH_CSTATUS_VALID_DATA)
+                       printInfo.load = 100.0 - DisplayValue.doubleValue;
+               PdhCloseQuery(phQuery);
+               return -1;
+       }
+
+cleanup:
+       if (phQuery)
+               PdhCloseQuery(phQuery);
+       return 3;
+}
\ No newline at end of file
diff --git a/plugins/check_network.cpp b/plugins/check_network.cpp
new file mode 100644 (file)
index 0000000..44cb99b
--- /dev/null
@@ -0,0 +1,232 @@
+#include <Windows.h>
+#include <Pdh.h>
+#include <Shlwapi.h>
+#include <iostream>
+#include <pdhmsg.h>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+namespace po = boost::program_options;
+
+using std::endl; using std::vector; using std::wstring;
+using std::wcout; using std::cout;
+struct nInterface {
+       wstring name;
+       long BytesInSec, BytesOutSec;
+       nInterface(wstring p)
+               : name(p)
+       {}
+};
+
+struct printInfoStruct {
+       threshold warn, crit;
+};
+
+static void die(const DWORD err=NULL);
+static int parseArguments(int, TCHAR **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&, const vector<nInterface>&);
+static int check_network(vector<nInterface>&);
+
+int wmain(int argc, wchar_t **argv) {
+       vector<nInterface> vInterfaces;
+       printInfoStruct printInfo{ };
+       po::variables_map vm;
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       ret = check_network(vInterfaces);
+       if (ret != -1)
+               return ret;
+               
+       printOutput(printInfo, vInterfaces);
+       return 1;
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc("Options");
+
+       desc.add_options()
+               (",h", "print usage and exit")
+               ("help", "print help message and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning value")
+               ("critical,c", po::wvalue<wstring>(), "critical value")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines network performance.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tNETWORK WARNING 1131B/s|network=1131B/s;1000;7000;0\n\n"
+                       L"\"DISK\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"1131B/s\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value. Performance data will onl be displayed when\n"
+                       L"you set at least one threshold\n"
+                       L"This program will also print out additional performance data interface\n"
+                       L"by interface\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too."
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+
+       if (vm.count("version"))
+               cout << "Version: " << VERSION << endl;
+
+       if (vm.count("warning"))
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical")) 
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+       
+       return -1;
+}
+
+int printOutput(printInfoStruct& printInfo, const vector<nInterface>& vInterfaces) {
+       long tIn = 0, tOut = 0;
+       std::wstringstream tss;
+       state state = OK;
+
+       for (vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
+               tIn += it->BytesInSec;
+               tOut += it->BytesOutSec;
+               tss << L"netI=\"" << it->name << L"\";in=" << it->BytesInSec << L"B/s;out=" << it->BytesOutSec << L"B/s ";
+       }
+
+       if (!printInfo.warn.set && !printInfo.crit.set) {
+               wcout << L"NETWORK OK " << tIn+tOut << endl;
+       }
+
+       if (printInfo.warn.rend(tIn + tOut))
+               state = WARNING;
+       if (printInfo.crit.rend(tIn + tOut))
+               state = CRITICAL;
+
+       switch (state) {
+       case OK:
+               wcout << L"NETWORK OK " << tIn + tOut << L"B/s|" << tss.str() << endl;
+               break;
+       case WARNING:
+               wcout << L"NETWORK WARNING " << tIn + tOut << L"B/s|" << tss.str() << endl;
+               break;
+       case CRITICAL:
+               wcout << L"NETWORK CRITICAL " << tIn + tOut << L"B/s|" << tss.str() << endl;
+               break;
+       }
+
+       return state;
+}
+
+int check_network(vector <nInterface>& vInterfaces) {
+       const wchar_t *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
+       const wchar_t *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
+
+       PDH_HQUERY phQuery = NULL;
+       PDH_HCOUNTER phCounterIn, phCounterOut;
+       DWORD dwBufferSizeIn = 0, dwBufferSizeOut = 0, dwItemCount = 0;
+       PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
+
+       if (PdhOpenQuery(NULL, NULL, &phQuery) != ERROR_SUCCESS)
+               goto die;
+
+       if (PdhOpenQuery(NULL, NULL, &phQuery) == ERROR_SUCCESS) {
+               if (PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn) == ERROR_SUCCESS) {
+                       if (PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut) == ERROR_SUCCESS) {
+                               if (PdhCollectQueryData(phQuery) == ERROR_SUCCESS) {
+                                       Sleep(1000);
+                                       if (PdhCollectQueryData(phQuery) == ERROR_SUCCESS) {
+                                               if (PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn) == PDH_MORE_DATA &&
+                                                       PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut) == PDH_MORE_DATA) {
+                                                       pDisplayValuesIn = new PDH_FMT_COUNTERVALUE_ITEM[dwItemCount*dwBufferSizeIn];
+                                                       pDisplayValuesOut = new  PDH_FMT_COUNTERVALUE_ITEM[dwItemCount*dwBufferSizeOut];
+                                                       if (PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn) == ERROR_SUCCESS &&
+                                                               PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut) == ERROR_SUCCESS) {
+                                                               for (DWORD i = 0; i < dwItemCount; i++) {
+                                                                       nInterface *iface = new nInterface(wstring(pDisplayValuesIn[i].szName));
+                                                                       iface->BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
+                                                                       iface->BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
+                                                                       vInterfaces.push_back(*iface);
+                                                               }
+                                                               return -1;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       
+die:
+       die();
+       if (phQuery)
+               PdhCloseQuery(phQuery);
+       return 3;
+}
+
+void die(DWORD err) {
+       if (!err)
+               err = GetLastError();
+       LPWSTR mBuf = NULL;
+       size_t mS = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+               NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&mBuf, 0, NULL);
+       wcout << mBuf << endl;
+}
\ No newline at end of file
diff --git a/plugins/check_procs.cpp b/plugins/check_procs.cpp
new file mode 100644 (file)
index 0000000..6c5a5e4
--- /dev/null
@@ -0,0 +1,278 @@
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <tlhelp32.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::endl; using std::wstring; using std::wcout;
+using std::cout;
+
+struct printInfoStruct {
+       threshold warn, crit;
+       wstring user;
+};
+
+static int countProcs();
+static int countProcs(const wstring);
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(const int, printInfoStruct&);
+
+int wmain(int argc, wchar_t **argv) {
+       po::variables_map vm;
+       printInfoStruct printInfo = { };
+
+
+       int r = parseArguments(argc, argv, vm, printInfo);
+       if (r != -1)
+               return r;
+
+       if(!printInfo.user.empty())
+               return printOutput(countProcs(printInfo.user), printInfo);
+
+       return printOutput(countProcs(), printInfo);
+}
+
+int printOutput(const int numProcs, printInfoStruct& printInfo) {
+       state state = OK;
+
+       if (!printInfo.warn.set && !printInfo.crit.set) {
+               wcout << L"PROCS OK " << numProcs << endl;
+       }
+
+       if (printInfo.warn.rend(numProcs))
+               state = WARNING;
+
+       if (printInfo.crit.rend(numProcs))
+               state = CRITICAL;
+       
+       switch (state)
+       {
+       case OK:
+               wcout << L"PROCS OK " << numProcs << L"|procs=" << numProcs << L";" 
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case WARNING:
+               wcout << L"PROCS WARNING " << numProcs << L"|procs=" << numProcs << L";"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case CRITICAL:
+               wcout << L"PROCS CRITICAL " << numProcs << L"|procs=" << numProcs << L";"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       }
+
+       return state;
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               ("h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning threshold")
+               ("critical,c", po::wvalue<wstring>(), "critical threshold")
+               ("user,u", po::wvalue<wstring>(), "count only processes by user [arg]")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               std::cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               std::cout << desc << endl;
+               return 0;
+       }
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines processes.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tPROCS WARNING 67|load=67;50;90;0\n\n"
+                       L"\"PROCS\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"67\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value. Performance data will onl be displayed when\n"
+                       L"you set at least one threshold\n"
+                       L"For \"-user\" option keep in mind you need root to see other users processes\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too."
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+       if (vm.count("version")) {
+               std::cout << "Version: " << VERSION << endl;
+               return 0;
+       }
+
+       if (vm.count("warning"))
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical"))
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+
+       if (vm.count("user")) 
+               printInfo.user = vm["user"].as<wstring>();
+
+       return -1;
+}
+
+int countProcs() {
+       HANDLE hProcessSnap;
+       PROCESSENTRY32 pe32;
+
+       hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+       if (hProcessSnap == INVALID_HANDLE_VALUE)
+               return -1;
+
+       pe32.dwSize = sizeof(PROCESSENTRY32);
+
+       if (!Process32First(hProcessSnap, &pe32)) {
+               CloseHandle(hProcessSnap);
+               return -1;
+       }
+
+       int numProcs = 0;
+
+       do {
+               ++numProcs;
+       } while (Process32Next(hProcessSnap, &pe32));
+
+       CloseHandle(hProcessSnap);
+       return numProcs;
+}
+
+int countProcs(const wstring user) {
+       const wchar_t *wuser = user.c_str();
+       int numProcs = 0;
+
+       HANDLE hProcessSnap, hProcess = NULL, hToken = NULL;
+       PROCESSENTRY32 pe32;
+       DWORD dwReturnLength, dwAcctName, dwDomainName;
+       PTOKEN_USER pSIDTokenUser = NULL;
+       SID_NAME_USE sidNameUse;
+       LPWSTR AcctName, DomainName;
+
+       hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+       if (hProcessSnap == INVALID_HANDLE_VALUE)
+               goto die;
+
+       pe32.dwSize = sizeof(PROCESSENTRY32);
+
+       if (!Process32First(hProcessSnap, &pe32)) {
+               goto die;
+       }
+
+       do {
+               //get ProcessToken
+               hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
+               if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
+            //Won't count pid 0 (system idle) and 4/8 (Sytem)
+                       continue;
+               }
+
+
+               //Get dwReturnLength in first call
+               dwReturnLength = 1;
+               if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength)
+                       && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+                       continue;
+               }
+
+               pSIDTokenUser = (PTOKEN_USER)new BYTE[dwReturnLength];
+               memset(pSIDTokenUser, 0, dwReturnLength);
+
+               if (!pSIDTokenUser)
+                       continue;
+
+               //write Info in pSIDTokenUser
+               if (!GetTokenInformation(hToken, TokenUser, pSIDTokenUser, dwReturnLength, NULL))
+                       continue;
+
+               AcctName = NULL;
+               DomainName = NULL;
+               dwAcctName = 1;
+               dwDomainName = 1;
+               //get dwAcctName and dwDomainName size
+               if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
+                       (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse)
+                       && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+                       continue;
+               
+               AcctName = (LPWSTR) new wchar_t[dwAcctName];
+               DomainName = (LPWSTR) new wchar_t[dwDomainName];
+
+               if (!AcctName || !DomainName)
+                       continue;
+               
+               if (!LookupAccountSid(NULL, pSIDTokenUser->User.Sid, AcctName,
+                       (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &sidNameUse))
+                       continue;
+
+               if (!wcscmp(AcctName, wuser)) {
+                       ++numProcs;
+               }
+
+       } while (Process32Next(hProcessSnap, &pe32));
+       
+
+die:
+       if (hProcessSnap)
+               CloseHandle(hProcessSnap);
+       if (hProcess)
+               CloseHandle(hProcess);
+       if (hToken)
+               CloseHandle(hToken);
+       return numProcs;
+}
\ No newline at end of file
diff --git a/plugins/check_service.cpp b/plugins/check_service.cpp
new file mode 100644 (file)
index 0000000..caeeaf9
--- /dev/null
@@ -0,0 +1,180 @@
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::wcout; using std::endl;
+using std::cout; using std::wstring;
+
+struct printInfoStruct {
+       bool warn;
+       int ServiceState;
+       wstring service;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(const printInfoStruct&);
+static int ServiceStatus(const printInfoStruct&);
+
+int wmain(int argc, wchar_t **argv)
+{
+       po::variables_map vm;
+       printInfoStruct printInfo = { false, 0, L"" };
+
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       printInfo.ServiceState = ServiceStatus(printInfo);
+       if (printInfo.ServiceState == -1)
+               return 3;
+
+       return printOutput(printInfo);
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               (",h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("service,s", po::wvalue<wstring>(), "service to check (required)")
+               ("warn,w", "return warning (1) instead of critical (2)\n when service is not running")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       } catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       } 
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }       
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check the status of a service.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tSERVICE CRITICAL NOT_RUNNING|service=1;-1;!4;1;7\n\n"
+                       L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
+                       L"and \"1\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value.\n"
+                       L"A service is either running (Code 0x04) or not running (any other).\n"
+                       L"For more information consult the msdn on service state transitions.\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"%s' thresholds work differently, since a service is either running or not\n"
+                       L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
+                       L"or critical state respectively.\n"
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+        if (vm.count("version")) {
+               cout << "Version: " << VERSION << endl;
+               return 0;
+       } if (!vm.count("service")) {
+               cout << "Missing argument: service" << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("warn"))
+               printInfo.warn = true;
+       
+       printInfo.service = vm["service"].as<wstring>();
+       
+       return -1;
+}
+
+int printOutput(const printInfoStruct& printInfo) {
+       wstring perf;
+
+       state state = OK;
+       if (printInfo.ServiceState != 0x04) 
+               printInfo.warn ? state = WARNING : state = CRITICAL;
+       
+       printInfo.warn ? perf.append(L"!4;-1;1;7") : perf.append(L"-1;!4;1;7");
+
+       switch (state) {
+       case OK:
+               wcout << L"SERVICE OK RUNNING|service=4;" << perf << endl;
+               break;
+       case WARNING:
+               wcout << L"SERVICE WARNING NOT_RUNNING|service=" << printInfo.ServiceState << perf << endl;
+               break;
+       case CRITICAL:
+               wcout << L"SERVICE CRITICAL NOT_RUNNING|service=" << printInfo.ServiceState << perf << endl;
+               break;
+       }
+       return state;
+}
+
+int ServiceStatus(const printInfoStruct& printInfo) {
+
+       SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
+       if (service_api == NULL)
+               goto die;
+
+
+       LPBYTE lpServices = NULL;
+       DWORD cbBufSize = 0;
+       DWORD *pcbBytesNeeded = (LPDWORD)malloc(sizeof(DWORD));
+       DWORD *lpServicesReturned = (LPDWORD)malloc(sizeof(DWORD));
+       DWORD *lpResumeHandle = (LPDWORD)malloc(sizeof(DWORD));
+       *lpResumeHandle = 0;
+
+       if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
+               lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL)
+               && GetLastError() != ERROR_MORE_DATA) 
+               goto die;
+
+       lpServices = (LPBYTE)malloc(*pcbBytesNeeded);
+       cbBufSize = *pcbBytesNeeded;
+
+       if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
+               lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, NULL))
+               goto die;
+
+       LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
+       for (DWORD i = 0; i< *lpServicesReturned; i++)
+       {
+               if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName))
+                       return pInfo[i].ServiceStatusProcess.dwCurrentState;
+       }
+
+die:
+       wcout << L"Service " << printInfo.service << L" could not be found" << endl;
+       return -1;
+}
diff --git a/plugins/check_swap.cpp b/plugins/check_swap.cpp
new file mode 100644 (file)
index 0000000..b88c572
--- /dev/null
@@ -0,0 +1,185 @@
+#include <Shlwapi.h>
+#include <Pdh.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::endl; using std::wcout; using std::wstring;
+using std::cout;
+
+struct printInfoStruct {
+       threshold warn, crit;
+       double swap;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&);
+static int check_swap(printInfoStruct&);
+
+int wmain(int argc, wchar_t **argv) {
+       printInfoStruct printInfo = { };
+       po::variables_map vm;
+
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       ret = check_swap(printInfo);
+       if (ret != -1)
+               return ret;
+
+       return printOutput(printInfo);
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               (",h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning threshold")
+               ("critical,c", po::wvalue<wstring>(), "critical threshold")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines swap in percent.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tSWAP WARNING 23.8304%%|swap=23.8304%%;19.5;30;0;100\n\n"
+                       L"\"SWAP\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"23.8304%%\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value.\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too.\n"
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+
+       if (vm.count("version"))
+               wcout << L"Version: " << VERSION << endl;
+
+       if (vm.count("warning")) 
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical")) 
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+
+       return -1;
+}
+
+int printOutput(printInfoStruct& printInfo) {
+       state state = OK;
+
+       if (printInfo.warn.rend(printInfo.swap))
+               state = WARNING;
+
+       if (printInfo.crit.rend(printInfo.swap))
+               state = CRITICAL;
+
+       switch (state) {
+       case OK:
+               wcout << L"SWAP OK " << printInfo.swap << L"%|swap=" << printInfo.swap << L"%;" 
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;100" << endl;
+               break;
+       case WARNING:
+               wcout << L"SWAP WARNING " << printInfo.swap << L"%|swap=" << printInfo.swap << L"%;"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;100" << endl;
+               break;
+       case CRITICAL:
+               wcout << L"SWAP CRITICAL " << printInfo.swap << L"%|swap=" << printInfo.swap << L"%;"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;100" << endl;
+               break;
+       }
+
+       return state;
+}
+
+int check_swap(printInfoStruct& printInfo) {
+       PDH_HQUERY phQuery;
+       PDH_HCOUNTER phCounter;
+       DWORD dwBufferSize = 0;
+       DWORD CounterType;
+       PDH_FMT_COUNTERVALUE DisplayValue;
+
+       LPCWSTR path = L"\\Paging File(*)\\% Usage";
+
+       if (PdhOpenQuery(NULL, NULL, &phQuery) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhAddEnglishCounter(phQuery, path, NULL, &phCounter) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhCollectQueryData(phQuery) != ERROR_SUCCESS)
+               goto cleanup;
+
+       if (PdhGetFormattedCounterValue(phCounter, PDH_FMT_DOUBLE, &CounterType, &DisplayValue) == ERROR_SUCCESS) {
+               printInfo.swap = DisplayValue.doubleValue;
+               PdhCloseQuery(phQuery);
+               return -1;
+       }
+
+cleanup:
+       if (phQuery)
+               PdhCloseQuery(phQuery);
+       return 3;
+}
\ No newline at end of file
diff --git a/plugins/check_update.cpp b/plugins/check_update.cpp
new file mode 100644 (file)
index 0000000..99cf288
--- /dev/null
@@ -0,0 +1,227 @@
+#include <windows.h>
+#include <Shlwapi.h>
+#include <iostream>
+#include <wuapi.h>
+#include <wuerror.h>
+
+#include "thresholds.h"
+
+#include "boost/program_options.hpp"
+
+#define VERSION 1.0
+
+#define CRITERIA L"(IsInstalled = 0 and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441') or (IsInstalled = 0 and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4')"
+
+namespace po = boost::program_options;
+
+using std::wcout; using std::endl;
+using std::wstring; using std::cout;
+
+struct printInfoStruct {
+       BOOL warn, crit;
+       LONG numUpdates;
+       BOOL important, reboot, careForCanRequest;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(const printInfoStruct&);
+static int check_update(printInfoStruct&);
+
+int main(int argc, wchar_t **argv) 
+{
+       po::variables_map vm;
+       printInfoStruct printInfo = { FALSE, FALSE, 0, FALSE, FALSE, FALSE };
+
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+       
+       ret = check_update(printInfo);
+       if (ret != -1)
+               return ret;
+
+       return printOutput(printInfo);
+}
+
+int printOutput(const printInfoStruct& printInfo) 
+{
+       state state = OK;
+       wstring output = L"UPDATE ";
+
+       if (printInfo.important)
+               state = WARNING;
+
+       if (printInfo.reboot)
+               state = CRITICAL;
+
+       switch (state)
+       {
+       case OK:
+               output.append(L"OK ");
+               break;
+       case WARNING:
+               output.append(L"WARNING ");
+               break;
+       case CRITICAL:
+               output.append(L"CRITICAL ");
+               break;
+       }
+
+       wcout << output << printInfo.numUpdates << L"|update=" << printInfo.numUpdates << L";"
+               << printInfo.warn << L";" << printInfo.crit << L";0" << endl;
+       return state;
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) 
+{
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               (",h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", "warn if there are important updates available")
+               ("critical,c", "critical if there are important updates that require a reboot")
+               ("possible-reboot", "treat \"update may need to reboot\" as \"update needs to reboot\"")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       } 
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines required updates.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nAfter some time, it will then output a string like this one:\n\n"
+                       L"\tUPDATE WARNING 8|updates=8;1;1;0\n\n"
+                       L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"8\" is the number of important updates updates.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value.\n\n"
+                       L"An update counts as important when it is part of the Security- or\n"
+                       L"CriticalUpdates group.\n"
+                       L"Consult the msdn on WSUS Classification GUIDs for more information.\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"%s works different from other plugins in that you do not set thresholds\n"
+                       L"but only activate them. Using \"-w\" triggers warning state if there are not\n"
+                       L"installed and non-optional updates. \"-c\" triggers critical if there are\n"
+                       L"non-optional updates that require a reboot.\n"
+                       L"The \"possible-reboot\" option is not recommended since this true for nearly\n"
+                       L"every update."
+                       , progName, progName);
+               cout << endl;
+               return 0;
+       }  if (vm.count("version")) {
+               cout << "Version: " << VERSION << endl;
+               return 0;
+       }
+
+       if (vm.count("warning"))
+               printInfo.warn = TRUE;
+
+       if (vm.count("critical"))
+               printInfo.crit = TRUE;
+
+       if (vm.count("possible-reboot"))
+               printInfo.careForCanRequest = TRUE;
+
+       return -1;
+}
+
+int check_update(printInfoStruct& printInfo) 
+{
+       CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+       ISearchResult *pResult;
+       IUpdateSession *pSession;
+       IUpdateSearcher *pSearcher;
+
+       CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&pSession);
+       pSession->CreateUpdateSearcher(&pSearcher);
+
+
+       /*
+        IsInstalled = 0: All updates, including languagepacks and features
+        BrowseOnly = 0: No features or languagepacks, security and unnamed
+        BrowseOnly = 1: Nothing, broken
+        RebootRequired = 1: Reboot required
+       */
+
+       BSTR criteria = SysAllocString(CRITERIA);
+       // http://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx
+       // http://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx
+
+       if (pSearcher->Search(criteria, &pResult) != S_OK)
+               goto die;
+       SysFreeString(criteria);
+
+       IUpdateCollection *pCollection;
+       IUpdate *pUpdate;
+
+       LONG updateSize;
+       pResult->get_Updates(&pCollection);
+       pCollection->get_Count(&updateSize);
+
+       if (updateSize == 0)
+               return -1;
+
+       printInfo.numUpdates = updateSize;
+       printInfo.important = printInfo.warn;
+
+       if (!printInfo.crit)
+               return -1;
+
+       IInstallationBehavior *pIbehav;
+       InstallationRebootBehavior updateReboot;
+
+       for (LONG i = 0; i < updateSize; i++)
+       {
+               pCollection->get_Item(i, &pUpdate);
+               pUpdate->get_InstallationBehavior(&pIbehav);
+               pIbehav->get_RebootBehavior(&updateReboot);
+               if (updateReboot == irbAlwaysRequiresReboot) {
+                       printInfo.reboot = TRUE;
+                       continue;
+               }
+               if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot)
+                       printInfo.reboot = TRUE;
+       }
+
+       return 0;
+
+die:
+       if (criteria)
+               SysFreeString(criteria);
+       return 3;
+}
\ No newline at end of file
diff --git a/plugins/check_uptime.cpp b/plugins/check_uptime.cpp
new file mode 100644 (file)
index 0000000..a3b8c62
--- /dev/null
@@ -0,0 +1,188 @@
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\chrono.hpp"
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::cout; using std::endl;
+using std::wcout; using std::wstring;
+
+struct printInfoStruct {
+       threshold warn, crit;
+       long long time;
+       Tunit unit;
+};
+
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&);
+static void getUptime(printInfoStruct&);
+
+int main(int argc, wchar_t **argv)
+{
+       po::variables_map vm;
+       printInfoStruct printInfo = { };
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       
+       if (ret != -1)
+               return ret;
+
+       getUptime(printInfo);
+
+       return printOutput(printInfo);
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+       
+       desc.add_options()
+               (",h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning threshold (Uses -unit)")
+               ("critical,c", po::wvalue<wstring>(), "critical threshold (Uses -unit)")
+               ("unit,u", po::wvalue<wstring>(), "desired unit of output\nh    - hours\nm    - minutes\ns    - seconds (default)\nms   - milliseconds")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines uptime.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tUPTIME WARNING 712h|uptime=712h;700;1800;0\n\n"
+                       L"\"UPTIME\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"712h\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value.\n"
+                       L"Note that the returned time ins always rounded down,\n"
+                       L"4 hours and 44 minutes will show as 4h.\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too.\n"
+                       , progName);
+                       cout << endl;
+               return 0;
+       }
+
+       if (vm.count("version")) {
+               cout << VERSION << endl;
+               return 0;
+       }
+
+       if (vm.count("warning"))
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical"))
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+
+       if (vm.count("unit")) {
+               printInfo.unit = parseTUnit(vm["unit"].as<wstring>().c_str());
+       } else {
+               printInfo.unit = TunitS;
+       }
+       return -1;
+}
+
+static int printOutput(printInfoStruct& printInfo) {
+       state state = OK;
+       if (printInfo.warn.rend(printInfo.time))
+               state = WARNING;
+       if (printInfo.crit.rend(printInfo.time))
+               state = CRITICAL;
+
+       switch (state) {
+       case OK:
+               wcout << L"UPTIME OK " << printInfo.time << TunitStr(printInfo.unit) << L"|uptime=" << printInfo.time 
+                       << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";" 
+                       << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case WARNING:
+               wcout << L"UPTIME WARNING " << printInfo.time << TunitStr(printInfo.unit) << L"|uptime=" << printInfo.time
+                       << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";"
+                       << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case CRITICAL:
+               wcout << L"UPTIME CRITICAL " << printInfo.time << TunitStr(printInfo.unit) << L"|uptime=" << printInfo.time
+                       << TunitStr(printInfo.unit) << L";" << printInfo.warn.pString() << L";"
+                       << printInfo.crit.pString() << L";0" << endl;
+               break;
+       }
+
+       return state;
+}
+
+void getUptime(printInfoStruct& printInfo) {
+       boost::chrono::milliseconds uptime = boost::chrono::milliseconds(GetTickCount64());
+       
+       switch (printInfo.unit) {
+       case TunitH: 
+               printInfo.time = boost::chrono::duration_cast<boost::chrono::hours>(uptime).count();
+               break;
+       case TunitM:
+               printInfo.time = boost::chrono::duration_cast<boost::chrono::minutes>(uptime).count();
+               break;
+       case TunitS:
+               printInfo.time = boost::chrono::duration_cast<boost::chrono::seconds>(uptime).count();
+               break;
+       case TunitMS:
+               printInfo.time = uptime.count();
+               break;
+       }
+       
+}
\ No newline at end of file
diff --git a/plugins/check_users.cpp b/plugins/check_users.cpp
new file mode 100644 (file)
index 0000000..f00623a
--- /dev/null
@@ -0,0 +1,193 @@
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <wtsapi32.h>
+#include <iostream>
+
+#include "thresholds.h"
+
+#include "boost\program_options.hpp"
+
+#define VERSION 1.0
+
+namespace po = boost::program_options;
+
+using std::endl; using std::wcout;
+using std::cout; using std::wstring;
+
+struct printInfoStruct {
+       threshold warn, crit;
+       int users;
+};
+
+static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
+static int printOutput(printInfoStruct&);
+static int check_users(printInfoStruct&);
+
+int wmain(int argc, wchar_t **argv) {
+       printInfoStruct printInfo = { };
+       po::variables_map vm;
+
+       int ret = parseArguments(argc, argv, vm, printInfo);
+       if (ret != -1)
+               return ret;
+
+       ret = check_users(printInfo);
+       if (ret != -1)
+               return ret;
+
+       return printOutput(printInfo);
+}
+
+int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
+       wchar_t namePath[MAX_PATH];
+       GetModuleFileName(NULL, namePath, MAX_PATH);
+       wchar_t *progName = PathFindFileName(namePath);
+
+       po::options_description desc;
+
+       desc.add_options()
+               (",h", "print help message and exit")
+               ("help", "print verbose help and exit")
+               ("version,v", "print version and exit")
+               ("warning,w", po::wvalue<wstring>(), "warning threshold")
+               ("critical,c", po::wvalue<wstring>(), "critical threshold")
+               ;
+
+       po::basic_command_line_parser<wchar_t> parser(ac, av);
+
+       try {
+               po::store(
+                       parser
+                       .options(desc)
+                       .style(
+                       po::command_line_style::unix_style |
+                       po::command_line_style::allow_long_disguise)
+                       .run(),
+                       vm);
+               vm.notify();
+       }
+
+       catch (std::exception& e) {
+               cout << e.what() << endl << desc << endl;
+               return 3;
+       }
+
+       if (vm.count("h")) {
+               cout << desc << endl;
+               return 0;
+       }
+       if (vm.count("help")) {
+               wcout << progName << " Help\n\tVersion: " << VERSION << endl;
+               wprintf(
+                       L"%s is a simple program to check a machines logged in users.\n"
+                       L"You can use the following options to define its behaviour:\n\n", progName);
+               cout << desc;
+               wprintf(
+                       L"\nIt will then output a string looking something like this:\n\n"
+                       L"\tUSERS WARNING 48|users=48;10;50;0\n\n"
+                       L"\"USERS\" being the type of the check, \"WARNING\" the returned status\n"
+                       L"and \"48\" is the returned value.\n"
+                       L"The performance data is found behind the \"|\", in order:\n"
+                       L"returned value, warning threshold, critical threshold, minimal value and,\n"
+                       L"if applicable, the maximal value.\n\n"
+                       L"%s' exit codes denote the following:\n"
+                       L" 0\tOK,\n\tno Thresholds were broken or the programs check part was not executed\n"
+                       L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
+                       L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
+                       L" 3\tUNKNOWN, \n\tThe programme experienced an internal or input error\n\n"
+                       L"Threshold syntax:\n\n"
+                       L"-w THRESHOLD\n"
+                       L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
+                       L"(unless stated differently)\n\n"
+                       L"-w !THRESHOLD\n"
+                       L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
+                       L"-w [THR1-THR2]\n"
+                       L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
+                       L"-w ![THR1-THR2]\n"
+                       L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
+                       L"-w THRESHOLD%%\n"
+                       L"if the plugin accepts percentage based thresholds those will be used.\n"
+                       L"Does nothing if the plugin does not accept percentages, or only uses\n"
+                       L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
+                       L"to end with a percentage sign.\n\n"
+                       L"All of these options work with the critical threshold \"-c\" too."
+                       , progName);
+               cout << endl;
+               return 0;
+       }
+
+       if (vm.count("version"))
+               wcout << L"Version: " << VERSION << endl;
+
+       if (vm.count("warning")) 
+               printInfo.warn = parse(vm["warning"].as<wstring>());
+
+       if (vm.count("critical")) 
+               printInfo.crit = parse(vm["critical"].as<wstring>());
+
+       return -1;
+}
+
+int printOutput(printInfoStruct& printInfo) {
+       state state = OK;
+       
+       if (printInfo.warn.rend(printInfo.users))
+               state = WARNING;
+
+       if (printInfo.crit.rend(printInfo.users))
+               state = CRITICAL;
+
+       switch (state) {
+       case OK:
+               wcout << L"USERS OK " << printInfo.users << L"|users=" << printInfo.users << L";" 
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case WARNING:
+               wcout << L"USERS WARNING " << printInfo.users << L"|users=" << printInfo.users << L";"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       case CRITICAL:
+               wcout << L"USERS CRITICAL " << printInfo.users << L"|users=" << printInfo.users << L";"
+                       << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0" << endl;
+               break;
+       }
+
+       return state;
+}
+
+int check_users(printInfoStruct& printInfo) {
+       int users = 0;
+       WTS_SESSION_INFOW *pSessionInfo;
+       DWORD count;
+       DWORD index;
+
+       if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &count)) {
+               wcout << L"Failed to enumerate terminal sessions" << endl;
+               return 3;
+       }
+
+       for (index = 0; index < count; index++) {
+               LPWSTR name;
+               DWORD size;
+               int len;
+
+               if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, pSessionInfo[index].SessionId,
+                       WTSUserName, &name, &size))
+                       continue;
+
+               len = lstrlenW(name);
+
+               WTSFreeMemory(name);
+
+               if (!len)
+                       continue;
+
+               if (pSessionInfo[index].State == WTSActive || pSessionInfo[index].State == WTSDisconnected)
+                       users++;
+       }
+
+       WTSFreeMemory(pSessionInfo);
+       printInfo.users = users;
+       return -1;
+
+}
\ No newline at end of file
diff --git a/plugins/thresholds.cpp b/plugins/thresholds.cpp
new file mode 100644 (file)
index 0000000..a43c87f
--- /dev/null
@@ -0,0 +1,116 @@
+#include <vector>
+
+#include "thresholds.h"
+
+#include "boost\algorithm\string.hpp"
+#include "boost\lexical_cast.hpp"
+
+using std::wstring;
+
+threshold parse(const wstring& stri)
+{
+       if (stri.empty())
+               throw std::invalid_argument("thresholds must not be empty");
+
+       wstring str = stri;
+
+       bool low = (str.at(0) == L'!');
+       if (low)
+               str = wstring(str.begin() + 1, str.end());
+
+       bool perc = false;
+
+       if (str.at(0) == L'[' && str.at(str.length() - 1) == L']') {//is range
+               str = wstring(str.begin() + 1, str.end() - 1);
+               std::vector<wstring> svec;
+               boost::split(svec, str, boost::is_any_of(L"-"));
+               if (svec.size() != 2)
+                       throw std::invalid_argument("threshold range requires two arguments");
+               wstring str1 = svec.at(0), str2 = svec.at(1);
+
+               if (str1.at(str1.length() - 1) == L'%' && str2.at(str2.length() - 1) == L'%') {
+                       perc = true;
+                       str1 = wstring(str1.begin(), str1.end() - 1);
+                       str2 = wstring(str2.begin(), str2.end() - 1);
+               }
+                       
+               try {
+                       double d1 = boost::lexical_cast<double>(str1);
+                       double d2 = boost::lexical_cast<double>(str2);
+                       return threshold(d1, d2, !low, perc);
+               } catch (const boost::bad_lexical_cast&) {
+                       throw std::invalid_argument("threshold must be a number");
+               }
+       } else { //not range
+               if (str.at(str.length() - 1) == L'%') {
+                       perc = true;
+                       str = wstring(str.begin(), str.end() - 1);
+               }
+               try {
+                       double d = boost::lexical_cast<double>(str);
+                       return threshold(d, d, !low, perc);
+
+               } catch (const boost::bad_lexical_cast&) {
+                       throw std::invalid_argument("threshold must be a number");
+               }
+       }
+}
+
+Bunit parseBUnit(const wchar_t *str)
+{
+       if (!wcscmp(str, L"B"))
+               return BunitB;
+       if (!wcscmp(str, L"kB"))
+               return BunitkB;
+       if (!wcscmp(str, L"MB"))
+               return BunitMB;
+       if (!wcscmp(str, L"GB"))
+               return BunitGB;
+       if (!wcscmp(str, L"TB"))
+               return BunitTB;
+
+       throw std::invalid_argument("Unknown unit type");
+}
+
+wstring BunitStr(const Bunit& unit) {
+       switch (unit) {
+       case BunitB:
+               return L"B";
+       case BunitkB:
+               return L"kB";
+       case BunitMB:
+               return L"MB";
+       case BunitGB:
+               return L"GB";
+       case BunitTB:
+               return L"TB";
+       }
+       return NULL;
+}
+
+Tunit parseTUnit(const wchar_t *str) {
+       if (!wcscmp(str, L"ms"))
+               return TunitMS;
+       if (!wcscmp(str, L"s"))
+               return TunitS;
+       if (!wcscmp(str, L"m"))
+               return TunitM;
+       if (!wcscmp(str, L"h"))
+               return TunitH;
+
+       throw std::invalid_argument("Unknown unit type");
+}
+
+wstring TunitStr(const Tunit& unit) {
+       switch (unit) {
+       case TunitMS:
+               return L"ms";
+       case TunitS:
+               return L"s";
+       case TunitM:
+               return L"m";
+       case TunitH:
+               return L"h";
+       }
+       return NULL;
+}
\ No newline at end of file
diff --git a/plugins/thresholds.h b/plugins/thresholds.h
new file mode 100644 (file)
index 0000000..6668ee9
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef THRESHOLDS_H
+#define THRESHOLDS_H
+#include <string>
+
+enum Bunit { BunitB = 0, BunitkB = 1, BunitMB = 2, BunitGB = 3, BunitTB = 4 };
+enum Tunit { TunitMS, TunitS, TunitM, TunitH };
+enum state { OK = 0, WARNING = 1, CRITICAL = 2 };
+
+class threshold
+{
+public:
+       double lower, upper;
+       //TRUE means everything BELOW upper/outside [lower-upper] is fine
+       bool legal, perc, set;
+
+       threshold(bool l = true)
+               : set(false), legal(l) {}
+
+       threshold(const double v, const double c, bool l = true, bool p = false)
+               : lower(v), upper(c), legal(l), perc(p), set(true) {}
+
+       //return TRUE if the threshold is broken
+       bool rend(const double b)
+       {
+               if (!set)
+                       return set;
+               if (lower == upper)
+                       return b > upper == legal;
+               else
+                       return (b < lower || upper < b) != legal;
+       }
+
+       //returns a printable string of the threshold
+       std::wstring pString()
+       {
+               if (!set)
+                       return L"0";
+
+               std::wstring s;
+               if (!legal)
+                       s.append(L"!");
+
+               if (lower != upper) {
+                       if (perc)
+                               s.append(L"[").append(std::to_wstring(lower)).append(L"%").append(L"-")
+                               .append(std::to_wstring(upper)).append(L"%").append(L"]");
+                       else
+                               s.append(L"[").append(std::to_wstring(lower)).append(L"-")
+                               .append(std::to_wstring(upper)).append(L"]");
+               } else {
+                       if (perc)
+                               s = std::to_wstring(lower).append(L"%");
+                       else
+                               s = std::to_wstring(lower);
+               }
+               return s;
+       }
+};
+
+threshold parse(const std::wstring&);
+Bunit parseBUnit(const wchar_t *);
+std::wstring BunitStr(const Bunit&);
+Tunit parseTUnit(const wchar_t *);
+std::wstring TunitStr(const Tunit&);
+#endif
\ No newline at end of file