From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Frontends/VBoxManage/VBoxManageUpdateCheck.cpp | 392 +++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp (limited to 'src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp') diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp new file mode 100644 index 00000000..5b66b70b --- /dev/null +++ b/src/VBox/Frontends/VBoxManage/VBoxManageUpdateCheck.cpp @@ -0,0 +1,392 @@ +/* $Id: VBoxManageUpdateCheck.cpp $ */ +/** @file + * VBoxManage - The 'updatecheck' command. + */ + +/* + * Copyright (C) 2020-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "VBoxManage.h" + +DECLARE_TRANSLATION_CONTEXT(UpdateCheck); + +using namespace com; // SafeArray + + +static RTEXITCODE doUpdateList(int argc, char **argv, ComPtr pUpdateAgent) +{ + /* + * Parse options. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING } + }; + RTGETOPTSTATE GetState; + int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0); + AssertRCReturn(vrc, RTEXITCODE_INIT); + + bool fMachineReadable = false; + + int c; + RTGETOPTUNION ValueUnion; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'm': + fMachineReadable = true; + break; + + default: + return errorGetOpt(c, &ValueUnion); + } + } + + /* + * Do the work. + */ + BOOL fEnabled; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Enabled)(&fEnabled), RTEXITCODE_FAILURE); + if (fMachineReadable) + outputMachineReadableBool("enabled", &fEnabled); + else + RTPrintf(UpdateCheck::tr("Enabled: %s\n"), + fEnabled ? UpdateCheck::tr("yes") : UpdateCheck::tr("no")); + + ULONG cCheckCount; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckCount)(&cCheckCount), RTEXITCODE_FAILURE); + if (fMachineReadable) + outputMachineReadableULong("count", &cCheckCount); + else + RTPrintf(UpdateCheck::tr("Count: %u\n"), cCheckCount); + + ULONG uCheckFreqSeconds; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckFrequency)(&uCheckFreqSeconds), RTEXITCODE_FAILURE); + + ULONG uCheckFreqDays = uCheckFreqSeconds / RT_SEC_1DAY; + + if (fMachineReadable) + outputMachineReadableULong("frequency-days", &uCheckFreqDays); + else if (uCheckFreqDays == 0) + RTPrintf(UpdateCheck::tr("Frequency: Never\n")); + else if (uCheckFreqDays == 1) + RTPrintf(UpdateCheck::tr("Frequency: Every day\n")); + else + RTPrintf(UpdateCheck::tr("Frequency: Every %u days\n"), uCheckFreqDays); + + UpdateChannel_T enmUpdateChannel; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Channel)(&enmUpdateChannel), RTEXITCODE_FAILURE); + const char *psz; + const char *pszMachine; + switch (enmUpdateChannel) + { + case UpdateChannel_Stable: + psz = UpdateCheck::tr("Stable - new minor and maintenance releases"); + pszMachine = "stable"; + break; + case UpdateChannel_All: + psz = UpdateCheck::tr("All releases - new minor, maintenance, and major releases"); + pszMachine = "all-releases"; + break; + case UpdateChannel_WithBetas: + psz = UpdateCheck::tr("With Betas - new minor, maintenance, major, and beta releases"); + pszMachine = "with-betas"; + break; + default: + AssertFailed(); + psz = UpdateCheck::tr("Unset"); + pszMachine = "invalid"; + break; + } + if (fMachineReadable) + outputMachineReadableString("channel", pszMachine); + else + RTPrintf(UpdateCheck::tr("Channel: %s\n"), psz); + + Bstr bstrVal; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(LastCheckDate)(bstrVal.asOutParam()), + RTEXITCODE_FAILURE); + if (fMachineReadable) + outputMachineReadableString("last-check-date", &bstrVal); + else if (bstrVal.isNotEmpty()) + RTPrintf(UpdateCheck::tr("Last Check Date: %ls\n"), bstrVal.raw()); + + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(RepositoryURL)(bstrVal.asOutParam()), RTEXITCODE_FAILURE); + if (fMachineReadable) + outputMachineReadableString("repo-url", &bstrVal); + else + RTPrintf(UpdateCheck::tr("Repository: %ls\n"), bstrVal.raw()); + + return RTEXITCODE_SUCCESS; +} + +static RTEXITCODE doUpdateModify(int argc, char **argv, ComPtr pUpdateAgent) +{ + /* + * Parse options. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--enable", 'e', RTGETOPT_REQ_NOTHING }, + { "--disable", 'd', RTGETOPT_REQ_NOTHING }, + { "--channel", 'c', RTGETOPT_REQ_STRING }, + { "--frequency", 'f', RTGETOPT_REQ_UINT32 }, + }; + + RTGETOPTSTATE GetState; + int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0); + AssertRCReturn(vrc, RTEXITCODE_INIT); + + int fEnabled = -1; /* Tristate: -1 (not modified), false, true. */ + UpdateChannel_T enmChannel = (UpdateChannel_T)-1; + uint32_t cFrequencyDays = 0; + + int c; + RTGETOPTUNION ValueUnion; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'e': + fEnabled = true; + break; + + case 'd': + fEnabled = false; + break; + + case 'c': + if (!RTStrICmp(ValueUnion.psz, "stable")) + enmChannel = UpdateChannel_Stable; + else if (!RTStrICmp(ValueUnion.psz, "withbetas")) + enmChannel = UpdateChannel_WithBetas; + /** @todo UpdateChannel_WithTesting once supported. */ + else if (!RTStrICmp(ValueUnion.psz, "all")) + enmChannel = UpdateChannel_All; + else + return errorArgument(UpdateCheck::tr("Invalid channel specified: '%s'"), ValueUnion.psz); + break; + + case 'f': + cFrequencyDays = ValueUnion.u32; + if (cFrequencyDays == 0) + return errorArgument(UpdateCheck::tr("The update frequency cannot be zero")); + break; + + /** @todo Add more options like repo handling etc. */ + + default: + return errorGetOpt(c, &ValueUnion); + } + } + + if ( fEnabled == -1 + && enmChannel == (UpdateChannel_T)-1 + && cFrequencyDays == 0) + return errorSyntax(UpdateCheck::tr("No change requested")); + + /* + * Make the changes. + */ + if (enmChannel != (UpdateChannel_T)-1) + { + CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Channel)(enmChannel), RTEXITCODE_FAILURE); + } + if (fEnabled != -1) + { + CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Enabled)((BOOL)fEnabled), RTEXITCODE_FAILURE); + } + if (cFrequencyDays) + { + CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(CheckFrequency)(cFrequencyDays * RT_SEC_1DAY), RTEXITCODE_FAILURE); + } + return RTEXITCODE_SUCCESS; +} + +static RTEXITCODE doUpdateCheck(int argc, char **argv, ComPtr pUpdateAgent) +{ + /* + * Parse arguments. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING } + }; + RTGETOPTSTATE GetState; + int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0); + AssertRCReturn(vrc, RTEXITCODE_INIT); + + bool fMachineReadable = false; + + int c; + RTGETOPTUNION ValueUnion; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'm': + fMachineReadable = true; + break; + + default: + return errorGetOpt(c, &ValueUnion); + } + } + + /* + * Do the work. + */ + Bstr bstrName; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE); + + if (!fMachineReadable) + RTPrintf(UpdateCheck::tr("Checking for a new %ls version...\n"), bstrName.raw()); + + /* + * We don't call CHECK_ERROR2I_RET(pHostUpdate, VBoxUpdate(updateCheckType, ...); here so we can check for a specific + * return value indicating update checks are disabled. + */ + ComPtr pProgress; + HRESULT hrc = pUpdateAgent->CheckFor(pProgress.asOutParam()); + if (FAILED(hrc)) + { + if (pProgress.isNull()) + RTStrmPrintf(g_pStdErr, UpdateCheck::tr("Failed to create update progress object: %Rhrc\n"), hrc); + else + com::GlueHandleComError(pUpdateAgent, "HostUpdate(UpdateChannel_Stable, pProgress.asOutParam())", + hrc, __FILE__, __LINE__); + return RTEXITCODE_FAILURE; + } + + /* HRESULT hrc = */ showProgress(pProgress, fMachineReadable ? SHOW_PROGRESS_NONE : SHOW_PROGRESS); + CHECK_PROGRESS_ERROR_RET(pProgress, (UpdateCheck::tr("Checking for update failed.")), RTEXITCODE_FAILURE); + + UpdateState_T updateState; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(State)(&updateState), RTEXITCODE_FAILURE); + + BOOL const fUpdateNeeded = updateState == UpdateState_Available; + if (fMachineReadable) + outputMachineReadableBool("update-needed", &fUpdateNeeded); + + switch (updateState) + { + case UpdateState_Available: + { + Bstr bstrUpdateVersion; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Version)(bstrUpdateVersion.asOutParam()), RTEXITCODE_FAILURE); + Bstr bstrUpdateURL; + CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(DownloadUrl)(bstrUpdateURL.asOutParam()), RTEXITCODE_FAILURE); + + if (!fMachineReadable) + RTPrintf(UpdateCheck::tr( + "A new version of %ls has been released! Version %ls is available at virtualbox.org.\n" + "You can download this version here: %ls\n"), + bstrName.raw(), bstrUpdateVersion.raw(), bstrUpdateURL.raw()); + else + { + outputMachineReadableString("update-version", &bstrUpdateVersion); + outputMachineReadableString("update-url", &bstrUpdateURL); + } + + break; + } + + case UpdateState_NotAvailable: + { + if (!fMachineReadable) + RTPrintf(UpdateCheck::tr("You are already running the most recent version of %ls.\n"), bstrName.raw()); + break; + } + + case UpdateState_Canceled: + break; + + case UpdateState_Error: + RT_FALL_THROUGH(); + default: + { + if (!fMachineReadable) + RTPrintf(UpdateCheck::tr("Something went wrong while checking for updates!\n" + "Please check network connection and try again later.\n")); + break; + } + } + + return RTEXITCODE_SUCCESS; +} + +/** + * Handles the 'updatecheck' command. + * + * @returns Appropriate exit code. + * @param a Handler argument. + */ +RTEXITCODE handleUpdateCheck(HandlerArg *a) +{ + ComPtr pHost; + CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(pHost.asOutParam()), RTEXITCODE_FAILURE); + + ComPtr pUpdate; + CHECK_ERROR2I_RET(pHost, COMGETTER(UpdateHost)(pUpdate.asOutParam()), RTEXITCODE_FAILURE); + /** @todo Add other update agents here. */ + + if (a->argc < 1) + return errorNoSubcommand(); + if (!RTStrICmp(a->argv[0], "perform")) + { + setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_PERFORM); + return doUpdateCheck(a->argc - 1, &a->argv[1], pUpdate); + } + if (!RTStrICmp(a->argv[0], "list")) + { + setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_LIST); + return doUpdateList(a->argc - 1, &a->argv[1], pUpdate); + } + if (!RTStrICmp(a->argv[0], "modify")) + { + setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_MODIFY); + return doUpdateModify(a->argc - 1, &a->argv[1], pUpdate); + } + return errorUnknownSubcommand(a->argv[0]); +} + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ -- cgit v1.2.3