1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "plugins/thresholds.hpp"
4 #include <boost/program_options.hpp>
13 #define CRITERIA L"(IsInstalled = 0 and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441') or (IsInstalled = 0 and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4')"
15 namespace po = boost::program_options;
17 struct printInfoStruct
22 bool ignoreReboot{false};
24 bool careForCanRequest{false};
29 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
31 WCHAR namePath[MAX_PATH];
32 GetModuleFileName(NULL, namePath, MAX_PATH);
33 WCHAR *progName = PathFindFileName(namePath);
35 po::options_description desc;
38 ("help,h", "Print help message and exit")
39 ("version,V", "Print version and exit")
40 ("debug,d", "Verbose/Debug output")
41 ("warning,w", po::value<int>(), "Number of updates to trigger a warning.")
42 ("critical,c", po::value<int>(), "Number of updates to trigger a critical.")
43 ("possible-reboot", "Treat \"update may need reboot\" as \"update needs reboot\"")
44 ("no-reboot-critical", "Do not automatically return critical if an update requiring reboot is present.")
47 po::wcommand_line_parser parser(ac, av);
54 po::command_line_style::unix_style |
55 po::command_line_style::allow_long_disguise)
59 } catch (const std::exception& e) {
60 std::cout << e.what() << '\n' << desc << '\n';
64 if (vm.count("help")) {
65 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
67 L"%s is a simple program to check a machines required updates.\n"
68 L"You can use the following options to define its behaviour:\n\n", progName);
71 L"\nAfter some time, it will then output a string like this one:\n\n"
72 L"\tUPDATE WARNING 8 | updates=8;1;1;0\n\n"
73 L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n"
74 L"and \"8\" is the number of important updates.\n"
75 L"The performance data is found behind the \"|\", in order:\n"
76 L"returned value, warning threshold, critical threshold, minimal value and,\n"
77 L"if applicable, the maximal value.\n\n"
78 L"An update counts as important when it is part of the Security- or\n"
79 L"CriticalUpdates group.\n"
80 L"Consult the msdn on WSUS Classification GUIDs for more information.\n"
81 L"%s' exit codes denote the following:\n"
82 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
83 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
84 L" 2\tCRITICAL,\n\tThe critical threshold was broken or an update required reboot.\n"
85 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
86 L"If a warning threshold is set but not a critical threshold, the critical\n"
87 L"threshold will be set to one greater than the set warning threshold.\n\n"
88 L"The \"possible-reboot\" option is not recommended since this true for nearly\n"
93 } if (vm.count("version")) {
94 std::cout << "Version: " << VERSION << '\n';
97 if(vm.count("warning"))
98 printInfo.warn = vm["warning"].as<int>();
99 if (vm.count("critical"))
100 printInfo.crit = vm["critical"].as<int>();
101 else if (vm.count("warning"))
102 printInfo.crit = printInfo.warn + 1;
103 printInfo.careForCanRequest = vm.count("possible-reboot") > 0;
104 printInfo.ignoreReboot = vm.count("no-reboot-critical") > 0;
106 l_Debug = vm.count("debug") > 0;
111 static int printOutput(const printInfoStruct& printInfo)
114 std::wcout << L"Constructing output string" << '\n';
117 std::wstring output = L"UPDATE ";
119 if (printInfo.numUpdates >= printInfo.warn && printInfo.warn)
122 if ((printInfo.reboot && !printInfo.ignoreReboot) || (printInfo.numUpdates >= printInfo.crit && printInfo.crit))
127 output.append(L"OK ");
130 output.append(L"WARNING ");
133 output.append(L"CRITICAL ");
136 output.append(std::to_wstring(printInfo.numUpdates));
137 if (printInfo.reboot) {
138 output.append(L"; ");
139 output.append(std::to_wstring(printInfo.reboot));
140 output.append(L" NEED REBOOT ");
142 std::wcout << output << L" | 'update'=" << printInfo.numUpdates << L";"
143 << printInfo.warn << L";" << printInfo.crit << L";0;" << '\n';
148 static int check_update(printInfoStruct& printInfo)
151 std::wcout << "Initializing COM library" << '\n';
152 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
153 ISearchResult *pResult;
154 IUpdateSession *pSession;
155 IUpdateSearcher *pSearcher;
156 BSTR criteria = NULL;
160 std::wcout << "Creating UpdateSession and UpdateSearcher" << '\n';
161 CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (void **)&pSession);
162 pSession->CreateUpdateSearcher(&pSearcher);
165 * IsInstalled = 0: All updates, including languagepacks and features
166 * BrowseOnly = 0: No features or languagepacks, security and unnamed
167 * BrowseOnly = 1: Nothing, broken
168 * RebootRequired = 1: Reboot required
171 criteria = SysAllocString(CRITERIA);
172 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx
173 // https://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx
176 std::wcout << L"Querying updates from server" << '\n';
178 err = pSearcher->Search(criteria, &pResult);
181 SysFreeString(criteria);
183 IUpdateCollection *pCollection;
187 pResult->get_Updates(&pCollection);
188 pCollection->get_Count(&updateSize);
193 printInfo.numUpdates = updateSize;
194 // printInfo.important = printInfo.warn;
196 IInstallationBehavior *pIbehav;
197 InstallationRebootBehavior updateReboot;
199 for (LONG i = 0; i < updateSize; i++) {
200 pCollection->get_Item(i, &pUpdate);
202 std::wcout << L"Checking reboot behaviour of update number " << i << '\n';
204 pUpdate->get_InstallationBehavior(&pIbehav);
205 pIbehav->get_RebootBehavior(&updateReboot);
206 if (updateReboot == irbAlwaysRequiresReboot) {
209 std::wcout << L"It requires reboot" << '\n';
212 if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot) {
214 std::wcout << L"It requires reboot" << '\n';
220 std::wcout << L"Cleaning up and returning" << '\n';
222 SysFreeString(criteria);
230 SysFreeString(criteria);
234 int wmain(int argc, WCHAR **argv)
236 printInfoStruct printInfo;
237 po::variables_map vm;
239 int ret = parseArguments(argc, argv, vm, printInfo);
243 ret = check_update(printInfo);
247 return printOutput(printInfo);