VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp@ 95140

Last change on this file since 95140 was 95140, checked in by vboxsync, 3 years ago

Frontends + Main: Adjust to the new rules wrt. to rc -> hrc,vrc usage. This also fixes quite a few bugs wrt shadow variables, wrong return values and output error translations / exit codes. Also see @todos added. ​​bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: VBoxManageUpdateCheck.cpp 95140 2022-05-31 09:11:39Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'updatecheck' command.
4 */
5
6/*
7 * Copyright (C) 2020-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <VBox/com/com.h>
23#include <VBox/com/ErrorInfo.h>
24#include <VBox/com/errorprint.h>
25#include <VBox/com/VirtualBox.h>
26#include <VBox/com/array.h>
27
28#include <iprt/buildconfig.h>
29#include <VBox/version.h>
30
31#include <VBox/log.h>
32#include <iprt/getopt.h>
33#include <iprt/stream.h>
34#include <iprt/ctype.h>
35#include <iprt/message.h>
36
37#include "VBoxManage.h"
38
39DECLARE_TRANSLATION_CONTEXT(UpdateCheck);
40
41using namespace com; // SafeArray
42
43
44static RTEXITCODE doUpdateList(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
45{
46 /*
47 * Parse options.
48 */
49 static const RTGETOPTDEF s_aOptions[] =
50 {
51 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
52 };
53 RTGETOPTSTATE GetState;
54 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
55 AssertRCReturn(vrc, RTEXITCODE_INIT);
56
57 bool fMachineReadable = false;
58
59 int c;
60 RTGETOPTUNION ValueUnion;
61 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
62 {
63 switch (c)
64 {
65 case 'm':
66 fMachineReadable = true;
67 break;
68
69 default:
70 return errorGetOpt(c, &ValueUnion);
71 }
72 }
73
74 /*
75 * Do the work.
76 */
77 BOOL fEnabled;
78 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Enabled)(&fEnabled), RTEXITCODE_FAILURE);
79 if (fMachineReadable)
80 outputMachineReadableBool("enabled", &fEnabled);
81 else
82 RTPrintf(UpdateCheck::tr("Enabled: %s\n"),
83 fEnabled ? UpdateCheck::tr("yes") : UpdateCheck::tr("no"));
84
85 ULONG cCheckCount;
86 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckCount)(&cCheckCount), RTEXITCODE_FAILURE);
87 if (fMachineReadable)
88 outputMachineReadableULong("count", &cCheckCount);
89 else
90 RTPrintf(UpdateCheck::tr("Count: %u\n"), cCheckCount);
91
92 ULONG uCheckFreqSeconds;
93 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckFrequency)(&uCheckFreqSeconds), RTEXITCODE_FAILURE);
94
95 ULONG uCheckFreqDays = uCheckFreqSeconds / RT_SEC_1DAY;
96
97 if (fMachineReadable)
98 outputMachineReadableULong("frequency-days", &uCheckFreqDays);
99 else if (uCheckFreqDays == 0)
100 RTPrintf(UpdateCheck::tr("Frequency: Never\n"));
101 else if (uCheckFreqDays == 1)
102 RTPrintf(UpdateCheck::tr("Frequency: Every day\n"));
103 else
104 RTPrintf(UpdateCheck::tr("Frequency: Every %u days\n"), uCheckFreqDays);
105
106 UpdateChannel_T enmUpdateChannel;
107 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Channel)(&enmUpdateChannel), RTEXITCODE_FAILURE);
108 const char *psz;
109 const char *pszMachine;
110 switch (enmUpdateChannel)
111 {
112 case UpdateChannel_Stable:
113 psz = UpdateCheck::tr("Stable - new minor and maintenance releases");
114 pszMachine = "stable";
115 break;
116 case UpdateChannel_All:
117 psz = UpdateCheck::tr("All releases - new minor, maintenance, and major releases");
118 pszMachine = "all-releases";
119 break;
120 case UpdateChannel_WithBetas:
121 psz = UpdateCheck::tr("With Betas - new minor, maintenance, major, and beta releases");
122 pszMachine = "with-betas";
123 break;
124 default:
125 AssertFailed();
126 psz = UpdateCheck::tr("Unset");
127 pszMachine = "invalid";
128 break;
129 }
130 if (fMachineReadable)
131 outputMachineReadableString("channel", pszMachine);
132 else
133 RTPrintf(UpdateCheck::tr("Channel: %s\n"), psz);
134
135 Bstr bstrVal;
136 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(LastCheckDate)(bstrVal.asOutParam()),
137 RTEXITCODE_FAILURE);
138 if (fMachineReadable)
139 outputMachineReadableString("last-check-date", &bstrVal);
140 else if (bstrVal.isNotEmpty())
141 RTPrintf(UpdateCheck::tr("Last Check Date: %ls\n"), bstrVal.raw());
142
143 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(RepositoryURL)(bstrVal.asOutParam()), RTEXITCODE_FAILURE);
144 if (fMachineReadable)
145 outputMachineReadableString("repo-url", &bstrVal);
146 else
147 RTPrintf(UpdateCheck::tr("Repository: %ls\n"), bstrVal.raw());
148
149 return RTEXITCODE_SUCCESS;
150}
151
152static RTEXITCODE doUpdateModify(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
153{
154 /*
155 * Parse options.
156 */
157 static const RTGETOPTDEF s_aOptions[] =
158 {
159 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
160 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
161 { "--channel", 'c', RTGETOPT_REQ_STRING },
162 { "--frequency", 'f', RTGETOPT_REQ_UINT32 },
163 };
164
165 RTGETOPTSTATE GetState;
166 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
167 AssertRCReturn(vrc, RTEXITCODE_INIT);
168
169 int fEnabled = -1; /* Tristate: -1 (not modified), false, true. */
170 UpdateChannel_T enmChannel = (UpdateChannel_T)-1;
171 uint32_t cFrequencyDays = 0;
172
173 int c;
174 RTGETOPTUNION ValueUnion;
175 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
176 {
177 switch (c)
178 {
179 case 'e':
180 fEnabled = true;
181 break;
182
183 case 'd':
184 fEnabled = false;
185 break;
186
187 case 'c':
188 if (!RTStrICmp(ValueUnion.psz, "stable"))
189 enmChannel = UpdateChannel_Stable;
190 else if (!RTStrICmp(ValueUnion.psz, "withbetas"))
191 enmChannel = UpdateChannel_WithBetas;
192 /** @todo UpdateChannel_WithTesting once supported. */
193 else if (!RTStrICmp(ValueUnion.psz, "all"))
194 enmChannel = UpdateChannel_All;
195 else
196 return errorArgument(UpdateCheck::tr("Invalid channel specified: '%s'"), ValueUnion.psz);
197 break;
198
199 case 'f':
200 cFrequencyDays = ValueUnion.u32;
201 if (cFrequencyDays == 0)
202 return errorArgument(UpdateCheck::tr("The update frequency cannot be zero"));
203 break;
204
205 /** @todo Add more options like repo handling etc. */
206
207 default:
208 return errorGetOpt(c, &ValueUnion);
209 }
210 }
211
212 if ( fEnabled == -1
213 && enmChannel == (UpdateChannel_T)-1
214 && cFrequencyDays == 0)
215 return errorSyntax(UpdateCheck::tr("No change requested"));
216
217 /*
218 * Make the changes.
219 */
220 if (enmChannel != (UpdateChannel_T)-1)
221 {
222 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Channel)(enmChannel), RTEXITCODE_FAILURE);
223 }
224 if (fEnabled != -1)
225 {
226 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Enabled)((BOOL)fEnabled), RTEXITCODE_FAILURE);
227 }
228 if (cFrequencyDays)
229 {
230 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(CheckFrequency)(cFrequencyDays * RT_SEC_1DAY), RTEXITCODE_FAILURE);
231 }
232 return RTEXITCODE_SUCCESS;
233}
234
235static RTEXITCODE doUpdateCheck(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
236{
237 /*
238 * Parse arguments.
239 */
240 static const RTGETOPTDEF s_aOptions[] =
241 {
242 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
243 };
244 RTGETOPTSTATE GetState;
245 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
246 AssertRCReturn(vrc, RTEXITCODE_INIT);
247
248 bool fMachineReadable = false;
249
250 int c;
251 RTGETOPTUNION ValueUnion;
252 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
253 {
254 switch (c)
255 {
256 case 'm':
257 fMachineReadable = true;
258 break;
259
260 default:
261 return errorGetOpt(c, &ValueUnion);
262 }
263 }
264
265 /*
266 * Do the work.
267 */
268 Bstr bstrName;
269 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
270
271 if (!fMachineReadable)
272 RTPrintf(UpdateCheck::tr("Checking for a new %ls version...\n"), bstrName.raw());
273
274 /*
275 * We don't call CHECK_ERROR2I_RET(pHostUpdate, VBoxUpdate(updateCheckType, ...); here so we can check for a specific
276 * return value indicating update checks are disabled.
277 */
278 ComPtr<IProgress> pProgress;
279 HRESULT hrc = pUpdateAgent->CheckFor(pProgress.asOutParam());
280 if (FAILED(hrc))
281 {
282 if (pProgress.isNull())
283 RTStrmPrintf(g_pStdErr, UpdateCheck::tr("Failed to create update progress object: %Rhrc\n"), hrc);
284 else
285 com::GlueHandleComError(pUpdateAgent, "HostUpdate(UpdateChannel_Stable, pProgress.asOutParam())",
286 hrc, __FILE__, __LINE__);
287 return RTEXITCODE_FAILURE;
288 }
289
290 /* HRESULT hrc = */ showProgress(pProgress, fMachineReadable ? SHOW_PROGRESS_NONE : SHOW_PROGRESS);
291 CHECK_PROGRESS_ERROR_RET(pProgress, (UpdateCheck::tr("Checking for update failed.")), RTEXITCODE_FAILURE);
292
293 UpdateState_T updateState;
294 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(State)(&updateState), RTEXITCODE_FAILURE);
295
296 BOOL const fUpdateNeeded = updateState == UpdateState_Available;
297 if (fMachineReadable)
298 outputMachineReadableBool("update-needed", &fUpdateNeeded);
299
300 switch (updateState)
301 {
302 case UpdateState_Available:
303 {
304 Bstr bstrUpdateVersion;
305 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Version)(bstrUpdateVersion.asOutParam()), RTEXITCODE_FAILURE);
306 Bstr bstrUpdateURL;
307 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(DownloadUrl)(bstrUpdateURL.asOutParam()), RTEXITCODE_FAILURE);
308
309 if (!fMachineReadable)
310 RTPrintf(UpdateCheck::tr(
311 "A new version of %ls has been released! Version %ls is available at virtualbox.org.\n"
312 "You can download this version here: %ls\n"),
313 bstrName.raw(), bstrUpdateVersion.raw(), bstrUpdateURL.raw());
314 else
315 {
316 outputMachineReadableString("update-version", &bstrUpdateVersion);
317 outputMachineReadableString("update-url", &bstrUpdateURL);
318 }
319
320 break;
321 }
322
323 case UpdateState_NotAvailable:
324 {
325 if (!fMachineReadable)
326 RTPrintf(UpdateCheck::tr("You are already running the most recent version of %ls.\n"), bstrName.raw());
327 break;
328 }
329
330 case UpdateState_Canceled:
331 break;
332
333 case UpdateState_Error:
334 RT_FALL_THROUGH();
335 default:
336 {
337 if (!fMachineReadable)
338 RTPrintf(UpdateCheck::tr("Something went wrong while checking for updates!\n"
339 "Please check network connection and try again later.\n"));
340 break;
341 }
342 }
343
344 return RTEXITCODE_SUCCESS;
345}
346
347/**
348 * Handles the 'updatecheck' command.
349 *
350 * @returns Appropriate exit code.
351 * @param a Handler argument.
352 */
353RTEXITCODE handleUpdateCheck(HandlerArg *a)
354{
355 ComPtr<IHost> pHost;
356 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(pHost.asOutParam()), RTEXITCODE_FAILURE);
357
358 ComPtr<IUpdateAgent> pUpdate;
359 CHECK_ERROR2I_RET(pHost, COMGETTER(UpdateHost)(pUpdate.asOutParam()), RTEXITCODE_FAILURE);
360 /** @todo Add other update agents here. */
361
362 if (a->argc < 1)
363 return errorNoSubcommand();
364 if (!RTStrICmp(a->argv[0], "perform"))
365 {
366 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_PERFORM);
367 return doUpdateCheck(a->argc - 1, &a->argv[1], pUpdate);
368 }
369 if (!RTStrICmp(a->argv[0], "list"))
370 {
371 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_LIST);
372 return doUpdateList(a->argc - 1, &a->argv[1], pUpdate);
373 }
374 if (!RTStrICmp(a->argv[0], "modify"))
375 {
376 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_MODIFY);
377 return doUpdateModify(a->argc - 1, &a->argv[1], pUpdate);
378 }
379 return errorUnknownSubcommand(a->argv[0]);
380}
381
382/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette