VirtualBox

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

最後變更 在這個檔案從94756是 94756,由 vboxsync 提交於 3 年 前

Main/VBoxManage/Update check: More code + docs for proxy settings handling. bugref:7983

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.7 KB
 
1/* $Id: VBoxManageUpdateCheck.cpp 94756 2022-04-29 08:55:44Z 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.alldomusa.eu.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
44/**
45 * Returns the proxy mode as a string.
46 *
47 * @returns Proxy mode as string.
48 * @param enmMode Proxy mode to return as string.
49 */
50static const char *proxyModeToStr(ProxyMode_T enmMode)
51{
52 switch (enmMode)
53 {
54 case ProxyMode_System: return "System";
55 case ProxyMode_Manual: return "Manual";
56 case ProxyMode_NoProxy: return "None";
57 default: break;
58 }
59
60 AssertFailed();
61 return "<Invalid>";
62}
63
64static RTEXITCODE doUpdateList(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
65{
66 /*
67 * Parse options.
68 */
69 static const RTGETOPTDEF s_aOptions[] =
70 {
71 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
72 };
73 RTGETOPTSTATE GetState;
74 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
75 AssertRCReturn(vrc, RTEXITCODE_INIT);
76
77 bool fMachineReadable = false;
78
79 int c;
80 RTGETOPTUNION ValueUnion;
81 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
82 {
83 switch (c)
84 {
85 case 'm':
86 fMachineReadable = true;
87 break;
88
89 default:
90 return errorGetOpt(c, &ValueUnion);
91 }
92 }
93
94 /*
95 * Do the work.
96 */
97 BOOL fEnabled;
98 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Enabled)(&fEnabled), RTEXITCODE_FAILURE);
99 if (fMachineReadable)
100 outputMachineReadableBool("enabled", &fEnabled);
101 else
102 RTPrintf(UpdateCheck::tr("Enabled: %s\n"),
103 fEnabled ? UpdateCheck::tr("yes") : UpdateCheck::tr("no"));
104
105 ULONG cCheckCount;
106 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckCount)(&cCheckCount), RTEXITCODE_FAILURE);
107 if (fMachineReadable)
108 outputMachineReadableULong("count", &cCheckCount);
109 else
110 RTPrintf(UpdateCheck::tr("Count: %u\n"), cCheckCount);
111
112 ULONG uCheckFreqSeconds;
113 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckFrequency)(&uCheckFreqSeconds), RTEXITCODE_FAILURE);
114
115 ULONG uCheckFreqDays = uCheckFreqSeconds / RT_SEC_1DAY;
116
117 if (fMachineReadable)
118 outputMachineReadableULong("frequency-days", &uCheckFreqDays);
119 else if (uCheckFreqDays == 0)
120 RTPrintf(UpdateCheck::tr("Frequency: Never\n"));
121 else if (uCheckFreqDays == 1)
122 RTPrintf(UpdateCheck::tr("Frequency: Every day\n"));
123 else
124 RTPrintf(UpdateCheck::tr("Frequency: Every %u days\n"), uCheckFreqDays);
125
126 UpdateChannel_T enmUpdateChannel;
127 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Channel)(&enmUpdateChannel), RTEXITCODE_FAILURE);
128 const char *psz;
129 const char *pszMachine;
130 switch (enmUpdateChannel)
131 {
132 case UpdateChannel_Stable:
133 psz = UpdateCheck::tr("Stable - new minor and maintenance releases");
134 pszMachine = "stable";
135 break;
136 case UpdateChannel_All:
137 psz = UpdateCheck::tr("All releases - new minor, maintenance, and major releases");
138 pszMachine = "all-releases";
139 break;
140 case UpdateChannel_WithBetas:
141 psz = UpdateCheck::tr("With Betas - new minor, maintenance, major, and beta releases");
142 pszMachine = "with-betas";
143 break;
144 default:
145 AssertFailed();
146 psz = UpdateCheck::tr("Unset");
147 pszMachine = "invalid";
148 break;
149 }
150 if (fMachineReadable)
151 outputMachineReadableString("channel", pszMachine);
152 else
153 RTPrintf(UpdateCheck::tr("Channel: %s\n"), psz);
154
155 Bstr bstrVal;
156 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(LastCheckDate)(bstrVal.asOutParam()),
157 RTEXITCODE_FAILURE);
158 if (fMachineReadable)
159 outputMachineReadableString("last-check-date", &bstrVal);
160 else if (bstrVal.isNotEmpty())
161 RTPrintf(UpdateCheck::tr("Last Check Date: %ls\n"), bstrVal.raw());
162
163 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(RepositoryURL)(bstrVal.asOutParam()), RTEXITCODE_FAILURE);
164 if (fMachineReadable)
165 outputMachineReadableString("repo-url", &bstrVal);
166 else
167 RTPrintf(UpdateCheck::tr("Repository: %ls\n"), bstrVal.raw());
168
169 ProxyMode_T enmProxyMode;
170 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(ProxyMode)(&enmProxyMode), RTEXITCODE_FAILURE);
171 if (fMachineReadable)
172 outputMachineReadableString("proxy-mode", proxyModeToStr(enmProxyMode));
173 else
174 RTPrintf(UpdateCheck::tr("Proxy mode: %s\n"), proxyModeToStr(enmProxyMode));
175 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(ProxyURL)(bstrVal.asOutParam()), RTEXITCODE_FAILURE);
176 if (fMachineReadable)
177 outputMachineReadableString("proxy-url", &bstrVal);
178 else
179 RTPrintf(UpdateCheck::tr("Proxy URL: %ls\n"), bstrVal.raw());
180
181 return RTEXITCODE_SUCCESS;
182}
183
184static RTEXITCODE doUpdateModify(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
185{
186 /*
187 * Parse options.
188 */
189 enum GETOPTDEF_UPDATEMODIFY
190 {
191 GETOPTDEF_UPDATEMODIFY_PROXY_MODE = 2000,
192 GETOPTDEF_UPDATEMODIFY_PROXY_URL
193 };
194 static const RTGETOPTDEF s_aOptions[] =
195 {
196 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
197 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
198 { "--channel", 'c', RTGETOPT_REQ_STRING },
199 { "--frequency", 'f', RTGETOPT_REQ_UINT32 },
200 { "--proxy-mode", GETOPTDEF_UPDATEMODIFY_PROXY_MODE, RTGETOPT_REQ_STRING },
201 { "--proxy-url", GETOPTDEF_UPDATEMODIFY_PROXY_URL, RTGETOPT_REQ_STRING }
202 };
203
204 RTGETOPTSTATE GetState;
205 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
206 AssertRCReturn(vrc, RTEXITCODE_INIT);
207
208 int fEnabled = -1; /* Tristate: -1 (not modified), false, true. */
209 UpdateChannel_T enmChannel = (UpdateChannel_T)-1;
210 uint32_t cFrequencyDays = 0;
211 ProxyMode_T enmProxyMode = (ProxyMode_T)-1; /* Default if not modified, or ProxyMode_T values. */
212 Bstr strProxyURL = "unmodified"; /* Default if not modified, so that empty values also can be set (clears proxy). */
213
214 int c;
215 RTGETOPTUNION ValueUnion;
216 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
217 {
218 switch (c)
219 {
220 case 'e':
221 fEnabled = true;
222 break;
223
224 case 'd':
225 fEnabled = false;
226 break;
227
228 case 'c':
229 if (!RTStrICmp(ValueUnion.psz, "stable"))
230 enmChannel = UpdateChannel_Stable;
231 else if (!RTStrICmp(ValueUnion.psz, "withbetas"))
232 enmChannel = UpdateChannel_WithBetas;
233 /** @todo UpdateChannel_WithTesting once supported. */
234 else if (!RTStrICmp(ValueUnion.psz, "all"))
235 enmChannel = UpdateChannel_All;
236 else
237 return errorArgument(UpdateCheck::tr("Invalid channel specified: '%s'"), ValueUnion.psz);
238 break;
239
240 case 'f':
241 cFrequencyDays = ValueUnion.u32;
242 if (cFrequencyDays == 0)
243 return errorArgument(UpdateCheck::tr("The update frequency cannot be zero"));
244 break;
245
246 case GETOPTDEF_UPDATEMODIFY_PROXY_MODE:
247 if (!RTStrICmp(ValueUnion.psz, "system"))
248 enmProxyMode = ProxyMode_System;
249 else if ( !RTStrICmp(ValueUnion.psz, "none")
250 || !RTStrICmp(ValueUnion.psz, "disabled")
251 || !RTStrICmp(ValueUnion.psz, "off"))
252 enmProxyMode = ProxyMode_NoProxy;
253 else if (!RTStrICmp(ValueUnion.psz, "manual"))
254 enmProxyMode = ProxyMode_Manual;
255 else
256 return errorArgument(UpdateCheck::tr("Invalid proxy mode specified: '%s'"), ValueUnion.psz);
257 break;
258
259 case GETOPTDEF_UPDATEMODIFY_PROXY_URL:
260 strProxyURL = ValueUnion.psz;
261 break;
262
263 /** @todo Add more options like repo handling etc. */
264
265 default:
266 return errorGetOpt(c, &ValueUnion);
267 }
268 }
269
270 if ( fEnabled == -1
271 && enmChannel == (UpdateChannel_T)-1
272 && cFrequencyDays == 0
273 && enmProxyMode == (ProxyMode_T)-1
274 && strProxyURL == "unmodified")
275 return errorSyntax(UpdateCheck::tr("No change requested"));
276
277 /*
278 * Make the changes.
279 */
280 if (enmChannel != (UpdateChannel_T)-1)
281 {
282 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Channel)(enmChannel), RTEXITCODE_FAILURE);
283 }
284 if (fEnabled != -1)
285 {
286 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Enabled)((BOOL)fEnabled), RTEXITCODE_FAILURE);
287 }
288 if (cFrequencyDays)
289 {
290 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(CheckFrequency)(cFrequencyDays * RT_SEC_1DAY), RTEXITCODE_FAILURE);
291 }
292 if (enmProxyMode != (ProxyMode_T)-1)
293 {
294 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(ProxyMode)(enmProxyMode), RTEXITCODE_FAILURE);
295 }
296 if (strProxyURL.compare("unmodified") != 0)
297 {
298 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(ProxyURL)(strProxyURL.raw()), RTEXITCODE_FAILURE);
299 }
300 return RTEXITCODE_SUCCESS;
301}
302
303static RTEXITCODE doUpdateCheck(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
304{
305 /*
306 * Parse arguments.
307 */
308 static const RTGETOPTDEF s_aOptions[] =
309 {
310 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
311 };
312 RTGETOPTSTATE GetState;
313 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
314 AssertRCReturn(vrc, RTEXITCODE_INIT);
315
316 bool fMachineReadable = false;
317
318 int c;
319 RTGETOPTUNION ValueUnion;
320 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
321 {
322 switch (c)
323 {
324 case 'm':
325 fMachineReadable = true;
326 break;
327
328 default:
329 return errorGetOpt(c, &ValueUnion);
330 }
331 }
332
333 /*
334 * Do the work.
335 */
336 Bstr bstrName;
337 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
338
339 if (!fMachineReadable)
340 RTPrintf(UpdateCheck::tr("Checking for a new %ls version...\n"), bstrName.raw());
341
342 /*
343 * We don't call CHECK_ERROR2I_RET(pHostUpdate, VBoxUpdate(updateCheckType, ...); here so we can check for a specific
344 * return value indicating update checks are disabled.
345 */
346 ComPtr<IProgress> pProgress;
347 HRESULT rc = pUpdateAgent->CheckFor(pProgress.asOutParam());
348 if (FAILED(rc))
349 {
350 if (pProgress.isNull())
351 RTStrmPrintf(g_pStdErr, UpdateCheck::tr("Failed to create update progress object: %Rhrc\n"), rc);
352 else
353 com::GlueHandleComError(pUpdateAgent, "HostUpdate(UpdateChannel_Stable, pProgress.asOutParam())",
354 rc, __FILE__, __LINE__);
355 return RTEXITCODE_FAILURE;
356 }
357
358 /* HRESULT hrc = */ showProgress(pProgress, fMachineReadable ? SHOW_PROGRESS_NONE : SHOW_PROGRESS);
359 CHECK_PROGRESS_ERROR_RET(pProgress, (UpdateCheck::tr("Checking for update failed.")), RTEXITCODE_FAILURE);
360
361 UpdateState_T updateState;
362 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(State)(&updateState), RTEXITCODE_FAILURE);
363
364 BOOL const fUpdateNeeded = updateState == UpdateState_Available;
365 if (fMachineReadable)
366 outputMachineReadableBool("update-needed", &fUpdateNeeded);
367
368 switch (updateState)
369 {
370 case UpdateState_Available:
371 {
372 Bstr bstrUpdateVersion;
373 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Version)(bstrUpdateVersion.asOutParam()), RTEXITCODE_FAILURE);
374 Bstr bstrUpdateURL;
375 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(DownloadUrl)(bstrUpdateURL.asOutParam()), RTEXITCODE_FAILURE);
376
377 if (!fMachineReadable)
378 RTPrintf(UpdateCheck::tr(
379 "A new version of %ls has been released! Version %ls is available at virtualbox.org.\n"
380 "You can download this version here: %ls\n"),
381 bstrName.raw(), bstrUpdateVersion.raw(), bstrUpdateURL.raw());
382 else
383 {
384 outputMachineReadableString("update-version", &bstrUpdateVersion);
385 outputMachineReadableString("update-url", &bstrUpdateURL);
386 }
387
388 break;
389 }
390
391 case UpdateState_NotAvailable:
392 {
393 if (!fMachineReadable)
394 RTPrintf(UpdateCheck::tr("You are already running the most recent version of %ls.\n"), bstrName.raw());
395 break;
396 }
397
398 case UpdateState_Canceled:
399 break;
400
401 case UpdateState_Error:
402 RT_FALL_THROUGH();
403 default:
404 {
405 if (!fMachineReadable)
406 RTPrintf(UpdateCheck::tr("Something went wrong while checking for updates!\n"
407 "Please check network connection and try again later.\n"));
408 break;
409 }
410 }
411
412 return RTEXITCODE_SUCCESS;
413}
414
415/**
416 * Handles the 'updatecheck' command.
417 *
418 * @returns Appropriate exit code.
419 * @param a Handler argument.
420 */
421RTEXITCODE handleUpdateCheck(HandlerArg *a)
422{
423 ComPtr<IHost> pHost;
424 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(pHost.asOutParam()), RTEXITCODE_FAILURE);
425
426 ComPtr<IUpdateAgent> pUpdate;
427 CHECK_ERROR2I_RET(pHost, COMGETTER(UpdateHost)(pUpdate.asOutParam()), RTEXITCODE_FAILURE);
428 /** @todo Add other update agents here. */
429
430 if (a->argc < 1)
431 return errorNoSubcommand();
432 if (!RTStrICmp(a->argv[0], "perform"))
433 {
434 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_PERFORM);
435 return doUpdateCheck(a->argc - 1, &a->argv[1], pUpdate);
436 }
437 if (!RTStrICmp(a->argv[0], "list"))
438 {
439 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_LIST);
440 return doUpdateList(a->argc - 1, &a->argv[1], pUpdate);
441 }
442 if (!RTStrICmp(a->argv[0], "modify"))
443 {
444 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_MODIFY);
445 return doUpdateModify(a->argc - 1, &a->argv[1], pUpdate);
446 }
447 return errorUnknownSubcommand(a->argv[0]);
448}
449
450/* vi: set tabstop=4 shiftwidth=4 expandtab: */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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