1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.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 ******************************************************************************/
25 #include "check_update.h"
29 #define CRITERIA L"(IsInstalled = 0 and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441') or (IsInstalled = 0 and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4')"
31 namespace po = boost::program_options;
33 static BOOL debug = FALSE;
35 INT wmain(INT argc, WCHAR **argv)
37 printInfoStruct printInfo = { FALSE, FALSE, 0, FALSE, FALSE, FALSE };
40 INT ret = parseArguments(argc, argv, vm, printInfo);
44 ret = check_update(printInfo);
48 return printOutput(printInfo);
51 INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
53 WCHAR namePath[MAX_PATH];
54 GetModuleFileName(NULL, namePath, MAX_PATH);
55 WCHAR *progName = PathFindFileName(namePath);
57 po::options_description desc;
60 ("help,h", "Print help message and exit")
61 ("version,V", "Print version and exit")
62 ("debug,d", "Verbose/Debug output")
63 ("warning,w", "Warn if there are important updates available")
64 ("critical,c", "Critical if there are important updates that require a reboot")
65 ("possible-reboot", "Treat \"update may need reboot\" as \"update needs reboot\"")
68 po::basic_command_line_parser<WCHAR> parser(ac, av);
75 po::command_line_style::unix_style |
76 po::command_line_style::allow_long_disguise)
80 } catch (std::exception& e) {
81 std::cout << e.what() << '\n' << desc << '\n';
85 if (vm.count("help")) {
86 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
88 L"%s is a simple program to check a machines required updates.\n"
89 L"You can use the following options to define its behaviour:\n\n", progName);
92 L"\nAfter some time, it will then output a string like this one:\n\n"
93 L"\tUPDATE WARNING 8 | updates=8;1;1;0\n\n"
94 L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n"
95 L"and \"8\" is the number of important updates updates.\n"
96 L"The performance data is found behind the \"|\", in order:\n"
97 L"returned value, warning threshold, critical threshold, minimal value and,\n"
98 L"if applicable, the maximal value. Performance data will only be displayed when\n"
99 L"you set at least one threshold\n\n"
100 L"An update counts as important when it is part of the Security- or\n"
101 L"CriticalUpdates group.\n"
102 L"Consult the msdn on WSUS Classification GUIDs for more information.\n"
103 L"%s' exit codes denote the following:\n"
104 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
105 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
106 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
107 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
108 L"%s works different from other plugins in that you do not set thresholds\n"
109 L"but only activate them. Using \"-w\" triggers warning state if there are not\n"
110 L"installed and non-optional updates. \"-c\" triggers critical if there are\n"
111 L"non-optional updates that require a reboot.\n"
112 L"The \"possible-reboot\" option is not recommended since this true for nearly\n"
114 , progName, progName);
117 } if (vm.count("version")) {
118 std::cout << "Version: " << VERSION << '\n';
122 if (vm.count("warning"))
123 printInfo.warn = TRUE;
125 if (vm.count("critical"))
126 printInfo.crit = TRUE;
128 if (vm.count("possible-reboot"))
129 printInfo.careForCanRequest = TRUE;
131 if (vm.count("debug"))
137 INT printOutput(const printInfoStruct& printInfo)
140 std::wcout << L"Constructing output string" << '\n';
143 std::wstring output = L"UPDATE ";
145 if (printInfo.important)
148 if (printInfo.reboot)
153 output.append(L"OK ");
156 output.append(L"WARNING ");
159 output.append(L"CRITICAL ");
163 std::wcout << output << printInfo.numUpdates << L" | update=" << printInfo.numUpdates << L";"
164 << printInfo.warn << L";" << printInfo.crit << L";0;" << '\n';
169 INT check_update(printInfoStruct& printInfo)
172 std::wcout << "Initializing COM library" << '\n';
173 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
174 ISearchResult *pResult;
175 IUpdateSession *pSession;
176 IUpdateSearcher *pSearcher;
177 BSTR criteria = NULL;
181 std::wcout << "Creating UpdateSession and UpdateSearcher" << '\n';
182 CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&pSession);
183 pSession->CreateUpdateSearcher(&pSearcher);
186 * IsInstalled = 0: All updates, including languagepacks and features
187 * BrowseOnly = 0: No features or languagepacks, security and unnamed
188 * BrowseOnly = 1: Nothing, broken
189 * RebootRequired = 1: Reboot required
192 criteria = SysAllocString(CRITERIA);
193 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx
194 // https://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx
197 std::wcout << L"Querrying updates from server" << '\n';
199 err = pSearcher->Search(criteria, &pResult);
202 SysFreeString(criteria);
204 IUpdateCollection *pCollection;
208 pResult->get_Updates(&pCollection);
209 pCollection->get_Count(&updateSize);
214 printInfo.numUpdates = updateSize;
215 // printInfo.important = printInfo.warn;
217 IInstallationBehavior *pIbehav;
218 InstallationRebootBehavior updateReboot;
220 for (LONG i = 0; i < updateSize; i++) {
221 pCollection->get_Item(i, &pUpdate);
223 std::wcout << L"Checking reboot behaviour of update number " << i << '\n';
225 pUpdate->get_InstallationBehavior(&pIbehav);
226 pIbehav->get_RebootBehavior(&updateReboot);
227 if (updateReboot == irbAlwaysRequiresReboot) {
228 printInfo.reboot = TRUE;
230 std::wcout << L"It requires reboot" << '\n';
233 if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot)
235 std::wcout << L"It requires reboot" << '\n';
236 printInfo.reboot = TRUE;
240 std::wcout << L"Cleaning up and returning" << '\n';
242 SysFreeString(criteria);
250 SysFreeString(criteria);