1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "plugins/thresholds.hpp"
21 #include <boost/program_options.hpp>
30 #define CRITERIA L"(IsInstalled = 0 and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441') or (IsInstalled = 0 and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4')"
32 namespace po = boost::program_options;
34 struct printInfoStruct
39 bool ignoreReboot{false};
41 bool careForCanRequest{false};
46 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
48 WCHAR namePath[MAX_PATH];
49 GetModuleFileName(NULL, namePath, MAX_PATH);
50 WCHAR *progName = PathFindFileName(namePath);
52 po::options_description desc;
55 ("help,h", "Print help message and exit")
56 ("version,V", "Print version and exit")
57 ("debug,d", "Verbose/Debug output")
58 ("warning,w", po::value<int>(), "Number of updates to trigger a warning.")
59 ("critical,c", po::value<int>(), "Number of updates to trigger a critical.")
60 ("possible-reboot", "Treat \"update may need reboot\" as \"update needs reboot\"")
61 ("no-reboot-critical", "Do not automatically return critical if an update requiring reboot is present.")
64 po::wcommand_line_parser parser(ac, av);
71 po::command_line_style::unix_style |
72 po::command_line_style::allow_long_disguise)
76 } catch (const std::exception& e) {
77 std::cout << e.what() << '\n' << desc << '\n';
81 if (vm.count("help")) {
82 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
84 L"%s is a simple program to check a machines required updates.\n"
85 L"You can use the following options to define its behaviour:\n\n", progName);
88 L"\nAfter some time, it will then output a string like this one:\n\n"
89 L"\tUPDATE WARNING 8 | updates=8;1;1;0\n\n"
90 L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n"
91 L"and \"8\" is the number of important updates.\n"
92 L"The performance data is found behind the \"|\", in order:\n"
93 L"returned value, warning threshold, critical threshold, minimal value and,\n"
94 L"if applicable, the maximal value.\n\n"
95 L"An update counts as important when it is part of the Security- or\n"
96 L"CriticalUpdates group.\n"
97 L"Consult the msdn on WSUS Classification GUIDs for more information.\n"
98 L"%s' exit codes denote the following:\n"
99 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
100 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
101 L" 2\tCRITICAL,\n\tThe critical threshold was broken or an update required reboot.\n"
102 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
103 L"If a warning threshold is set but not a critical threshold, the critical\n"
104 L"threshold will be set to one greater than the set warning threshold.\n\n"
105 L"The \"possible-reboot\" option is not recommended since this true for nearly\n"
107 , progName, progName);
110 } if (vm.count("version")) {
111 std::cout << "Version: " << VERSION << '\n';
114 if(vm.count("warning"))
115 printInfo.warn = vm["warning"].as<int>();
116 if (vm.count("critical"))
117 printInfo.crit = vm["critical"].as<int>();
118 else if (vm.count("warning"))
119 printInfo.crit = printInfo.warn + 1;
120 printInfo.careForCanRequest = vm.count("possible-reboot") > 0;
121 printInfo.ignoreReboot = vm.count("no-reboot-critical") > 0;
123 l_Debug = vm.count("debug") > 0;
128 static int printOutput(const printInfoStruct& printInfo)
131 std::wcout << L"Constructing output string" << '\n';
134 std::wstring output = L"UPDATE ";
136 if (printInfo.numUpdates >= printInfo.warn && printInfo.warn)
139 if ((printInfo.reboot && !printInfo.ignoreReboot) || (printInfo.numUpdates >= printInfo.crit && printInfo.crit))
144 output.append(L"OK ");
147 output.append(L"WARNING ");
150 output.append(L"CRITICAL ");
153 output.append(std::to_wstring(printInfo.numUpdates));
154 if (printInfo.reboot) {
155 output.append(L"; ");
156 output.append(std::to_wstring(printInfo.reboot));
157 output.append(L" NEED REBOOT ");
159 std::wcout << output << L" | 'update'=" << printInfo.numUpdates << L";"
160 << printInfo.warn << L";" << printInfo.crit << L";0;" << '\n';
165 static int check_update(printInfoStruct& printInfo)
168 std::wcout << "Initializing COM library" << '\n';
169 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
170 ISearchResult *pResult;
171 IUpdateSession *pSession;
172 IUpdateSearcher *pSearcher;
173 BSTR criteria = NULL;
177 std::wcout << "Creating UpdateSession and UpdateSearcher" << '\n';
178 CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (void **)&pSession);
179 pSession->CreateUpdateSearcher(&pSearcher);
182 * IsInstalled = 0: All updates, including languagepacks and features
183 * BrowseOnly = 0: No features or languagepacks, security and unnamed
184 * BrowseOnly = 1: Nothing, broken
185 * RebootRequired = 1: Reboot required
188 criteria = SysAllocString(CRITERIA);
189 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx
190 // https://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx
193 std::wcout << L"Querying updates from server" << '\n';
195 err = pSearcher->Search(criteria, &pResult);
198 SysFreeString(criteria);
200 IUpdateCollection *pCollection;
204 pResult->get_Updates(&pCollection);
205 pCollection->get_Count(&updateSize);
210 printInfo.numUpdates = updateSize;
211 // printInfo.important = printInfo.warn;
213 IInstallationBehavior *pIbehav;
214 InstallationRebootBehavior updateReboot;
216 for (LONG i = 0; i < updateSize; i++) {
217 pCollection->get_Item(i, &pUpdate);
219 std::wcout << L"Checking reboot behaviour of update number " << i << '\n';
221 pUpdate->get_InstallationBehavior(&pIbehav);
222 pIbehav->get_RebootBehavior(&updateReboot);
223 if (updateReboot == irbAlwaysRequiresReboot) {
226 std::wcout << L"It requires reboot" << '\n';
229 if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot) {
231 std::wcout << L"It requires reboot" << '\n';
237 std::wcout << L"Cleaning up and returning" << '\n';
239 SysFreeString(criteria);
247 SysFreeString(criteria);
251 int wmain(int argc, WCHAR **argv)
253 printInfoStruct printInfo;
254 po::variables_map vm;
256 int ret = parseArguments(argc, argv, vm, printInfo);
260 ret = check_update(printInfo);
264 return printOutput(printInfo);