VBoxGuestR3LibHostVersion.cpp revision 5bb7b06e9e2186e1f51700e01cfd58f2b5f70937
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/* $Id: */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/** @file
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, host version check.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/*
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * available from http://www.virtualbox.org. This file is free software;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * you can redistribute it and/or modify it under the terms of the GNU
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * General Public License (GPL) as published by the Free Software
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * additional information or have any questions.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/*******************************************************************************
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync* Header Files *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync*******************************************************************************/
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#include <stdlib.h>
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#include <stdio.h>
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#include <iprt/string.h>
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#include <VBox/log.h>
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#ifdef RT_OS_WINDOWS
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync #define WIN32_LEAN_AND_MEAN
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync #include <windows.h>
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#endif
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#include "VBGLR3Internal.h"
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/** Compares two VirtualBox version strings and returns the result.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * Requires strings in form of "majorVer.minorVer.build"
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * @returns 0 if equal, 1 if Ver1 is greater, 2 if Ver2 is greater.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * @param pszVer1 First version string to compare.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync * @param pszVer2 First version string to compare.
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync *
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsyncVBGLR3DECL(int) VbglR3HostVersionCompare(const char *pszVer1, const char *pszVer2)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync{
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int rc = 0;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int iVer1Major, iVer1Minor, iVer1Build;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync sscanf(pszVer1, "%d.%d.%d", &iVer1Major, &iVer1Minor, &iVer1Build);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int iVer2Major, iVer2Minor, iVer2Build;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync sscanf(pszVer2, "%d.%d.%d", &iVer2Major, &iVer2Minor, &iVer2Build);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int iVer1Final = (iVer1Major * 10000) + (iVer1Minor * 100) + iVer1Build;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int iVer2Final = (iVer2Major * 10000) + (iVer2Minor * 100) + iVer2Build;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (iVer1Final > iVer2Final)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = 1;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else if (iVer2Final > iVer1Final)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = 2;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync return rc;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync}
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/** @todo Docs */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsyncVBGLR3DECL(bool) VbglR3HostVersionCheckForUpdate(char **ppszHostVersion, char **ppszGuestVersion)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync{
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int rc;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync uint32_t uGuestPropSvcClientID;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_SUCCESS(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Property Service Client ID: %ld\n", uGuestPropSvcClientID));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Failed to connect to the guest property service! Error: %d\n", rc));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Do we need to do all this stuff? */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync char *pszCheckHostVersion;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VbglR3GuestPropReadValueAlloc(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/CheckHostVersion", &pszCheckHostVersion);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_FAILURE(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (rc == VERR_NOT_FOUND)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VINF_SUCCESS; /* If we don't find the value above we do the check by default */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not read check host version flag! rc = %d\n", rc));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Only don't do the check if we have a valid "0" in it */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if ( atoi(pszCheckHostVersion) == 0
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync && strlen(pszCheckHostVersion))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VERR_NOT_SUPPORTED;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync VbglR3GuestPropReadValueFree(pszCheckHostVersion);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (rc == VERR_NOT_SUPPORTED)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogRel(("No host version check performed (disabled)."));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_SUCCESS(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Look up host version (revision) */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VbglR3GuestPropReadValueAlloc(uGuestPropSvcClientID, "/VirtualBox/HostInfo/VBoxVer", ppszHostVersion);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_FAILURE(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not read VBox host version! rc = %d\n", rc));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Host version: %s\n", *ppszHostVersion));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Look up guest version */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VbglR3GetAdditionsVersion(ppszGuestVersion, NULL /* Revision */);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_SUCCESS(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Additions version: %s\n", *ppszGuestVersion));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Look up last informed host version */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync char szVBoxHostVerLastChecked[32];
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#ifdef RT_OS_WINDOWS
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync HKEY hKey;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Sun\\VirtualBox Guest Additions", 0, KEY_READ, &hKey);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (lRet == ERROR_SUCCESS)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync DWORD dwType;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync DWORD dwSize = sizeof(szVBoxHostVerLastChecked);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync lRet = RegQueryValueEx(hKey, "HostVerLastChecked", NULL, &dwType, (BYTE*)szVBoxHostVerLastChecked, &dwSize);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not read HostVerLastChecked! Error = %ld\n", lRet));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync RegCloseKey(hKey);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else if (lRet != ERROR_FILE_NOT_FOUND)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not open registry key! Error = %ld\n", lRet));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = RTErrConvertFromWin32(lRet);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#endif
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync /* Compare both versions and prepare message */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if ( RT_SUCCESS(rc)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync && strcmp(*ppszHostVersion, szVBoxHostVerLastChecked) != 0 /* Make sure we did not process this host version already */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync && VbglR3HostVersionCompare(*ppszHostVersion, *ppszGuestVersion) == 1) /* Is host version greater than guest add version? */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Update found."));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else rc = VERR_VERSION_MISMATCH; /* No update found */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_FAILURE(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (*ppszHostVersion)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync VbglR3GuestPropReadValueFree(*ppszHostVersion);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (*ppszGuestVersion)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync VbglR3GuestPropReadValueFree(*ppszGuestVersion);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync return rc == VINF_SUCCESS ? true : false;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync}
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync/** @todo Docs */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsyncVBGLR3DECL(int) VbglR3HostVersionStore(const char* pszVer)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync{
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync int rc;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync uint32_t uGuestPropSvcClientID;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (RT_FAILURE(rc))
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Failed to connect to the guest property service! Error: %d\n", rc));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#ifdef RT_OS_WINDOWS
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync HKEY hKey;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync long lRet;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync lRet = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync "SOFTWARE\\Sun\\VirtualBox Guest Additions",
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync 0, /* Reserved */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync NULL, /* lpClass [in, optional] */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync 0, /* dwOptions [in] */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync KEY_WRITE,
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync NULL, /* lpSecurityAttributes [in, optional] */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync &hKey,
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync NULL); /* lpdwDisposition [out, optional] */
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (lRet == ERROR_SUCCESS)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync {
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync lRet = RegSetValueEx(hKey, "HostVerLastChecked", 0, REG_SZ, (BYTE*)pszVer, (DWORD)(strlen(pszVer)*sizeof(char)));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (lRet != ERROR_SUCCESS)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not write HostVerLastChecked! Error = %ld\n", lRet));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync RegCloseKey(hKey);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync LogFlow(("Could not open registry key! Error = %ld\n", lRet));
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync if (lRet != ERROR_SUCCESS)
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync rc = RTErrConvertFromWin32(lRet);
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#else
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync#endif
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync }
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync return rc;
5bb7b06e9e2186e1f51700e01cfd58f2b5f70937vboxsync}