VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostUpdateImpl.cpp@ 85731

Last change on this file since 85731 was 85731, checked in by vboxsync, 5 years ago

Main/HostUpdateImpl.cpp: updateCheck() must validate the bugref:7983updateCheck

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/* $Id: HostUpdateImpl.cpp 85731 2020-08-12 20:26:52Z vboxsync $ */
2/** @file
3 * IHostUpdate COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#define LOG_GROUP LOG_GROUP_MAIN_HOSTUPDATE
20
21#include <iprt/cpp/utils.h>
22#include <iprt/param.h>
23#include <iprt/path.h>
24#include <iprt/http.h>
25#include <iprt/system.h>
26#include <iprt/message.h>
27#include <iprt/pipe.h>
28#include <iprt/env.h>
29#include <iprt/process.h>
30#include <iprt/assert.h>
31#include <iprt/err.h>
32#include <iprt/stream.h>
33#include <iprt/time.h>
34#include <VBox/com/defs.h>
35#include <VBox/version.h>
36
37#include "HostImpl.h"
38#include "HostUpdateImpl.h"
39#include "ProgressImpl.h"
40#include "AutoCaller.h"
41#include "LoggingNew.h"
42#include "VirtualBoxImpl.h"
43#include "ThreadTask.h"
44#include "SystemPropertiesImpl.h"
45#include "VirtualBoxBase.h"
46
47
48////////////////////////////////////////////////////////////////////////////////
49//
50// HostUpdate private data definition
51//
52////////////////////////////////////////////////////////////////////////////////
53
54
55class HostUpdate::UpdateCheckTask : public ThreadTask
56{
57public:
58 UpdateCheckTask(UpdateCheckType_T aCheckType, HostUpdate *aThat, Progress *aProgress)
59 : m_checkType(aCheckType)
60 , m_pHostUpdate(aThat)
61 , m_ptrProgress(aProgress)
62 , m_rc(S_OK)
63 {
64 m_strTaskName = "UpdateCheckTask";
65 }
66 ~UpdateCheckTask() { }
67
68private:
69 void handler();
70
71 UpdateCheckType_T m_checkType;
72 HostUpdate *m_pHostUpdate;
73
74 /** Smart pointer to the progress object for this job. */
75 ComObjPtr<Progress> m_ptrProgress;
76 HRESULT m_rc; /**< Not really used for anything outside i_updateCheckTask, at the moment. */
77
78 friend class HostUpdate; // allow member functions access to private data
79};
80
81void HostUpdate::UpdateCheckTask::handler()
82{
83 HostUpdate *pHostUpdate = this->m_pHostUpdate;
84
85 LogFlowFuncEnter();
86 LogFlowFunc(("HostUpdate %p\n", pHostUpdate));
87
88 HRESULT rc = pHostUpdate->i_updateCheckTask(this);
89
90 LogFlowFunc(("rc=%Rhrc\n", rc)); NOREF(rc);
91 LogFlowFuncLeave();
92}
93
94Utf8Str HostUpdate::i_platformInfo()
95{
96 /* Prepare platform report: */
97 Utf8Str strPlatform;
98
99#if defined (RT_OS_WINDOWS)
100 strPlatform = "win";
101#elif defined (RT_OS_LINUX)
102 strPlatform = "linux";
103#elif defined (RT_OS_DARWIN)
104 strPlatform = "macosx";
105#elif defined (RT_OS_OS2)
106 strPlatform = "os2";
107#elif defined (RT_OS_FREEBSD)
108 strPlatform = "freebsd";
109#elif defined (RT_OS_SOLARIS)
110 strPlatform = "solaris";
111#else
112 strPlatform = "unknown";
113#endif
114
115 /* The format is <system>.<bitness>: */
116 strPlatform.appendPrintf(".%lu", ARCH_BITS);
117
118 /* Add more system information: */
119 int vrc;
120#ifdef RT_OS_LINUX
121 // WORKAROUND:
122 // On Linux we try to generate information using script first of all..
123
124 /* Get script path: */
125 char szAppPrivPath[RTPATH_MAX];
126 vrc = RTPathAppPrivateNoArch(szAppPrivPath, sizeof(szAppPrivPath));
127 AssertRC(vrc);
128 if (RT_SUCCESS(vrc))
129 vrc = RTPathAppend(szAppPrivPath, sizeof(szAppPrivPath), "/VBoxSysInfo.sh");
130 AssertRC(vrc);
131 if (RT_SUCCESS(vrc))
132 {
133 RTPIPE hPipeR;
134 RTHANDLE hStdOutPipe;
135 hStdOutPipe.enmType = RTHANDLETYPE_PIPE;
136 vrc = RTPipeCreate(&hPipeR, &hStdOutPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE);
137 AssertLogRelRC(vrc);
138
139 char const *szAppPrivArgs[2];
140 szAppPrivArgs[0] = szAppPrivPath;
141 szAppPrivArgs[1] = NULL;
142 RTPROCESS hProc = NIL_RTPROCESS;
143
144 /* Run script: */
145 vrc = RTProcCreateEx(szAppPrivPath, szAppPrivArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL /*phStdin*/, &hStdOutPipe,
146 NULL /*phStderr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/, NULL /*pvExtraData*/, &hProc);
147
148 (void) RTPipeClose(hStdOutPipe.u.hPipe);
149 hStdOutPipe.u.hPipe = NIL_RTPIPE;
150
151 if (RT_SUCCESS(vrc))
152 {
153 RTPROCSTATUS ProcStatus;
154 size_t cbStdOutBuf = 0;
155 size_t offStdOutBuf = 0;
156 char *pszStdOutBuf = NULL;
157 do
158 {
159 if (hPipeR != NIL_RTPIPE)
160 {
161 char achBuf[1024];
162 size_t cbRead;
163 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
164 if (RT_SUCCESS(vrc))
165 {
166 /* grow the buffer? */
167 size_t cbBufReq = offStdOutBuf + cbRead + 1;
168 if ( cbBufReq > cbStdOutBuf
169 && cbBufReq < _256K)
170 {
171 size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024
172 void *pvNew = RTMemRealloc(pszStdOutBuf, cbNew);
173 if (pvNew)
174 {
175 pszStdOutBuf = (char *)pvNew;
176 cbStdOutBuf = cbNew;
177 }
178 }
179
180 /* append if we've got room. */
181 if (cbBufReq <= cbStdOutBuf)
182 {
183 (void) memcpy(&pszStdOutBuf[offStdOutBuf], achBuf, cbRead);
184 offStdOutBuf = offStdOutBuf + cbRead;
185 pszStdOutBuf[offStdOutBuf] = '\0';
186 }
187 }
188 else
189 {
190 AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc));
191 RTPipeClose(hPipeR);
192 hPipeR = NIL_RTPIPE;
193 }
194 }
195
196 /*
197 * Service the process. Block if we have no pipe.
198 */
199 if (hProc != NIL_RTPROCESS)
200 {
201 vrc = RTProcWait(hProc,
202 hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK,
203 &ProcStatus);
204 if (RT_SUCCESS(vrc))
205 hProc = NIL_RTPROCESS;
206 else
207 AssertLogRelMsgStmt(vrc == VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProc = NIL_RTPROCESS);
208 }
209 } while ( hPipeR != NIL_RTPIPE
210 || hProc != NIL_RTPROCESS);
211
212 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
213 && ProcStatus.iStatus == 0) {
214 pszStdOutBuf[offStdOutBuf-1] = '\0'; // remove trailing newline
215 Utf8Str pszStdOutBufUTF8(pszStdOutBuf);
216 strPlatform.appendPrintf(" [%s]", pszStdOutBufUTF8.strip().c_str());
217 // For testing, here is some sample output:
218 //strPlatform.appendPrintf(" [Distribution: Redhat | Version: 7.6.1810 | Kernel: Linux version 3.10.0-952.27.2.el7.x86_64 (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1 SMP Mon Jul 29 17:46:05 UTC 2019]");
219 }
220 }
221 else
222 vrc = VERR_TRY_AGAIN; /* (take the fallback path) */
223 }
224
225 LogRelFunc(("strPlatform (Linux) = %s\n", strPlatform.c_str()));
226
227 if (RT_FAILURE(vrc))
228#endif /* RT_OS_LINUX */
229 {
230 /* Use RTSystemQueryOSInfo: */
231 char szTmp[256];
232
233 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
234 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
235 strPlatform.appendPrintf(" [Product: %s", szTmp);
236
237 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
238 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
239 strPlatform.appendPrintf(" %sRelease: %s", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
240
241 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
242 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
243 strPlatform.appendPrintf(" %sVersion: %s", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
244
245 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
246 if ((RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) && szTmp[0] != '\0')
247 strPlatform.appendPrintf(" %sSP: %s]", strlen(szTmp) == 0 ? "[" : "| ", szTmp);
248
249 if (!strPlatform.endsWith("]"))
250 strPlatform.append("]");
251
252 LogRelFunc(("strPlatform = %s\n", strPlatform.c_str()));
253 }
254
255 return strPlatform;
256}
257
258HRESULT HostUpdate::i_checkForVBoxUpdate()
259{
260 HRESULT rc;
261
262 // Default to no update required
263 m_updateNeeded = FALSE;
264
265 // Following the sequence of steps in UIUpdateStepVirtualBox::sltStartStep()
266 // Build up our query URL starting with the URL basename
267 Bstr url("https://update.virtualbox.org/query.php/?");
268 Bstr platform;
269 rc = mVirtualBox->COMGETTER(PackageType)(platform.asOutParam());
270 if (FAILED(rc))
271 return setErrorVrc(rc, tr("%s: IVirtualBox::packageType() failed: %Rrc"), __FUNCTION__, rc);
272 url.appendPrintf("platform=%ls", platform.raw()); // e.g. SOLARIS_64BITS_GENERIC
273
274 // Get the complete current version string for the query URL
275 Bstr versionNormalized;
276 rc = mVirtualBox->COMGETTER(VersionNormalized)(versionNormalized.asOutParam());
277 if (FAILED(rc))
278 return setErrorVrc(rc, tr("%s: IVirtualBox::versionNormalized() failed: %Rrc"), __FUNCTION__, rc);
279 url.appendPrintf("&version=%ls", versionNormalized.raw()); // e.g. 6.1.1
280 // url.appendPrintf("&version=6.0.12"); // comment out previous line and uncomment this one for testing
281
282 ULONG revision;
283 rc = mVirtualBox->COMGETTER(Revision)(&revision);
284 if (FAILED(rc))
285 return setErrorVrc(rc, tr("%s: IVirtualBox::revision() failed: %Rrc"), __FUNCTION__, rc);
286 url.appendPrintf("_%ld", revision); // e.g. 135618
287
288 // acquire the System Properties interface
289 ComPtr<ISystemProperties> pSystemProperties;
290 rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
291 if (FAILED(rc))
292 return setErrorVrc(rc, tr("%s: IVirtualBox::systemProperties() failed: %Rrc"), __FUNCTION__, rc);
293
294 // Update the VBoxUpdate setting 'VBoxUpdateLastCheckDate'
295 RTTIME Time;
296 RTTIMESPEC TimeNow;
297 char szTimeStr[RTTIME_STR_LEN];
298
299 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeNow)), szTimeStr, sizeof(szTimeStr));
300 LogRelFunc(("VBox updating UpdateDate with TimeString = %s\n", szTimeStr));
301 rc = pSystemProperties->COMSETTER(VBoxUpdateLastCheckDate)(Bstr(szTimeStr).raw());
302 if (FAILED(rc))
303 return rc; // ISystemProperties::setLastCheckDate calls setError() on failure
304
305 // Update the queryURL and the VBoxUpdate setting 'VBoxUpdateCount'
306 ULONG cVBoxUpdateCount = 0;
307 rc = pSystemProperties->COMGETTER(VBoxUpdateCount)(&cVBoxUpdateCount);
308 if (FAILED(rc))
309 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::VBoxUpdateCount failed: %Rrc"), __FUNCTION__, rc);
310
311 cVBoxUpdateCount++;
312
313 rc = pSystemProperties->COMSETTER(VBoxUpdateCount)(cVBoxUpdateCount);
314 if (FAILED(rc))
315 return rc; // ISystemProperties::setVBoxUpdateCount calls setError() on failure
316 url.appendPrintf("&count=%lu", cVBoxUpdateCount);
317
318 // Update the query URL and the VBoxUpdate settings (if necessary) with the 'Target' information.
319 VBoxUpdateTarget_T enmTarget = VBoxUpdateTarget_Stable; // default branch is 'stable'
320 rc = pSystemProperties->COMGETTER(VBoxUpdateTarget)(&enmTarget);
321 if (FAILED(rc))
322 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::Target failed: %Rrc"), __FUNCTION__, rc);
323
324 switch (enmTarget)
325 {
326 case VBoxUpdateTarget_AllReleases:
327 url.appendPrintf("&branch=allrelease"); // query.php expects 'allrelease' and not 'allreleases'
328 break;
329 case VBoxUpdateTarget_WithBetas:
330 url.appendPrintf("&branch=withbetas");
331 break;
332 case VBoxUpdateTarget_Stable:
333 default:
334 url.appendPrintf("&branch=stable");
335 break;
336 }
337
338 rc = pSystemProperties->COMSETTER(VBoxUpdateTarget)(enmTarget);
339 if (FAILED(rc))
340 return rc; // ISystemProperties::setTarget calls setError() on failure
341
342 LogRelFunc(("VBox update URL = %s\n", Utf8Str(url).c_str()));
343
344 // Setup the User-Agent headers for the GET request
345 Bstr version;
346 rc = mVirtualBox->COMGETTER(Version)(version.asOutParam()); // e.g. 6.1.0_RC1
347 if (FAILED(rc))
348 return setErrorVrc(rc, tr("%s: IVirtualBox::version() failed: %Rrc"), __FUNCTION__, rc);
349
350 Utf8StrFmt const strUserAgent("VirtualBox %ls <%s>", version.raw(), HostUpdate::i_platformInfo().c_str());
351 LogRelFunc(("userAgent = %s\n", strUserAgent.c_str()));
352
353 RTHTTP hHttp = NIL_RTHTTP;
354 int vrc = RTHttpCreate(&hHttp);
355 if (RT_FAILURE(vrc))
356 return setErrorVrc(vrc, tr("%s: RTHttpCreate() failed: %Rrc"), __FUNCTION__, vrc);
357
358 /// @todo Are there any other headers needed to be added first via RTHttpSetHeaders()?
359 vrc = RTHttpAddHeader(hHttp, "User-Agent", strUserAgent.c_str(), strUserAgent.length(), RTHTTPADDHDR_F_BACK);
360 if (RT_FAILURE(vrc))
361 return setErrorVrc(vrc, tr("%s: RTHttpAddHeader() failed: %Rrc (on User-Agent)"), __FUNCTION__, vrc);
362
363 ProxyMode_T enmProxyMode;
364 rc = pSystemProperties->COMGETTER(ProxyMode)(&enmProxyMode);
365 if (FAILED(rc))
366 return setErrorVrc(rc, tr("%s: ISystemProperties::proxyMode() failed: %Rrc"), __FUNCTION__, rc);
367
368 if (enmProxyMode == ProxyMode_Manual)
369 {
370 Bstr strProxyURL;
371
372 rc = pSystemProperties->COMGETTER(ProxyURL)(strProxyURL.asOutParam());
373 if (FAILED(rc))
374 return setErrorVrc(rc, tr("%s: ISystemProperties::proxyURL() failed: %Rrc"), __FUNCTION__, rc);
375 vrc = RTHttpSetProxyByUrl(hHttp, Utf8Str(strProxyURL).c_str());
376 if (RT_FAILURE(vrc))
377 return setErrorVrc(vrc, tr("%s: RTHttpSetProxyByUrl() failed: %Rrc"), __FUNCTION__, vrc);
378 }
379 else if (enmProxyMode == ProxyMode_System)
380 {
381 vrc = RTHttpUseSystemProxySettings(hHttp);
382 if (RT_FAILURE(vrc))
383 return setErrorVrc(vrc, tr("%s: RTHttpUseSystemProxySettings() failed: %Rrc"), __FUNCTION__, vrc);
384 }
385
386 void *pvResponse = 0;
387 size_t cbResponse = 0;
388 vrc = RTHttpGetBinary(hHttp, Utf8Str(url).c_str(), &pvResponse, &cbResponse);
389 if (RT_FAILURE(vrc))
390 return setErrorVrc(vrc, tr("%s: RTHttpGetBinary() failed: %Rrc"), __FUNCTION__, vrc);
391
392 RTCList<RTCString> lstHttpReply = RTCString((char *)pvResponse, (size_t)cbResponse).split(" ", RTCString::RemoveEmptyParts);
393 RTHttpFreeResponse(pvResponse);
394
395 // If url is platform=DARWIN_64BITS_GENERIC&version=6.0.12&branch=stable for example, the reply is:
396 // reply[0] = 6.0.14
397 // reply[1] = https://download.virtualbox.org/virtualbox/6.0.14/VirtualBox-6.0.14-133895-OSX.dmg
398 // If no update required, 'UPTODATE' is returned.
399 if (strcmp(lstHttpReply.at(0).c_str(), "UPTODATE") == 0)
400 {
401 m_updateNeeded = FALSE;
402 }
403 else
404 {
405 /** @todo r=bird: trusting the server reply too much here! */
406 m_updateNeeded = TRUE;
407 m_updateVersion = lstHttpReply.at(0).c_str();
408 m_updateURL = lstHttpReply.at(1).c_str();
409 LogRelFunc(("HTTP server reply = %s %s\n", lstHttpReply.at(0).c_str(), lstHttpReply.at(1).c_str()));
410 }
411
412 // clean-up HTTP request paperwork
413 if (hHttp != NIL_RTHTTP)
414 RTHttpDestroy(hHttp);
415
416 return S_OK;
417}
418
419HRESULT HostUpdate::i_updateCheckTask(UpdateCheckTask *pTask)
420{
421 LogFlowFuncEnter();
422 AutoCaller autoCaller(this);
423 HRESULT hrc = autoCaller.rc();
424 if (SUCCEEDED(hrc))
425 {
426 try
427 {
428 switch (pTask->m_checkType)
429 {
430 case UpdateCheckType_VirtualBox:
431 hrc = i_checkForVBoxUpdate();
432 break;
433#if 0
434 case UpdateCheckType_ExtensionPack:
435 hrc = i_checkForExtPackUpdate();
436 break;
437
438 case UpdateCheckType_GuestAdditions:
439 hrc = i_checkForGuestAdditionsUpdate();
440 break;
441#endif
442 default:
443 hrc = setError(E_FAIL, tr("Update check type %d is not implemented"), pTask->m_checkType);
444 break;
445 }
446 }
447 catch (...)
448 {
449 AssertFailed();
450 hrc = E_UNEXPECTED;
451 }
452 }
453
454 if (!pTask->m_ptrProgress.isNull())
455 pTask->m_ptrProgress->i_notifyComplete(hrc);
456
457 LogFlowFunc(("rc=%Rhrc\n", hrc));
458 LogFlowFuncLeave();
459 return pTask->m_rc = hrc;
460}
461
462////////////////////////////////////////////////////////////////////////////////
463//
464// HostUpdate constructor / destructor
465//
466// ////////////////////////////////////////////////////////////////////////////////
467HostUpdate::HostUpdate()
468 : mVirtualBox(NULL)
469{
470}
471
472HostUpdate::~HostUpdate()
473{
474}
475
476
477HRESULT HostUpdate::FinalConstruct()
478{
479 return BaseFinalConstruct();
480}
481
482void HostUpdate::FinalRelease()
483{
484 uninit();
485
486 BaseFinalRelease();
487}
488
489HRESULT HostUpdate::init(VirtualBox *aVirtualBox)
490{
491 // Enclose the state transition NotReady->InInit->Ready.
492 AutoInitSpan autoInitSpan(this);
493 AssertReturn(autoInitSpan.isOk(), E_FAIL);
494
495 /* Weak reference to a VirtualBox object */
496 unconst(mVirtualBox) = aVirtualBox;
497
498 autoInitSpan.setSucceeded();
499 return S_OK;
500}
501
502void HostUpdate::uninit()
503{
504 // Enclose the state transition Ready->InUninit->NotReady.
505 AutoUninitSpan autoUninitSpan(this);
506 if (autoUninitSpan.uninitDone())
507 return;
508}
509
510HRESULT HostUpdate::updateCheck(UpdateCheckType_T aCheckType,
511 ComPtr<IProgress> &aProgress)
512{
513 /* Validate input */
514 switch (aCheckType)
515 {
516 case UpdateCheckType_VirtualBox:
517 break;
518 case UpdateCheckType_ExtensionPack:
519 return setError(E_NOTIMPL, tr("UpdateCheckType::ExtensionPack is not implemented"));
520 case UpdateCheckType_GuestAdditions:
521 return setError(E_NOTIMPL, tr("UpdateCheckType::GuestAdditions is not implemented"));
522 default:
523 return setError(E_INVALIDARG, tr("Invalid aCheckType value %d"), aCheckType);
524 }
525
526 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
527
528 // Check whether VirtualBox updates have been disabled before spawning the task thread.
529 ComPtr<ISystemProperties> pSystemProperties;
530 HRESULT rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
531 if (FAILED(rc))
532 return setErrorVrc(rc, tr("%s: IVirtualBox::systemProperties() failed: %Rrc"), __FUNCTION__, rc);
533
534 BOOL fVBoxUpdateEnabled = true;
535 rc = pSystemProperties->COMGETTER(VBoxUpdateEnabled)(&fVBoxUpdateEnabled);
536 if (FAILED(rc))
537 return setErrorVrc(rc, tr("%s: retrieving ISystemProperties::VBoxUpdateEnabled failed: %Rrc"), __FUNCTION__, rc);
538
539 /** @todo r=bird: Not sure if this makes sense, it should at least have a
540 * better status code and a proper error message. Also, isn't this really
541 * something the caller should check? Presumably the caller already check
542 * whther this was a good time to perform an update check (i.e. the configured
543 * time has elapsed since last check) ...
544 *
545 * It would make sense to allow performing a one-off update check even if the
546 * automatic update checking is disabled, wouldn't it? */
547 if (!fVBoxUpdateEnabled)
548 return E_NOTIMPL;
549
550 ComObjPtr<Progress> pProgress;
551 rc = pProgress.createObject();
552 if (FAILED(rc))
553 return rc;
554
555 rc = pProgress->init(mVirtualBox,
556 static_cast<IHostUpdate*>(this),
557 tr("Checking for software update..."),
558 TRUE /* aCancelable */);
559 if (FAILED(rc))
560 return rc;
561
562 /* initialize the worker task */
563 UpdateCheckTask *pTask = new UpdateCheckTask(aCheckType, this, pProgress);
564 rc = pTask->createThread();
565 pTask = NULL;
566 if (FAILED(rc))
567 return rc;
568
569 rc = pProgress.queryInterfaceTo(aProgress.asOutParam());
570
571 return rc;
572}
573
574HRESULT HostUpdate::getUpdateVersion(com::Utf8Str &aUpdateVersion)
575{
576 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
577
578 aUpdateVersion = m_updateVersion;
579
580 return S_OK;
581}
582
583HRESULT HostUpdate::getUpdateURL(com::Utf8Str &aUpdateURL)
584{
585 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
586
587 aUpdateURL = m_updateURL;
588
589 return S_OK;
590}
591
592HRESULT HostUpdate::getUpdateResponse(BOOL *aUpdateNeeded)
593{
594 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
595
596 *aUpdateNeeded = m_updateNeeded;
597
598 return S_OK;
599}
600
601HRESULT HostUpdate::getUpdateCheckNeeded(BOOL *aUpdateCheckNeeded)
602{
603 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
604
605 HRESULT rc;
606 ComPtr<ISystemProperties> pSystemProperties;
607 rc = mVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
608 if (FAILED(rc))
609 return rc;
610
611 /*
612 * Is update checking enabled?
613 */
614 BOOL fVBoxUpdateEnabled;
615 rc = pSystemProperties->COMGETTER(VBoxUpdateEnabled)(&fVBoxUpdateEnabled);
616 if (FAILED(rc))
617 return rc;
618
619 if (!fVBoxUpdateEnabled)
620 {
621 *aUpdateCheckNeeded = false;
622 return S_OK;
623 }
624
625 /*
626 * When was the last update?
627 */
628 Bstr strVBoxUpdateLastCheckDate;
629 rc = pSystemProperties->COMGETTER(VBoxUpdateLastCheckDate)(strVBoxUpdateLastCheckDate.asOutParam());
630 if (FAILED(rc))
631 return rc;
632
633 // No prior update check performed so do so now
634 if (strVBoxUpdateLastCheckDate.isEmpty())
635 {
636 *aUpdateCheckNeeded = true;
637 return S_OK;
638 }
639
640 // convert stored timestamp to time spec
641 RTTIMESPEC LastCheckTime;
642 if (!RTTimeSpecFromString(&LastCheckTime, Utf8Str(strVBoxUpdateLastCheckDate).c_str()))
643 {
644 *aUpdateCheckNeeded = true;
645 return S_OK;
646 }
647
648 /*
649 * Compare last update with how often we are supposed to check for updates.
650 */
651 ULONG uVBoxUpdateFrequency = 0; // value in days
652 rc = pSystemProperties->COMGETTER(VBoxUpdateFrequency)(&uVBoxUpdateFrequency);
653 if (FAILED(rc))
654 return rc;
655
656 if (!uVBoxUpdateFrequency)
657 {
658 /* Consider config (enable, 0 day interval) as checking once but never again.
659 We've already check since we've got a date. */
660 *aUpdateCheckNeeded = false;
661 return S_OK;
662 }
663 uint64_t const cSecsInXDays = uVBoxUpdateFrequency * RT_SEC_1DAY_64;
664
665 RTTIMESPEC TimeDiff;
666 RTTimeSpecSub(RTTimeNow(&TimeDiff), &LastCheckTime);
667
668 LogRelFunc(("Checking if seconds since last check (%lld) >= Number of seconds in %lu day%s (%lld)\n",
669 RTTimeSpecGetSeconds(&TimeDiff), uVBoxUpdateFrequency, uVBoxUpdateFrequency > 1 ? "s" : "", cSecsInXDays));
670
671 if (RTTimeSpecGetSeconds(&TimeDiff) >= (int64_t)cSecsInXDays)
672 *aUpdateCheckNeeded = true;
673
674 return S_OK;
675}
676
677/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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