VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use