]> granicus.if.org Git - icinga2/blob - plugins/check_update.cpp
Fix missing command arguments
[icinga2] / plugins / check_update.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
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.                     *
9  *                                                                            *
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.                               *
14  *                                                                            *
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  ******************************************************************************/
19 #include <windows.h>
20 #include <Shlwapi.h>
21 #include <iostream>
22 #include <wuapi.h>
23 #include <wuerror.h>
24
25 #include "thresholds.h"
26
27 #include "boost/program_options.hpp"
28
29 #define VERSION 1.0
30
31 #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
33 namespace po = boost::program_options;
34
35 using std::wcout; using std::endl;
36 using std::wstring; using std::cout;
37
38 struct printInfoStruct 
39 {
40         BOOL warn, crit;
41         LONG numUpdates;
42         BOOL important, reboot, careForCanRequest;
43 };
44
45 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
46 static int printOutput(const printInfoStruct&);
47 static int check_update(printInfoStruct&);
48
49 int main(int argc, wchar_t **argv) 
50 {
51         po::variables_map vm;
52         printInfoStruct printInfo = { FALSE, FALSE, 0, FALSE, FALSE, FALSE };
53
54         int ret = parseArguments(argc, argv, vm, printInfo);
55         if (ret != -1)
56                 return ret;
57         
58         ret = check_update(printInfo);
59         if (ret != -1)
60                 return ret;
61
62         return printOutput(printInfo);
63 }
64
65 int printOutput(const printInfoStruct& printInfo) 
66 {
67         state state = OK;
68         wstring output = L"UPDATE ";
69
70         if (printInfo.important)
71                 state = WARNING;
72
73         if (printInfo.reboot)
74                 state = CRITICAL;
75
76         switch (state) {
77         case OK:
78                 output.append(L"OK ");
79                 break;
80         case WARNING:
81                 output.append(L"WARNING ");
82                 break;
83         case CRITICAL:
84                 output.append(L"CRITICAL ");
85                 break;
86         }
87
88         wcout << output << printInfo.numUpdates << L" | update=" << printInfo.numUpdates << L";"
89                 << printInfo.warn << L";" << printInfo.crit << L";0;" << endl;
90         
91         return state;
92 }
93
94 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) 
95 {
96         wchar_t namePath[MAX_PATH];
97         GetModuleFileName(NULL, namePath, MAX_PATH);
98         wchar_t *progName = PathFindFileName(namePath);
99
100         po::options_description desc;
101
102         desc.add_options()
103                 ("help,h", "print help message and exit")
104                 ("version,V", "print version and exit")
105                 ("warning,w", "warn if there are important updates available")
106                 ("critical,c", "critical if there are important updates that require a reboot")
107                 ("possible-reboot", "treat \"update may need to reboot\" as \"update needs to reboot\"")
108                 ;
109
110         po::basic_command_line_parser<wchar_t> parser(ac, av);
111
112         try {
113                 po::store(
114                         parser
115                         .options(desc)
116                         .style(
117                         po::command_line_style::unix_style |
118                         po::command_line_style::allow_long_disguise)
119                         .run(),
120                         vm);
121                 vm.notify();
122         } catch (std::exception& e) {
123                 cout << e.what() << endl << desc << endl;
124                 return 3;
125         }
126     
127         if (vm.count("help")) {
128                 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
129                 wprintf(
130                         L"%s is a simple program to check a machines required updates.\n"
131                         L"You can use the following options to define its behaviour:\n\n", progName);
132                 cout << desc;
133                 wprintf(
134                         L"\nAfter some time, it will then output a string like this one:\n\n"
135                         L"\tUPDATE WARNING 8|updates=8;1;1;0\n\n"
136                         L"\"UPDATE\" being the type of the check, \"WARNING\" the returned status\n"
137                         L"and \"8\" is the number of important updates updates.\n"
138                         L"The performance data is found behind the \"|\", in order:\n"
139                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
140                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
141                         L"you set at least one threshold\n\n"
142                         L"An update counts as important when it is part of the Security- or\n"
143                         L"CriticalUpdates group.\n"
144                         L"Consult the msdn on WSUS Classification GUIDs for more information.\n"
145                         L"%s' exit codes denote the following:\n"
146                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
147                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
148                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
149                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
150                         L"%s works different from other plugins in that you do not set thresholds\n"
151                         L"but only activate them. Using \"-w\" triggers warning state if there are not\n"
152                         L"installed and non-optional updates. \"-c\" triggers critical if there are\n"
153                         L"non-optional updates that require a reboot.\n"
154                         L"The \"possible-reboot\" option is not recommended since this true for nearly\n"
155                         L"every update."
156                         , progName, progName);
157                 cout << endl;
158                 return 0;
159         }  if (vm.count("version")) {
160                 cout << "Version: " << VERSION << endl;
161                 return 0;
162         }
163
164         if (vm.count("warning"))
165                 printInfo.warn = TRUE;
166
167         if (vm.count("critical"))
168                 printInfo.crit = TRUE;
169
170         if (vm.count("possible-reboot"))
171                 printInfo.careForCanRequest = TRUE;
172
173         return -1;
174 }
175
176 int check_update(printInfoStruct& printInfo) 
177 {
178         CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
179         ISearchResult *pResult;
180         IUpdateSession *pSession;
181         IUpdateSearcher *pSearcher;
182
183         HRESULT err;
184
185         CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&pSession);
186         pSession->CreateUpdateSearcher(&pSearcher);
187
188         /*
189          IsInstalled = 0: All updates, including languagepacks and features
190          BrowseOnly = 0: No features or languagepacks, security and unnamed
191          BrowseOnly = 1: Nothing, broken
192          RebootRequired = 1: Reboot required
193         */
194
195         BSTR criteria = SysAllocString(CRITERIA);
196         // http://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx
197         // http://msdn.microsoft.com/en-us/library/ff357803%28v=vs.85%29.aspx
198
199         err = pSearcher->Search(criteria, &pResult);
200         if (!SUCCEEDED(err))
201                 goto die;
202         SysFreeString(criteria);
203
204         IUpdateCollection *pCollection;
205         IUpdate *pUpdate;
206
207         LONG updateSize;
208         pResult->get_Updates(&pCollection);
209         pCollection->get_Count(&updateSize);
210
211         if (updateSize == 0)
212                 return -1;
213
214         printInfo.numUpdates = updateSize;
215         printInfo.important = printInfo.warn;
216
217         if (!printInfo.crit)
218                 return -1;
219
220         IInstallationBehavior *pIbehav;
221         InstallationRebootBehavior updateReboot;
222
223         for (LONG i = 0; i < updateSize; i++) {
224                 pCollection->get_Item(i, &pUpdate);
225                 pUpdate->get_InstallationBehavior(&pIbehav);
226                 pIbehav->get_RebootBehavior(&updateReboot);
227                 if (updateReboot == irbAlwaysRequiresReboot) {
228                         printInfo.reboot = TRUE;
229                         continue;
230                 }
231                 if (printInfo.careForCanRequest && updateReboot == irbCanRequestReboot)
232                         printInfo.reboot = TRUE;
233         }
234
235         return 0;
236
237 die:
238         die(err);
239         if (criteria)
240                 SysFreeString(criteria);
241         return 3;
242 }