VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 weeks 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
Line 
1/* $Id: VBoxManageUpdateCheck.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'updatecheck' command.
4 */
5
6/*
7 * Copyright (C) 2020-2024 Oracle and/or its affiliates.
8 *
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
26 */
27
28
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
49DECLARE_TRANSLATION_CONTEXT(UpdateCheck);
50
51using namespace com; // SafeArray
52
53
54static RTEXITCODE doUpdateList(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
55{
56 /*
57 * Parse options.
58 */
59 static const RTGETOPTDEF s_aOptions[] =
60 {
61 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
62 };
63 RTGETOPTSTATE GetState;
64 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
65 AssertRCReturn(vrc, RTEXITCODE_INIT);
66
67 bool fMachineReadable = false;
68
69 int c;
70 RTGETOPTUNION ValueUnion;
71 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
72 {
73 switch (c)
74 {
75 case 'm':
76 fMachineReadable = true;
77 break;
78
79 default:
80 return errorGetOpt(c, &ValueUnion);
81 }
82 }
83
84 /*
85 * Do the work.
86 */
87 BOOL fEnabled;
88 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Enabled)(&fEnabled), RTEXITCODE_FAILURE);
89 if (fMachineReadable)
90 outputMachineReadableBool("enabled", &fEnabled);
91 else
92 RTPrintf(UpdateCheck::tr("Enabled: %s\n"),
93 fEnabled ? UpdateCheck::tr("yes") : UpdateCheck::tr("no"));
94
95 ULONG cCheckCount;
96 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckCount)(&cCheckCount), RTEXITCODE_FAILURE);
97 if (fMachineReadable)
98 outputMachineReadableULong("count", &cCheckCount);
99 else
100 RTPrintf(UpdateCheck::tr("Count: %u\n"), cCheckCount);
101
102 ULONG uCheckFreqSeconds;
103 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(CheckFrequency)(&uCheckFreqSeconds), RTEXITCODE_FAILURE);
104
105 ULONG uCheckFreqDays = uCheckFreqSeconds / RT_SEC_1DAY;
106
107 if (fMachineReadable)
108 outputMachineReadableULong("frequency-days", &uCheckFreqDays);
109 else if (uCheckFreqDays == 0)
110 RTPrintf(UpdateCheck::tr("Frequency: Never\n"));
111 else if (uCheckFreqDays == 1)
112 RTPrintf(UpdateCheck::tr("Frequency: Every day\n"));
113 else
114 RTPrintf(UpdateCheck::tr("Frequency: Every %u days\n"), uCheckFreqDays);
115
116 UpdateChannel_T enmUpdateChannel;
117 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Channel)(&enmUpdateChannel), RTEXITCODE_FAILURE);
118 const char *psz;
119 const char *pszMachine;
120 switch (enmUpdateChannel)
121 {
122 case UpdateChannel_Stable:
123 psz = UpdateCheck::tr("Stable - new minor and maintenance releases");
124 pszMachine = "stable";
125 break;
126 case UpdateChannel_All:
127 psz = UpdateCheck::tr("All releases - new minor, maintenance, and major releases");
128 pszMachine = "all-releases";
129 break;
130 case UpdateChannel_WithBetas:
131 psz = UpdateCheck::tr("With Betas - new minor, maintenance, major, and beta releases");
132 pszMachine = "with-betas";
133 break;
134 default:
135 AssertFailed();
136 psz = UpdateCheck::tr("Unset");
137 pszMachine = "invalid";
138 break;
139 }
140 if (fMachineReadable)
141 outputMachineReadableString("channel", pszMachine);
142 else
143 RTPrintf(UpdateCheck::tr("Channel: %s\n"), psz);
144
145 Bstr bstrVal;
146 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(LastCheckDate)(bstrVal.asOutParam()),
147 RTEXITCODE_FAILURE);
148 if (fMachineReadable)
149 outputMachineReadableString("last-check-date", &bstrVal);
150 else if (bstrVal.isNotEmpty())
151 RTPrintf(UpdateCheck::tr("Last Check Date: %ls\n"), bstrVal.raw());
152
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
159 return RTEXITCODE_SUCCESS;
160}
161
162static RTEXITCODE doUpdateModify(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
163{
164 /*
165 * Parse options.
166 */
167 static const RTGETOPTDEF s_aOptions[] =
168 {
169 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
170 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
171 { "--channel", 'c', RTGETOPT_REQ_STRING },
172 { "--frequency", 'f', RTGETOPT_REQ_UINT32 },
173 };
174
175 RTGETOPTSTATE GetState;
176 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
177 AssertRCReturn(vrc, RTEXITCODE_INIT);
178
179 int fEnabled = -1; /* Tristate: -1 (not modified), false, true. */
180 UpdateChannel_T enmChannel = (UpdateChannel_T)-1;
181 uint32_t cFrequencyDays = 0;
182
183 int c;
184 RTGETOPTUNION ValueUnion;
185 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
186 {
187 switch (c)
188 {
189 case 'e':
190 fEnabled = true;
191 break;
192
193 case 'd':
194 fEnabled = false;
195 break;
196
197 case 'c':
198 if (!RTStrICmp(ValueUnion.psz, "stable"))
199 enmChannel = UpdateChannel_Stable;
200 else if (!RTStrICmp(ValueUnion.psz, "withbetas"))
201 enmChannel = UpdateChannel_WithBetas;
202 /** @todo UpdateChannel_WithTesting once supported. */
203 else if (!RTStrICmp(ValueUnion.psz, "all"))
204 enmChannel = UpdateChannel_All;
205 else
206 return errorArgument(UpdateCheck::tr("Invalid channel specified: '%s'"), ValueUnion.psz);
207 break;
208
209 case 'f':
210 cFrequencyDays = ValueUnion.u32;
211 if (cFrequencyDays == 0)
212 return errorArgument(UpdateCheck::tr("The update frequency cannot be zero"));
213 break;
214
215 /** @todo Add more options like repo handling etc. */
216
217 default:
218 return errorGetOpt(c, &ValueUnion);
219 }
220 }
221
222 if ( fEnabled == -1
223 && enmChannel == (UpdateChannel_T)-1
224 && cFrequencyDays == 0)
225 return errorSyntax(UpdateCheck::tr("No change requested"));
226
227 /*
228 * Make the changes.
229 */
230 if (enmChannel != (UpdateChannel_T)-1)
231 {
232 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Channel)(enmChannel), RTEXITCODE_FAILURE);
233 }
234 if (fEnabled != -1)
235 {
236 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(Enabled)((BOOL)fEnabled), RTEXITCODE_FAILURE);
237 }
238 if (cFrequencyDays)
239 {
240 CHECK_ERROR2I_RET(pUpdateAgent, COMSETTER(CheckFrequency)(cFrequencyDays * RT_SEC_1DAY), RTEXITCODE_FAILURE);
241 }
242 return RTEXITCODE_SUCCESS;
243}
244
245static RTEXITCODE doUpdateCheck(int argc, char **argv, ComPtr<IUpdateAgent> pUpdateAgent)
246{
247 /*
248 * Parse arguments.
249 */
250 static const RTGETOPTDEF s_aOptions[] =
251 {
252 { "--machine-readable", 'm', RTGETOPT_REQ_NOTHING }
253 };
254 RTGETOPTSTATE GetState;
255 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /* First */, 0);
256 AssertRCReturn(vrc, RTEXITCODE_INIT);
257
258 bool fMachineReadable = false;
259
260 int c;
261 RTGETOPTUNION ValueUnion;
262 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
263 {
264 switch (c)
265 {
266 case 'm':
267 fMachineReadable = true;
268 break;
269
270 default:
271 return errorGetOpt(c, &ValueUnion);
272 }
273 }
274
275 /*
276 * Do the work.
277 */
278 Bstr bstrName;
279 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
280
281 if (!fMachineReadable)
282 RTPrintf(UpdateCheck::tr("Checking for a new %ls version...\n"), bstrName.raw());
283
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;
289 HRESULT hrc = pUpdateAgent->CheckFor(pProgress.asOutParam());
290 if (FAILED(hrc))
291 {
292 if (pProgress.isNull())
293 RTStrmPrintf(g_pStdErr, UpdateCheck::tr("Failed to create update progress object: %Rhrc\n"), hrc);
294 else
295 com::GlueHandleComError(pUpdateAgent, "HostUpdate(UpdateChannel_Stable, pProgress.asOutParam())",
296 hrc, __FILE__, __LINE__);
297 return RTEXITCODE_FAILURE;
298 }
299
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);
302
303 UpdateState_T updateState;
304 CHECK_ERROR2I_RET(pUpdateAgent, COMGETTER(State)(&updateState), RTEXITCODE_FAILURE);
305
306 BOOL const fUpdateNeeded = updateState == UpdateState_Available;
307 if (fMachineReadable)
308 outputMachineReadableBool("update-needed", &fUpdateNeeded);
309
310 switch (updateState)
311 {
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);
318
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:
334 {
335 if (!fMachineReadable)
336 RTPrintf(UpdateCheck::tr("You are already running the most recent version of %ls.\n"), bstrName.raw());
337 break;
338 }
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 }
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{
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
372 if (a->argc < 1)
373 return errorNoSubcommand();
374 if (!RTStrICmp(a->argv[0], "perform"))
375 {
376 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_PERFORM);
377 return doUpdateCheck(a->argc - 1, &a->argv[1], pUpdate);
378 }
379 if (!RTStrICmp(a->argv[0], "list"))
380 {
381 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_LIST);
382 return doUpdateList(a->argc - 1, &a->argv[1], pUpdate);
383 }
384 if (!RTStrICmp(a->argv[0], "modify"))
385 {
386 setCurrentSubcommand(HELP_SCOPE_UPDATECHECK_MODIFY);
387 return doUpdateModify(a->argc - 1, &a->argv[1], pUpdate);
388 }
389 return errorUnknownSubcommand(a->argv[0]);
390}
391
392/* 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