summaryrefslogtreecommitdiff
path: root/src/VBox/Additions/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/common')
-rw-r--r--src/VBox/Additions/common/Makefile.kmk8
-rw-r--r--src/VBox/Additions/common/VBoxControl/Makefile.kmk1
-rw-r--r--src/VBox/Additions/common/VBoxControl/VBoxControl.cpp392
-rw-r--r--src/VBox/Additions/common/VBoxControl/testcase/tstVBoxControl.cpp10
-rw-r--r--src/VBox/Additions/common/VBoxGuest/Makefile.kmk46
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxDev-haiku.c446
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-darwin.cpp1085
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-freebsd.c2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c448
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.c553
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.h226
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c16
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp4
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.def2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.conf2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-legacy.cpp202
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp252
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp902
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h115
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp343
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm4
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuestIDC-unix.c.h19
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h34
-rw-r--r--src/VBox/Additions/common/VBoxGuest/darwin/Info.plist50
-rw-r--r--src/VBox/Additions/common/VBoxGuest/freebsd/Makefile2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/linux/Makefile4
-rwxr-xr-xsrc/VBox/Additions/common/VBoxGuest/linux/files_vboxguest2
-rw-r--r--src/VBox/Additions/common/VBoxGuest/win/VBoxGuest.inf7
-rw-r--r--src/VBox/Additions/common/VBoxGuest/win/VBoxGuestInst.cpp83
-rw-r--r--src/VBox/Additions/common/VBoxGuest/win/VBoxGuestMsg.mc60
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/GenericRequest.cpp20
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/HGCM.cpp4
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp9
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/Init.cpp8
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk3
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/PhysHeap.cpp16
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp12
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/SysHlp.h4
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBGLInternal.h19
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBGLR3Internal.h2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestLog.h2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibCrOgl.cpp15
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c119
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h8
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3Lib.cpp79
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibClipboard.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibCredentials.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp12
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGR.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp1183
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp28
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestUser.cpp114
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostChannel.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostVersion.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMouse.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSeamless.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSharedFolders.cpp7
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibTime.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibVideo.cpp66
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VMMDev.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxGuestLib/VbglR0CanUsePhysPageList.cpp7
-rw-r--r--src/VBox/Additions/common/VBoxService/Makefile.kmk21
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxService-os2.def2
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxService-win.cpp33
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxService.cpp64
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp36
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp4
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp1144
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControl.h325
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp2141
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp2364
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp1794
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp37
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h272
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp27
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp66
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServicePropCache.h2
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceResource-win.h2
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp71
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp4
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp10
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp74
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceUtils.h3
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp666
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp733
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.h31
-rw-r--r--src/VBox/Additions/common/VBoxService/testcase/tstUserInfo.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp2
-rw-r--r--src/VBox/Additions/common/VBoxVideo/VBVABase.cpp4
-rwxr-xr-xsrc/VBox/Additions/common/crOpenGL/Linux_i386_glxapi_exports.py2
-rw-r--r--src/VBox/Additions/common/crOpenGL/Makefile.kmk105
-rwxr-xr-xsrc/VBox/Additions/common/crOpenGL/SunOS_i386_exports.py2
-rwxr-xr-xsrc/VBox/Additions/common/crOpenGL/SunOS_i386_exports_dri.py2
-rwxr-xr-xsrc/VBox/Additions/common/crOpenGL/SunOS_i386_glxapi_exports.py2
-rw-r--r--src/VBox/Additions/common/crOpenGL/VBoxICDList.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/context.c107
-rw-r--r--src/VBox/Additions/common/crOpenGL/defs.py13
-rw-r--r--src/VBox/Additions/common/crOpenGL/defs64.py10
-rw-r--r--src/VBox/Additions/common/crOpenGL/dri_drv.c2
-rw-r--r--src/VBox/Additions/common/crOpenGL/dri_drv.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/dri_glx.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/fakedri_drv.c110
-rw-r--r--src/VBox/Additions/common/crOpenGL/fakedri_drv.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/fakedri_glfuncsList.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/fakedri_glxfuncsList.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/feedback/feedback_context.c2
-rw-r--r--src/VBox/Additions/common/crOpenGL/glx.c116
-rw-r--r--src/VBox/Additions/common/crOpenGL/glx_c_exports.c2
-rw-r--r--src/VBox/Additions/common/crOpenGL/glx_proto.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/icd_drv.c2
-rw-r--r--src/VBox/Additions/common/crOpenGL/icd_drv.h2
-rw-r--r--src/VBox/Additions/common/crOpenGL/load.c508
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu.h13
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_bufferobject.c28
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_context.c70
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_framebuffer.c50
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_get.py8
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_getshaders.c10
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_glsl.c55
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_init.c9
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_misc.c17
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_special11
-rw-r--r--src/VBox/Additions/common/crOpenGL/pack/packspu_texture.c31
-rw-r--r--src/VBox/Additions/common/crOpenGL/stub.c7
-rw-r--r--src/VBox/Additions/common/crOpenGL/stub.h8
-rw-r--r--src/VBox/Additions/common/crOpenGL/wgl.c173
-rw-r--r--src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py24
-rw-r--r--src/VBox/Additions/common/pam/pam_vbox.cpp2
-rw-r--r--src/VBox/Additions/common/testcase/tstPageFusion.cpp2
131 files changed, 13297 insertions, 5235 deletions
diff --git a/src/VBox/Additions/common/Makefile.kmk b/src/VBox/Additions/common/Makefile.kmk
index b5852b0d..a14519e4 100644
--- a/src/VBox/Additions/common/Makefile.kmk
+++ b/src/VBox/Additions/common/Makefile.kmk
@@ -22,12 +22,8 @@ include $(KBUILD_PATH)/subheader.kmk
ifndef VBOX_ONLY_TESTSUITE
include $(PATH_SUB_CURRENT)/VBoxGuestLib/Makefile.kmk
include $(PATH_SUB_CURRENT)/VBoxControl/Makefile.kmk
- if1of ($(KBUILD_TARGET), freebsd linux os2 solaris win)
- include $(PATH_SUB_CURRENT)/VBoxGuest/Makefile.kmk
- endif
- if1of ($(KBUILD_TARGET), freebsd linux os2 solaris win)
- include $(PATH_SUB_CURRENT)/VBoxService/Makefile.kmk
- endif
+ include $(PATH_SUB_CURRENT)/VBoxGuest/Makefile.kmk
+ include $(PATH_SUB_CURRENT)/VBoxService/Makefile.kmk
ifdef VBOX_WITH_CROGL
include $(PATH_SUB_CURRENT)/crOpenGL/Makefile.kmk
endif
diff --git a/src/VBox/Additions/common/VBoxControl/Makefile.kmk b/src/VBox/Additions/common/VBoxControl/Makefile.kmk
index b42f928e..e2de0e20 100644
--- a/src/VBox/Additions/common/VBoxControl/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxControl/Makefile.kmk
@@ -42,6 +42,7 @@ VBoxControl_SOURCES = \
VBoxControl.cpp
VBoxControl_SOURCES.win = \
VBoxControl.rc
+VBoxControl_LDFLAGS.darwin = -framework IOKit
include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp b/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp
index afa7b69c..13242a09 100644
--- a/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp
+++ b/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,6 +36,11 @@
#ifdef VBOX_WITH_GUEST_PROPS
# include <VBox/HostServices/GuestPropertySvc.h>
#endif
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+# include <VBox/VBoxGuest.h>
+# include "../VBoxGuestLib/VBGLR3Internal.h" /* HACK ALERT! Using vbglR3DoIOCtl directly!! */
+#endif
+
/*******************************************************************************
* Global Variables *
@@ -70,6 +75,7 @@ enum VBoxControlUsage
#ifdef RT_OS_WINDOWS
GET_VIDEO_ACCEL,
SET_VIDEO_ACCEL,
+ VIDEO_FLAGS,
LIST_CUST_MODES,
ADD_CUST_MODE,
REMOVE_CUST_MODE,
@@ -100,27 +106,30 @@ static void usage(enum VBoxControlUsage eWhich = USAGE_ALL)
doUsage("suppress the logo", g_pszProgName, "--nologo ...");
RTPrintf("\n");
-/* Exclude the Windows bits from the test version. Anyone who needs to test
- * them can fix this. */
+ /* Exclude the Windows bits from the test version. Anyone who needs to
+ test them can fix this. */
#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
- if (GET_VIDEO_ACCEL == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == GET_VIDEO_ACCEL || eWhich == USAGE_ALL)
doUsage("", g_pszProgName, "getvideoacceleration");
- if (SET_VIDEO_ACCEL == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == SET_VIDEO_ACCEL || eWhich == USAGE_ALL)
doUsage("<on|off>", g_pszProgName, "setvideoacceleration");
- if (LIST_CUST_MODES == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == VIDEO_FLAGS || eWhich == USAGE_ALL)
+ doUsage("<get|set|clear|delete> [hex mask]", g_pszProgName, "videoflags");
+ if (eWhich == LIST_CUST_MODES || eWhich == USAGE_ALL)
doUsage("", g_pszProgName, "listcustommodes");
- if (ADD_CUST_MODE == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == ADD_CUST_MODE || eWhich == USAGE_ALL)
doUsage("<width> <height> <bpp>", g_pszProgName, "addcustommode");
- if (REMOVE_CUST_MODE == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == REMOVE_CUST_MODE || eWhich == USAGE_ALL)
doUsage("<width> <height> <bpp>", g_pszProgName, "removecustommode");
- if (SET_VIDEO_MODE == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == SET_VIDEO_MODE || eWhich == USAGE_ALL)
doUsage("<width> <height> <bpp> <screen>", g_pszProgName, "setvideomode");
#endif
#ifdef VBOX_WITH_GUEST_PROPS
- if (GUEST_PROP == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == GUEST_PROP || eWhich == USAGE_ALL)
{
doUsage("get <property> [--verbose]", g_pszProgName, "guestproperty");
doUsage("set <property> [<value> [--flags <flags>]]", g_pszProgName, "guestproperty");
+ doUsage("delete|unset <property>", g_pszProgName, "guestproperty");
doUsage("enumerate [--patterns <patterns>]", g_pszProgName, "guestproperty");
doUsage("wait <patterns>", g_pszProgName, "guestproperty");
doUsage("[--timestamp <last timestamp>]");
@@ -128,7 +137,7 @@ static void usage(enum VBoxControlUsage eWhich = USAGE_ALL)
}
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
- if (GUEST_SHAREDFOLDERS == eWhich || eWhich == USAGE_ALL)
+ if (eWhich == GUEST_SHAREDFOLDERS || eWhich == USAGE_ALL)
{
doUsage("list [-automount]", g_pszProgName, "sharedfolder");
}
@@ -575,7 +584,7 @@ static RTEXITCODE handleSetVideoMode(int argc, char *argv[])
scr = atoi(argv[3]);
}
- HMODULE hUser = GetModuleHandle("USER32");
+ HMODULE hUser = GetModuleHandle("user32.dll");
if (hUser)
{
@@ -603,38 +612,120 @@ static RTEXITCODE handleSetVideoMode(int argc, char *argv[])
return RTEXITCODE_SUCCESS;
}
-HKEY getVideoKey(bool writable)
+static int checkVBoxVideoKey(HKEY hkeyVideo)
{
- HKEY hkeyDeviceMap = 0;
- HKEY hkeyVideo = 0;
- LONG status;
+ char szValue[128];
+ DWORD len = sizeof(szValue);
+ DWORD dwKeyType;
+ LONG status = RegQueryValueExA(hkeyVideo, "Device Description", NULL, &dwKeyType,
+ (LPBYTE)szValue, &len);
- status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
- if ((status != ERROR_SUCCESS) || !hkeyDeviceMap)
+ if (status == ERROR_SUCCESS)
+ {
+ /* WDDM has additional chars after "Adapter" */
+ static char sszDeviceDescription[] = "VirtualBox Graphics Adapter";
+ if (_strnicmp(szValue, sszDeviceDescription, sizeof(sszDeviceDescription) - sizeof(char)) == 0)
+ {
+ return VINF_SUCCESS;
+ }
+ }
+
+ return VERR_NOT_FOUND;
+}
+
+static HKEY getVideoKey(bool writable)
+{
+ HKEY hkeyDeviceMap = 0;
+ LONG status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
+ if (status != ERROR_SUCCESS || !hkeyDeviceMap)
{
VBoxControlError("Error opening video device map registry key!\n");
return 0;
}
- char szVideoLocation[256];
+
+ HKEY hkeyVideo = 0;
+ ULONG iDevice;
DWORD dwKeyType;
- szVideoLocation[0] = 0;
- DWORD len = sizeof(szVideoLocation);
- status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len);
+
/*
- * This value will start with a weird value: \REGISTRY\Machine
- * Make sure this is true.
+ * Scan all '\Device\VideoX' REG_SZ keys to find VBox video driver entry.
+ * 'ObjectNumberList' REG_BINARY is an array of 32 bit device indexes (X).
*/
- if ( (status == ERROR_SUCCESS)
- && (dwKeyType == REG_SZ)
- && (_strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0))
+
+ /* Get the 'ObjectNumberList' */
+ ULONG numDevices = 0;
+ DWORD adwObjectNumberList[256];
+ DWORD len = sizeof(adwObjectNumberList);
+ status = RegQueryValueExA(hkeyDeviceMap, "ObjectNumberList", NULL, &dwKeyType, (LPBYTE)&adwObjectNumberList[0], &len);
+
+ if ( status == ERROR_SUCCESS
+ && dwKeyType == REG_BINARY)
{
- /* open that branch */
- status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
+ numDevices = len / sizeof(DWORD);
}
else
{
- VBoxControlError("Error opening registry key '%s'\n", &szVideoLocation[18]);
+ /* The list might not exists. Use 'MaxObjectNumber' REG_DWORD and build a list. */
+ DWORD dwMaxObjectNumber = 0;
+ len = sizeof(dwMaxObjectNumber);
+ status = RegQueryValueExA(hkeyDeviceMap, "MaxObjectNumber", NULL, &dwKeyType, (LPBYTE)&dwMaxObjectNumber, &len);
+
+ if ( status == ERROR_SUCCESS
+ && dwKeyType == REG_DWORD)
+ {
+ /* 'MaxObjectNumber' is inclusive. */
+ numDevices = RT_MIN(dwMaxObjectNumber + 1, RT_ELEMENTS(adwObjectNumberList));
+ for (iDevice = 0; iDevice < numDevices; iDevice++)
+ {
+ adwObjectNumberList[iDevice] = iDevice;
+ }
+ }
}
+
+ if (numDevices == 0)
+ {
+ /* Always try '\Device\Video0' as the old code did. Enum can be used in this case in principle. */
+ adwObjectNumberList[0] = 0;
+ numDevices = 1;
+ }
+
+ /* Scan device entries */
+ for (iDevice = 0; iDevice < numDevices; iDevice++)
+ {
+ char szValueName[64];
+ RTStrPrintf(szValueName, sizeof(szValueName), "\\Device\\Video%u", adwObjectNumberList[iDevice]);
+
+ char szVideoLocation[256];
+ len = sizeof(szVideoLocation);
+ status = RegQueryValueExA(hkeyDeviceMap, szValueName, NULL, &dwKeyType, (LPBYTE)&szVideoLocation[0], &len);
+
+ /* This value starts with '\REGISTRY\Machine' */
+ if ( status == ERROR_SUCCESS
+ && dwKeyType == REG_SZ
+ && _strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0)
+ {
+ status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0,
+ KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
+ if (status == ERROR_SUCCESS)
+ {
+ int rc = checkVBoxVideoKey(hkeyVideo);
+ if (RT_SUCCESS(rc))
+ {
+ /* Found, return hkeyVideo to the caller. */
+ break;
+ }
+
+ RegCloseKey(hkeyVideo);
+ hkeyVideo = 0;
+ }
+ }
+ }
+
+ if (hkeyVideo == 0)
+ {
+ VBoxControlError("Error opening video registry key!\n");
+ }
+
RegCloseKey(hkeyDeviceMap);
return hkeyVideo;
}
@@ -692,6 +783,135 @@ static RTEXITCODE handleSetVideoAcceleration(int argc, char *argv[])
return RTEXITCODE_SUCCESS;
}
+static RTEXITCODE videoFlagsGet(void)
+{
+ HKEY hkeyVideo = getVideoKey(false);
+
+ if (hkeyVideo)
+ {
+ DWORD dwFlags = 0;
+ DWORD len = sizeof(dwFlags);
+ DWORD dwKeyType;
+ ULONG status = RegQueryValueExA(hkeyVideo, "VBoxVideoFlags", NULL, &dwKeyType, (LPBYTE)&dwFlags, &len);
+ if (status != ERROR_SUCCESS)
+ RTPrintf("Video flags: default\n");
+ else
+ RTPrintf("Video flags: 0x%08X\n", dwFlags);
+ RegCloseKey(hkeyVideo);
+ return RTEXITCODE_SUCCESS;
+ }
+
+ return RTEXITCODE_FAILURE;
+}
+
+static RTEXITCODE videoFlagsDelete(void)
+{
+ HKEY hkeyVideo = getVideoKey(true);
+
+ if (hkeyVideo)
+ {
+ ULONG status = RegDeleteValueA(hkeyVideo, "VBoxVideoFlags");
+ if (status != ERROR_SUCCESS)
+ VBoxControlError("Error %d deleting video flags.\n", status);
+ RegCloseKey(hkeyVideo);
+ return RTEXITCODE_SUCCESS;
+ }
+
+ return RTEXITCODE_FAILURE;
+}
+
+static RTEXITCODE videoFlagsModify(bool fSet, int argc, char *argv[])
+{
+ if (argc != 1)
+ {
+ VBoxControlError("Mask required.\n");
+ return RTEXITCODE_FAILURE;
+ }
+
+ uint32_t u32Mask = 0;
+ int rc = RTStrToUInt32Full(argv[0], 16, &u32Mask);
+ if (RT_FAILURE(rc))
+ {
+ VBoxControlError("Invalid video flags mask.\n");
+ return RTEXITCODE_FAILURE;
+ }
+
+ RTEXITCODE exitCode = RTEXITCODE_SUCCESS;
+
+ HKEY hkeyVideo = getVideoKey(true);
+ if (hkeyVideo)
+ {
+ DWORD dwFlags = 0;
+ DWORD len = sizeof(dwFlags);
+ DWORD dwKeyType;
+ ULONG status = RegQueryValueExA(hkeyVideo, "VBoxVideoFlags", NULL, &dwKeyType, (LPBYTE)&dwFlags, &len);
+ if (status != ERROR_SUCCESS)
+ {
+ dwFlags = 0;
+ }
+
+ dwFlags = fSet? (dwFlags | u32Mask):
+ (dwFlags & ~u32Mask);
+
+ status = RegSetValueExA(hkeyVideo, "VBoxVideoFlags", 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
+ if (status != ERROR_SUCCESS)
+ {
+ VBoxControlError("Error %d writing video flags.\n", status);
+ exitCode = RTEXITCODE_FAILURE;
+ }
+
+ RegCloseKey(hkeyVideo);
+ }
+ else
+ {
+ exitCode = RTEXITCODE_FAILURE;
+ }
+
+ return exitCode;
+}
+
+static RTEXITCODE handleVideoFlags(int argc, char *argv[])
+{
+ /* Must have a keyword and optional value (32 bit hex string). */
+ if (argc != 1 && argc != 2)
+ {
+ VBoxControlError("Invalid number of arguments.\n");
+ usage(VIDEO_FLAGS);
+ return RTEXITCODE_FAILURE;
+ }
+
+ RTEXITCODE exitCode = RTEXITCODE_SUCCESS;
+
+ if (RTStrICmp(argv[0], "get") == 0)
+ {
+ exitCode = videoFlagsGet();
+ }
+ else if (RTStrICmp(argv[0], "delete") == 0)
+ {
+ exitCode = videoFlagsDelete();
+ }
+ else if (RTStrICmp(argv[0], "set") == 0)
+ {
+ exitCode = videoFlagsModify(true, argc - 1, &argv[1]);
+ }
+ else if (RTStrICmp(argv[0], "clear") == 0)
+ {
+ exitCode = videoFlagsModify(false, argc - 1, &argv[1]);
+ }
+ else
+ {
+ VBoxControlError("Invalid command.\n");
+ exitCode = RTEXITCODE_FAILURE;
+ }
+
+ if (exitCode != RTEXITCODE_SUCCESS)
+ {
+ usage(VIDEO_FLAGS);
+ }
+
+ return exitCode;
+}
+
#define MAX_CUSTOM_MODES 128
/* the table of custom modes */
@@ -1092,6 +1312,51 @@ static RTEXITCODE setGuestProperty(int argc, char *argv[])
/**
+ * Deletes a guest property from the guest property store.
+ * This is accessed through the "VBoxGuestPropSvc" HGCM service.
+ *
+ * @returns Command exit code.
+ * @note see the command line API description for parameters
+ */
+static RTEXITCODE deleteGuestProperty(int argc, char *argv[])
+{
+ /*
+ * Check the syntax. We can deduce the correct syntax from the number of
+ * arguments.
+ */
+ bool usageOK = true;
+ const char *pszName = NULL;
+ if (argc < 1)
+ usageOK = false;
+ if (!usageOK)
+ {
+ usage(GUEST_PROP);
+ return RTEXITCODE_FAILURE;
+ }
+ /* This is always needed. */
+ pszName = argv[0];
+
+ /*
+ * Do the actual setting.
+ */
+ uint32_t u32ClientId = 0;
+ int rc = VbglR3GuestPropConnect(&u32ClientId);
+ if (!RT_SUCCESS(rc))
+ VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3GuestPropDelete(u32ClientId, pszName);
+ if (!RT_SUCCESS(rc))
+ VBoxControlError("Failed to delete the property value, error %Rrc\n", rc);
+ }
+
+ if (u32ClientId != 0)
+ VbglR3GuestPropDisconnect(u32ClientId);
+ return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+
+/**
* Enumerates the properties in the guest property store.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
@@ -1311,6 +1576,8 @@ static RTEXITCODE handleGuestProperty(int argc, char *argv[])
return getGuestProperty(argc - 1, argv + 1);
else if (!strcmp(argv[0], "set"))
return setGuestProperty(argc - 1, argv + 1);
+ else if (!strcmp(argv[0], "delete") || !strcmp(argv[0], "unset"))
+ return deleteGuestProperty(argc - 1, argv + 1);
else if (!strcmp(argv[0], "enumerate"))
return enumGuestProperty(argc - 1, argv + 1);
else if (!strcmp(argv[0], "wait"))
@@ -1429,6 +1696,32 @@ static RTEXITCODE handleWriteCoreDump(int argc, char *argv[])
}
#endif
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+/**
+ * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: help}
+ */
+static RTEXITCODE handleDpc(int argc, char *argv[])
+{
+# ifndef VBOX_CONTROL_TEST
+ int rc;
+ for (int i = 0; i < 30; i++)
+ {
+ rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER, NULL, 0);
+ if (RT_FAILURE(rc))
+ break;
+ RTPrintf("%d\n", i);
+ }
+# else
+ int rc = VERR_NOT_IMPLEMENTED;
+# endif
+ if (RT_FAILURE(rc))
+ return VBoxControlError("Error. rc=%Rrc\n", rc);
+ RTPrintf("Samples collection completed.\n");
+ return RTEXITCODE_SUCCESS;
+}
+#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
+
+
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: takesnapshot}
*/
@@ -1486,38 +1779,6 @@ static RTEXITCODE handleHelp(int argc, char *argv[])
return RTEXITCODE_SUCCESS;
}
-#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
-#include "..\VBoxGuestLib\VBGLR3Internal.h"
-
-static RTEXITCODE handleDpc(int argc, char *argv[])
-{
-#ifndef VBOX_CONTROL_TEST
- int rc = VINF_SUCCESS;
- int i;
- for (i = 0; i < 30; i++)
- {
- rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_DPC, NULL, 0);
- if (RT_FAILURE(rc))
- {
- break;
- }
- RTPrintf("%d\n", i);
- }
-#else
- int rc = VERR_NOT_IMPLEMENTED;
-#endif
- if (RT_SUCCESS(rc))
- {
- RTPrintf("Samples collection completed.\n");
- return RTEXITCODE_SUCCESS;
- }
- else
- {
- VBoxControlError("Error. rc=%Rrc\n", rc);
- return RTEXITCODE_FAILURE;
- }
-}
-#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
/** command handler type */
typedef DECLCALLBACK(RTEXITCODE) FNVBOXCTRLCMDHANDLER(int argc, char *argv[]);
@@ -1533,6 +1794,7 @@ struct COMMANDHANDLER
#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
{ "getvideoacceleration", handleGetVideoAcceleration },
{ "setvideoacceleration", handleSetVideoAcceleration },
+ { "videoflags", handleVideoFlags },
{ "listcustommodes", handleListCustomModes },
{ "addcustommode", handleAddCustomMode },
{ "removecustommode", handleRemoveCustomMode },
@@ -1547,6 +1809,9 @@ struct COMMANDHANDLER
#if !defined(VBOX_CONTROL_TEST)
{ "writecoredump", handleWriteCoreDump },
#endif
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+ { "dpc", handleDpc },
+#endif
{ "takesnapshot", handleTakeSnapshot },
{ "savestate", handleSaveState },
{ "suspend", handleSuspend },
@@ -1555,9 +1820,6 @@ struct COMMANDHANDLER
{ "powerdown", handlePowerOff },
{ "getversion", handleVersion },
{ "version", handleVersion },
-#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
- { "dpc", handleDpc },
-#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
{ "help", handleHelp }
};
diff --git a/src/VBox/Additions/common/VBoxControl/testcase/tstVBoxControl.cpp b/src/VBox/Additions/common/VBoxControl/testcase/tstVBoxControl.cpp
index 7536162b..11185a74 100644
--- a/src/VBox/Additions/common/VBoxControl/testcase/tstVBoxControl.cpp
+++ b/src/VBox/Additions/common/VBoxControl/testcase/tstVBoxControl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -97,6 +97,14 @@ VBGLR3DECL(int) VbglR3GuestPropRead(uint32_t u32ClientId,
return VINF_SUCCESS;
}
+VBGLR3DECL(int) VbglR3GuestPropDelete(uint32_t u32ClientId,
+ const char *pszName)
+{
+ RTPrintf("Called DEL_PROP, client %d, name %s...\n",
+ u32ClientId, pszName);
+ return VINF_SUCCESS;
+}
+
struct VBGLR3GUESTPROPENUM
{
uint32_t u32;
diff --git a/src/VBox/Additions/common/VBoxGuest/Makefile.kmk b/src/VBox/Additions/common/VBoxGuest/Makefile.kmk
index 8ff81a91..ecaa22c4 100644
--- a/src/VBox/Additions/common/VBoxGuest/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxGuest/Makefile.kmk
@@ -19,22 +19,26 @@ SUB_DEPTH = ../../../../..
include $(KBUILD_PATH)/subheader.kmk
-if1of ($(KBUILD_TARGET), freebsd $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linux,) os2 solaris win)
+if1of ($(KBUILD_TARGET), darwin freebsd haiku $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linux,) os2 solaris win)
#
# VBoxGuest - The Guest Additions Driver.
#
SYSMODS += VBoxGuest
VBoxGuest_TEMPLATE = VBOXGUESTR0
VBoxGuest_NAME.freebsd = vboxguest
+ VBoxGuest_NAME.haiku = vboxguest
VBoxGuest_NAME.linux = vboxguest
VBoxGuest_NAME.solaris = vboxguest
+ VBoxGuest_INST.darwin = $(INST_ADDITIONS)VBoxGuest.kext/Contents/MacOS/
ifdef VBOX_SIGN_ADDITIONS # See Additions/WINNT/Makefile.kmk?
VBoxGuest_INSTTYPE.win = none
VBoxGuest_DEBUG_INSTTYPE.win = both
endif
+ VBoxGuest_DEFS.haiku = VBOX_SVN_REV=$(VBOX_SVN_REV) _KERNEL_MODE=1
VBoxGuest_DEFS.linux = KBUILD_MODNAME=KBUILD_STR\(vboxguest\) KBUILD_BASENAME=KBUILD_STR\(vboxguest\) DEBUG_HASH=2 DEBUG_HASH2=3 EXPORT_SYMTAB
VBoxGuest_DEFS.solaris = VBOX_SVN_REV=$(VBOX_SVN_REV)
VBoxGuest_DEFS.win = # VBOX_WITH_VRDP_SESSION_HANDLING
+ VBoxGuest_DEFS.darwin = VBOX_GUESTDRV_WITH_RELEASE_LOGGER
ifeq ($(KBUILD_TYPE),release)
# Allow stopping/removing the driver without a reboot
# in debug mode; this is very useful for testing the shutdown stuff!
@@ -48,7 +52,9 @@ if1of ($(KBUILD_TARGET), freebsd $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linu
$(if $(VBOX_WITH_DPC_LATENCY_CHECKER),VBOX_WITH_DPC_LATENCY_CHECKER,)
VBoxGuest_DEPS.solaris += $(VBOX_SVN_REV_KMK)
VBoxGuest_DEPS.linux += $(VBOX_SVN_REV_HEADER)
+ VBoxGuest_DEPS.haiku += $(VBOX_SVN_REV_HEADER)
VBoxGuest_DEPS.freebsd += $(VBOX_SVN_REV_HEADER)
+ VBoxGuest_DEPS.darwin += $(VBOX_SVN_REV_HEADER)
VBoxGuest_DEFS = VBGL_VBOXGUEST VBOX_WITH_HGCM
VBoxGuest_INCS = .
VBoxGuest_INCS.freebsd = $(VBoxGuest_0_OUTDIR) $(PATH_STAGE)/gen-sys-hdrs
@@ -74,7 +80,7 @@ if1of ($(KBUILD_TARGET), freebsd $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linu
VBoxGuest.cpp_SDKS = $(VBOX_WINDDK_GST_WLH)
endif
endif # win
- ifn1of ($(KBUILD_TARGET), linux freebsd solaris)
+ ifn1of ($(KBUILD_TARGET), linux freebsd solaris haiku)
VBoxGuest_SOURCES = VBoxGuest-$(KBUILD_TARGET).cpp
else
VBoxGuest_SOURCES = VBoxGuest-$(KBUILD_TARGET).c
@@ -94,6 +100,16 @@ if1of ($(KBUILD_TARGET), freebsd $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linu
$(PATH_STAGE)/gen-sys-hdrs/pci_if.h \
$(PATH_STAGE)/gen-sys-hdrs/bus_if.h \
$(PATH_STAGE)/gen-sys-hdrs/device_if.h
+ ifeq ($(KBUILD_TARGET),haiku)
+ # Haiku drivers cannot export symbols for other drivers, but modules can.
+ # Therefore vboxguest is a module containing the ring-0 guest lib, and vboxdev/vboxsf
+ # use this module to access the guest lib
+ SYSMODS += VBoxDev
+ VBoxDev_TEMPLATE = VBOXGUESTR0
+ VBoxDev_NAME = vboxdev
+ VBoxDev_DEFS = VBOX_SVN_REV=$(VBOX_SVN_REV) _KERNEL_MODE=1 VBGL_VBOXGUEST VBOX_WITH_HGCM IN_RING0
+ VBoxDev_SOURCES = VBoxDev-haiku.c VBoxGuest-haiku-stubs.c
+ endif
else # OS/2:
# The library order is crucial, so a bit of trickery is necessary.
# A library is used to make sure that VBoxGuestA-os2.asm is first in the link. (temporary hack?)
@@ -151,6 +167,32 @@ if1of ($(KBUILD_TARGET), freebsd $(if $(defined VBOX_WITH_ADDITION_DRIVERS),linu
endif # win
endif # enabled
+
+ifeq ($(KBUILD_TARGET), darwin)
+ # Files necessary to make a darwin kernel extension bundle.
+ INSTALLS += VBoxGuest.kext
+ VBoxGuest.kext_INST = $(INST_ADDITIONS)/VBoxGuest.kext/Contents/
+ VBoxGuest.kext_SOURCES = $(VBoxGuest.kext_0_OUTDIR)/Info.plist
+ VBoxGuest.kext_CLEAN = $(VBoxGuest.kext_0_OUTDIR)/Info.plist
+
+$$(VBoxGuest.kext_0_OUTDIR)/Info.plist: \
+ $(PATH_SUB_CURRENT)/darwin/Info.plist \
+ $(VBOX_VERSION_MK) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxGuest,$@,$<)
+ $(QUIET)$(RM) -f $@
+ $(QUIET)$(SED) \
+ -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/g' \
+ -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/g' \
+ -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/g' \
+ -e 's/@VBOX_VERSION_BUILD@/$(VBOX_VERSION_BUILD)/g' \
+ -e 's/@VBOX_VENDOR@/$(VBOX_VENDOR)/g' \
+ -e 's/@VBOX_PRODUCT@/$(VBOX_PRODUCT)/g' \
+ -e 's/@VBOX_C_YEAR@/$(VBOX_C_YEAR)/g' \
+ --output $@ \
+ $<
+endif # darwin
+
+
ifeq ($(KBUILD_TARGET),linux)
#
# Install the source files and script(s).
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxDev-haiku.c b/src/VBox/Additions/common/VBoxGuest/VBoxDev-haiku.c
new file mode 100644
index 00000000..82163323
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxDev-haiku.c
@@ -0,0 +1,446 @@
+/* $Id: VBoxDev-haiku.c $ */
+/** @file
+ * VBoxGuest kernel driver, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <OS.h>
+#include <Drivers.h>
+#include <KernelExport.h>
+#include <PCI.h>
+
+#include "VBoxGuest-haiku.h"
+#include "VBoxGuestInternal.h"
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/mem.h>
+#include <iprt/asm.h>
+
+#define DRIVER_NAME "vboxdev"
+#define DEVICE_NAME "misc/vboxguest"
+#define MODULE_NAME "generic/vboxguest"
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static status_t VBoxGuestHaikuOpen(const char *name, uint32 flags, void **cookie);
+static status_t VBoxGuestHaikuClose(void *cookie);
+static status_t VBoxGuestHaikuFree(void *cookie);
+static status_t VBoxGuestHaikuIOCtl(void *cookie, uint32 op, void *data, size_t len);
+static status_t VBoxGuestHaikuSelect(void *cookie, uint8 event, uint32 ref, selectsync *sync);
+static status_t VBoxGuestHaikuDeselect(void *cookie, uint8 event, selectsync *sync);
+static status_t VBoxGuestHaikuWrite(void *cookie, off_t position, const void *data, size_t *numBytes);
+static status_t VBoxGuestHaikuRead(void *cookie, off_t position, void *data, size_t *numBytes);
+
+static device_hooks g_VBoxGuestHaikuDeviceHooks =
+{
+ VBoxGuestHaikuOpen,
+ VBoxGuestHaikuClose,
+ VBoxGuestHaikuFree,
+ VBoxGuestHaikuIOCtl,
+ VBoxGuestHaikuRead,
+ VBoxGuestHaikuWrite,
+ VBoxGuestHaikuSelect,
+ VBoxGuestHaikuDeselect,
+};
+
+
+/**
+ * Driver open hook.
+ *
+ * @param name The name of the device as returned by publish_devices.
+ * @param flags Open flags.
+ * @param cookie Where to store the session pointer.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuOpen(const char *name, uint32 flags, void **cookie)
+{
+ int rc;
+ PVBOXGUESTSESSION pSession;
+
+ LogFlow((DRIVER_NAME ":VBoxGuestHaikuOpen\n"));
+
+ /*
+ * Create a new session.
+ */
+ rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ Log((DRIVER_NAME ":VBoxGuestHaikuOpen success: g_DevExt=%p pSession=%p rc=%d pid=%d\n",&g_DevExt, pSession, rc,(int)RTProcSelf()));
+ ASMAtomicIncU32(&cUsers);
+ *cookie = pSession;
+ return B_OK;
+ }
+
+ LogRel((DRIVER_NAME ":VBoxGuestHaikuOpen: failed. rc=%d\n", rc));
+ return RTErrConvertToErrno(rc);
+}
+
+
+/**
+ * Driver close hook.
+ * @param cookie The session.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuClose(void *cookie)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+ Log(("VBoxGuestHaikuClose: pSession=%p\n", pSession));
+
+ /** @todo r=ramshankar: should we really be using the session spinlock here? */
+ RTSpinlockAcquire(g_DevExt.SessionSpinlock);
+
+ /* @todo we don't know if it belongs to this session!! */
+ if (sState.selectSync)
+ {
+ //dprintf(DRIVER_NAME "close: unblocking select %p %x\n", sState.selectSync, sState.selectEvent);
+ notify_select_event(sState.selectSync, sState.selectEvent);
+ sState.selectEvent = (uint8_t)0;
+ sState.selectRef = (uint32_t)0;
+ sState.selectSync = (void *)NULL;
+ }
+
+ RTSpinlockRelease(g_DevExt.SessionSpinlock);
+ return B_OK;
+}
+
+
+/**
+ * Driver free hook.
+ * @param cookie The session.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuFree(void *cookie)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+ Log(("VBoxGuestHaikuFree: pSession=%p\n", pSession));
+
+ /*
+ * Close the session if it's still hanging on to the device...
+ */
+ if (VALID_PTR(pSession))
+ {
+ VBoxGuestCloseSession(&g_DevExt, pSession);
+ ASMAtomicDecU32(&cUsers);
+ }
+ else
+ Log(("VBoxGuestHaikuFree: si_drv1=%p!\n", pSession));
+ return B_OK;
+}
+
+
+/**
+ * Driver IOCtl entry.
+ * @param cookie The session.
+ * @param op The operation to perform.
+ * @param data The data associated with the operation.
+ * @param len Size of the data in bytes.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuIOCtl(void *cookie, uint32 op, void *data, size_t len)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+ Log((DRIVER_NAME ":VBoxGuestHaikuIOCtl cookie=%p op=0x%08x data=%p len=%lu)\n", cookie, op, data, len));
+
+ int rc = B_OK;
+
+ /*
+ * Validate the input.
+ */
+ if (RT_UNLIKELY(!VALID_PTR(pSession)))
+ return EINVAL;
+
+ /*
+ * Validate the request wrapper.
+ */
+#if 0
+ if (IOCPARM_LEN(ulCmd) != sizeof(VBGLBIGREQ))
+ {
+ Log((DRIVER_NAME ": VBoxGuestHaikuIOCtl: bad request %lu size=%lu expected=%d\n", ulCmd, IOCPARM_LEN(ulCmd),
+ sizeof(VBGLBIGREQ)));
+ return ENOTTY;
+ }
+#endif
+
+ if (RT_UNLIKELY(len > _1M * 16))
+ {
+ dprintf(DRIVER_NAME ": VBoxGuestHaikuIOCtl: bad size %#x; pArg=%p Cmd=%lu.\n", (unsigned)len, data, op);
+ return EINVAL;
+ }
+
+ /*
+ * Read the request.
+ */
+ void *pvBuf = NULL;
+ if (RT_LIKELY(len > 0))
+ {
+ pvBuf = RTMemTmpAlloc(len);
+ if (RT_UNLIKELY(!pvBuf))
+ {
+ LogRel((DRIVER_NAME ":VBoxGuestHaikuIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", len));
+ return ENOMEM;
+ }
+
+ /** @todo r=ramshankar: replace with RTR0MemUserCopyFrom() */
+ rc = user_memcpy(pvBuf, data, len);
+ if (RT_UNLIKELY(rc < 0))
+ {
+ RTMemTmpFree(pvBuf);
+ LogRel((DRIVER_NAME ":VBoxGuestHaikuIOCtl: user_memcpy failed; pvBuf=%p data=%p op=%d. rc=%d\n", pvBuf, data, op, rc));
+ return EFAULT;
+ }
+ if (RT_UNLIKELY(!VALID_PTR(pvBuf)))
+ {
+ RTMemTmpFree(pvBuf);
+ LogRel((DRIVER_NAME ":VBoxGuestHaikuIOCtl: pvBuf invalid pointer %p\n", pvBuf));
+ return EINVAL;
+ }
+ }
+ Log((DRIVER_NAME ":VBoxGuestHaikuIOCtl: pSession=%p pid=%d.\n", pSession,(int)RTProcSelf()));
+
+ /*
+ * Process the IOCtl.
+ */
+ size_t cbDataReturned;
+ rc = VBoxGuestCommonIOCtl(op, &g_DevExt, pSession, pvBuf, len, &cbDataReturned);
+ if (RT_SUCCESS(rc))
+ {
+ rc = 0;
+ if (RT_UNLIKELY(cbDataReturned > len))
+ {
+ Log((DRIVER_NAME ":VBoxGuestHaikuIOCtl: too much output data %d expected %d\n", cbDataReturned, len));
+ cbDataReturned = len;
+ }
+ if (cbDataReturned > 0)
+ {
+ rc = user_memcpy(data, pvBuf, cbDataReturned);
+ if (RT_UNLIKELY(rc < 0))
+ {
+ Log((DRIVER_NAME ":VBoxGuestHaikuIOCtl: user_memcpy failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, data, op, rc));
+ rc = EFAULT;
+ }
+ }
+ }
+ else
+ {
+ Log((DRIVER_NAME ":VBoxGuestHaikuIOCtl: VBoxGuestCommonIOCtl failed. rc=%d\n", rc));
+ rc = EFAULT;
+ }
+ RTMemTmpFree(pvBuf);
+ return rc;
+}
+
+
+/**
+ * Driver select hook.
+ *
+ * @param cookie The session.
+ * @param event The event.
+ * @param ref ???
+ * @param sync ???
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuSelect(void *cookie, uint8 event, uint32 ref, selectsync *sync)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+ status_t err = B_OK;
+
+ switch (event)
+ {
+ case B_SELECT_READ:
+ break;
+ default:
+ return EINVAL;
+ }
+
+ RTSpinlockAcquire(g_DevExt.SessionSpinlock);
+
+ uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
+ if (pSession->u32MousePosChangedSeq != u32CurSeq)
+ {
+ pSession->u32MousePosChangedSeq = u32CurSeq;
+ notify_select_event(sync, event);
+ }
+ else if (sState.selectSync == NULL)
+ {
+ sState.selectEvent = (uint8_t)event;
+ sState.selectRef = (uint32_t)ref;
+ sState.selectSync = (void *)sync;
+ }
+ else
+ err = B_WOULD_BLOCK;
+
+ RTSpinlockRelease(g_DevExt.SessionSpinlock);
+
+ return err;
+}
+
+
+/**
+ * Driver deselect hook.
+ * @param cookie The session.
+ * @param event The event.
+ * @param sync ???
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuDeselect(void *cookie, uint8 event, selectsync *sync)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+ status_t err = B_OK;
+ //dprintf(DRIVER_NAME "deselect(,%d,%p)\n", event, sync);
+
+ RTSpinlockAcquire(g_DevExt.SessionSpinlock);
+
+ if (sState.selectSync == sync)
+ {
+ //dprintf(DRIVER_NAME "deselect: dropping: %p %x\n", sState.selectSync, sState.selectEvent);
+ sState.selectEvent = (uint8_t)0;
+ sState.selectRef = (uint32_t)0;
+ sState.selectSync = NULL;
+ }
+ else
+ err = B_OK;
+
+ RTSpinlockRelease(g_DevExt.SessionSpinlock);
+ return err;
+}
+
+
+/**
+ * Driver write hook.
+ * @param cookie The session.
+ * @param position The offset.
+ * @param data Pointer to the data.
+ * @param numBytes Where to store the number of bytes written.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuWrite(void *cookie, off_t position, const void *data, size_t *numBytes)
+{
+ *numBytes = 0;
+ return B_OK;
+}
+
+
+/**
+ * Driver read hook.
+ * @param cookie The session.
+ * @param position The offset.
+ * @param data Pointer to the data.
+ * @param numBytes Where to store the number of bytes read.
+ *
+ * @return Haiku status code.
+ */
+static status_t VBoxGuestHaikuRead(void *cookie, off_t position, void *data, size_t *numBytes)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
+
+ if (*numBytes == 0)
+ return B_OK;
+
+ uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
+ if (pSession->u32MousePosChangedSeq != u32CurSeq)
+ {
+ pSession->u32MousePosChangedSeq = u32CurSeq;
+ *numBytes = 1;
+ return B_OK;
+ }
+
+ *numBytes = 0;
+ return B_OK;
+}
+
+
+int32 api_version = B_CUR_DRIVER_API_VERSION;
+
+status_t init_hardware()
+{
+ return get_module(MODULE_NAME, (module_info **)&g_VBoxGuest);
+}
+
+status_t init_driver()
+{
+ return B_OK;
+}
+
+device_hooks* find_device(const char *name)
+{
+ static device_hooks g_VBoxGuestHaikuDeviceHooks =
+ {
+ VBoxGuestHaikuOpen,
+ VBoxGuestHaikuClose,
+ VBoxGuestHaikuFree,
+ VBoxGuestHaikuIOCtl,
+ VBoxGuestHaikuRead,
+ VBoxGuestHaikuWrite,
+ VBoxGuestHaikuSelect,
+ VBoxGuestHaikuDeselect
+ };
+ return &g_VBoxGuestHaikuDeviceHooks;
+}
+
+const char** publish_devices()
+{
+ static const char *devices[] = { DEVICE_NAME, NULL };
+ return devices;
+}
+
+void uninit_driver()
+{
+ put_module(MODULE_NAME);
+}
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-darwin.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-darwin.cpp
new file mode 100644
index 00000000..3eb7dab4
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-darwin.cpp
@@ -0,0 +1,1085 @@
+/* $Id: VBoxGuest-darwin.cpp $ */
+/** @file
+ * VBoxGuest - Darwin Specifics.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_VBGD
+/*
+ * Deal with conflicts first.
+ * PVM - BSD mess, that FreeBSD has correct a long time ago.
+ * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
+ */
+#include <iprt/types.h>
+#include <sys/param.h>
+#undef PVM
+
+#include <IOKit/IOLib.h> /* Assert as function */
+
+#include <VBox/version.h>
+#include <iprt/asm.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+#include <iprt/alloc.h>
+#include <iprt/power.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <mach/kmod.h>
+#include <miscfs/devfs/devfs.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/kauth.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOUserClient.h>
+#include <IOKit/pwr_mgt/RootDomain.h>
+#include <IOKit/pci/IOPCIDevice.h>
+#include <IOKit/IOBufferMemoryDescriptor.h>
+#include <IOKit/IOFilterInterruptEventSource.h>
+#include "VBoxGuestInternal.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+
+/** The system device node name. */
+#define DEVICE_NAME_SYS "vboxguest"
+/** The user device node name. */
+#define DEVICE_NAME_USR "vboxguestu"
+
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+RT_C_DECLS_BEGIN
+static kern_return_t VbgdDarwinStart(struct kmod_info *pKModInfo, void *pvData);
+static kern_return_t VbgdDarwinStop(struct kmod_info *pKModInfo, void *pvData);
+static int VbgdDarwinCharDevRemove(void);
+
+static int VbgdDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VbgdDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VbgdDarwinIOCtlSlow(PVBOXGUESTSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
+static int VbgdDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
+
+static int VbgdDarwinErr2DarwinErr(int rc);
+
+static IOReturn VbgdDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
+RT_C_DECLS_END
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The service class for handling the VMMDev PCI device.
+ *
+ * Instantiated when the module is loaded (and on PCI hotplugging?).
+ */
+class org_virtualbox_VBoxGuest : public IOService
+{
+ OSDeclareDefaultStructors(org_virtualbox_VBoxGuest);
+
+private:
+ IOPCIDevice *m_pIOPCIDevice;
+ IOMemoryMap *m_pMap;
+ IOFilterInterruptEventSource *m_pInterruptSrc;
+
+ bool setupVmmDevInterrupts(IOService *pProvider);
+ bool disableVmmDevInterrupts(void);
+ bool isVmmDev(IOPCIDevice *pIOPCIDevice);
+
+public:
+ virtual bool start(IOService *pProvider);
+ virtual void stop(IOService *pProvider);
+ virtual bool terminate(IOOptionBits fOptions);
+};
+
+OSDefineMetaClassAndStructors(org_virtualbox_VBoxGuest, IOService);
+
+
+/**
+ * An attempt at getting that clientDied() notification.
+ * I don't think it'll work as I cannot figure out where/what creates the correct
+ * port right.
+ *
+ * Instantiated when userland does IOServiceOpen().
+ */
+class org_virtualbox_VBoxGuestClient : public IOUserClient
+{
+ OSDeclareDefaultStructors(org_virtualbox_VBoxGuestClient);
+
+private:
+ PVBOXGUESTSESSION m_pSession; /**< The session. */
+ task_t m_Task; /**< The client task. */
+ org_virtualbox_VBoxGuest *m_pProvider; /**< The service provider. */
+
+public:
+ virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
+ virtual bool start(IOService *pProvider);
+ static void sessionClose(RTPROCESS Process);
+ virtual IOReturn clientClose(void);
+};
+
+OSDefineMetaClassAndStructors(org_virtualbox_VBoxGuestClient, IOUserClient);
+
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Declare the module stuff.
+ */
+RT_C_DECLS_BEGIN
+extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
+extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
+
+KMOD_EXPLICIT_DECL(VBoxGuest, VBOX_VERSION_STRING, _start, _stop)
+DECLHIDDEN(kmod_start_func_t *) _realmain = VbgdDarwinStart;
+DECLHIDDEN(kmod_stop_func_t *) _antimain = VbgdDarwinStop;
+DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
+RT_C_DECLS_END
+
+
+/**
+ * Device extention & session data association structure.
+ */
+static VBOXGUESTDEVEXT g_DevExt;
+
+/**
+ * The character device switch table for the driver.
+ */
+static struct cdevsw g_DevCW =
+{
+ /*.d_open = */ VbgdDarwinOpen,
+ /*.d_close = */ VbgdDarwinClose,
+ /*.d_read = */ eno_rdwrt,
+ /*.d_write = */ eno_rdwrt,
+ /*.d_ioctl = */ VbgdDarwinIOCtl,
+ /*.d_stop = */ eno_stop,
+ /*.d_reset = */ eno_reset,
+ /*.d_ttys = */ NULL,
+ /*.d_select = */ eno_select,
+ /*.d_mmap = */ eno_mmap,
+ /*.d_strategy = */ eno_strat,
+ /*.d_getc = */ eno_getc,
+ /*.d_putc = */ eno_putc,
+ /*.d_type = */ 0
+};
+
+/** Major device number. */
+static int g_iMajorDeviceNo = -1;
+/** Registered devfs device handle. */
+static void *g_hDevFsDeviceSys = NULL;
+/** Registered devfs device handle for the user device. */
+static void *g_hDevFsDeviceUsr = NULL; /**< @todo 4 later */
+
+/** Spinlock protecting g_apSessionHashTab. */
+static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
+/** Hash table */
+static PVBOXGUESTSESSION g_apSessionHashTab[19];
+/** Calculates the index into g_apSessionHashTab.*/
+#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
+/** The number of open sessions. */
+static int32_t volatile g_cSessions = 0;
+/** The number of IOService class instances. */
+static bool volatile g_fInstantiated = 0;
+/** The notifier handle for the sleep callback handler. */
+static IONotifier *g_pSleepNotifier = NULL;
+
+
+
+/**
+ * Start the kernel module.
+ */
+static kern_return_t VbgdDarwinStart(struct kmod_info *pKModInfo, void *pvData)
+{
+#ifdef DEBUG
+ printf("VbgdDarwinStart\n");
+#endif
+
+ /*
+ * Initialize IPRT.
+ */
+ int rc = RTR0Init(0);
+ if (RT_FAILURE(rc))
+ {
+ printf("VBoxGuest: RTR0Init failed with rc=%d\n", rc);
+ return KMOD_RETURN_FAILURE;
+ }
+
+ return KMOD_RETURN_SUCCESS;
+}
+
+
+/* Register VBoxGuest char device */
+static int VbgdDarwinCharDevInit(void)
+{
+ int rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestDarwin");
+ if (RT_FAILURE(rc))
+ {
+ return KMOD_RETURN_FAILURE;
+ }
+
+ /*
+ * Registering ourselves as a character device.
+ */
+ g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
+ if (g_iMajorDeviceNo < 0)
+ {
+ VbgdDarwinCharDevRemove();
+ return KMOD_RETURN_FAILURE;
+ }
+
+ g_hDevFsDeviceSys = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
+ UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME_SYS);
+ if (!g_hDevFsDeviceSys)
+ {
+ VbgdDarwinCharDevRemove();
+ return KMOD_RETURN_FAILURE;
+ }
+
+ /* Register a sleep/wakeup notification callback */
+ g_pSleepNotifier = registerPrioritySleepWakeInterest(&VbgdDarwinSleepHandler, &g_DevExt, NULL);
+ if (g_pSleepNotifier == NULL)
+ {
+ VbgdDarwinCharDevRemove();
+ return KMOD_RETURN_FAILURE;
+ }
+
+ return KMOD_RETURN_SUCCESS;
+}
+
+
+/**
+ * Stop the kernel module.
+ */
+static kern_return_t VbgdDarwinStop(struct kmod_info *pKModInfo, void *pvData)
+{
+ RTR0TermForced();
+#ifdef DEBUG
+ printf("VbgdDarwinStop - done\n");
+#endif
+ return KMOD_RETURN_SUCCESS;
+}
+
+
+/* Unregister VBoxGuest char device */
+static int
+VbgdDarwinCharDevRemove(void)
+{
+ int rc = KMOD_RETURN_SUCCESS;
+
+ if (g_pSleepNotifier)
+ {
+ g_pSleepNotifier->remove();
+ g_pSleepNotifier = NULL;
+ }
+
+ if (g_hDevFsDeviceSys)
+ {
+ devfs_remove(g_hDevFsDeviceSys);
+ g_hDevFsDeviceSys = NULL;
+ }
+
+ if (g_hDevFsDeviceUsr)
+ {
+ devfs_remove(g_hDevFsDeviceUsr);
+ g_hDevFsDeviceUsr = NULL;
+ }
+
+ if (g_iMajorDeviceNo != -1)
+ {
+ int rc2 = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
+ Assert(rc2 == g_iMajorDeviceNo);
+ g_iMajorDeviceNo = -1;
+ }
+
+ if (g_Spinlock != NIL_RTSPINLOCK)
+ {
+ int rc2 = RTSpinlockDestroy(g_Spinlock); AssertRC(rc2);
+ g_Spinlock = NIL_RTSPINLOCK;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Device open. Called on open /dev/vboxguest and (later) /dev/vboxguestu.
+ *
+ * @param Dev The device number.
+ * @param fFlags ???.
+ * @param fDevType ???.
+ * @param pProcess The process issuing this request.
+ */
+static int VbgdDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+ /*
+ * Only two minor devices numbers are allowed.
+ */
+ if (minor(Dev) != 0 && minor(Dev) != 1)
+ return EACCES;
+
+ /*
+ * Find the session created by org_virtualbox_VBoxGuestClient, fail
+ * if no such session, and mark it as opened. We set the uid & gid
+ * here too, since that is more straight forward at this point.
+ */
+ //const bool fUnrestricted = minor(Dev) == 0;
+ int rc = VINF_SUCCESS;
+ PVBOXGUESTSESSION pSession = NULL;
+ kauth_cred_t pCred = kauth_cred_proc_ref(pProcess);
+ if (pCred)
+ {
+ RTPROCESS Process = RTProcSelf();
+ unsigned iHash = SESSION_HASH(Process);
+ RTSpinlockAcquire(g_Spinlock);
+
+ pSession = g_apSessionHashTab[iHash];
+ while (pSession && pSession->Process != Process)
+ pSession = pSession->pNextHash;
+ if (pSession)
+ {
+ if (!pSession->fOpened)
+ {
+ pSession->fOpened = true;
+ /*pSession->fUnrestricted = fUnrestricted; - later */
+ }
+ else
+ rc = VERR_ALREADY_LOADED;
+ }
+ else
+ rc = VERR_GENERAL_FAILURE;
+
+ RTSpinlockReleaseNoInts(g_Spinlock);
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ kauth_cred_unref(&pCred);
+#else /* 10.4 */
+ /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions
+ of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */
+ kauth_cred_rele(pCred);
+#endif /* 10.4 */
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ Log(("VbgdDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
+ return VbgdDarwinErr2DarwinErr(rc);
+}
+
+
+/**
+ * Close device.
+ */
+static int VbgdDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+ Log(("VbgdDarwinClose: pid=%d\n", (int)RTProcSelf()));
+ Assert(proc_pid(pProcess) == (int)RTProcSelf());
+
+ /*
+ * Hand the session closing to org_virtualbox_VBoxGuestClient.
+ */
+ org_virtualbox_VBoxGuestClient::sessionClose(RTProcSelf());
+ return 0;
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
+ * @param Dev The device number (major+minor).
+ * @param iCmd The IOCtl command.
+ * @param pData Pointer to the data (if any it's a VBOXGUESTIOCTLDATA (kernel copy)).
+ * @param fFlags Flag saying we're a character device (like we didn't know already).
+ * @param pProcess The process issuing this request.
+ */
+static int VbgdDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
+{
+ //const bool fUnrestricted = minor(Dev) == 0;
+ const RTPROCESS Process = proc_pid(pProcess);
+ const unsigned iHash = SESSION_HASH(Process);
+ PVBOXGUESTSESSION pSession;
+
+ /*
+ * Find the session.
+ */
+ RTSpinlockAcquire(g_Spinlock);
+ pSession = g_apSessionHashTab[iHash];
+ while (pSession && pSession->Process != Process /*later: && pSession->fUnrestricted == fUnrestricted*/ && pSession->fOpened)
+ pSession = pSession->pNextHash;
+ RTSpinlockReleaseNoInts(g_Spinlock);
+ if (!pSession)
+ {
+ Log(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#lx\n",
+ (int)Process, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * No high speed IOCtls here yet.
+ */
+
+ return VbgdDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
+}
+
+
+/**
+ * Worker for VbgdDarwinIOCtl that takes the slow IOCtl functions.
+ *
+ * @returns Darwin errno.
+ *
+ * @param pSession The session.
+ * @param iCmd The IOCtl command.
+ * @param pData Pointer to the kernel copy of the data buffer.
+ * @param pProcess The calling process.
+ */
+static int VbgdDarwinIOCtlSlow(PVBOXGUESTSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
+{
+ LogFlow(("VbgdDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
+
+
+ /*
+ * Buffered or unbuffered?
+ */
+ void *pvReqData;
+ user_addr_t pUser = 0;
+ void *pvPageBuf = NULL;
+ uint32_t cbReq = IOCPARM_LEN(iCmd);
+ if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
+ {
+ /*
+ * Raw buffered request data, common code validates it.
+ */
+ pvReqData = pData;
+ }
+ else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
+ {
+ /*
+ * Get the header and figure out how much we're gonna have to read.
+ */
+ VBGLBIGREQ Hdr;
+ pUser = (user_addr_t)*(void **)pData;
+ int rc = copyin(pUser, &Hdr, sizeof(Hdr));
+ if (RT_UNLIKELY(rc))
+ {
+ Log(("VbgdDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
+ return rc;
+ }
+ if (RT_UNLIKELY(Hdr.u32Magic != VBGLBIGREQ_MAGIC))
+ {
+ Log(("VbgdDarwinIOCtlSlow: bad magic u32Magic=%#x; iCmd=%#lx\n", Hdr.u32Magic, iCmd));
+ return EINVAL;
+ }
+ cbReq = Hdr.cbData;
+ if (RT_UNLIKELY(cbReq > _1M*16))
+ {
+ Log(("VbgdDarwinIOCtlSlow: %#x; iCmd=%#lx\n", Hdr.cbData, iCmd));
+ return EINVAL;
+ }
+ pUser = Hdr.pvDataR3;
+
+ /*
+ * Allocate buffer and copy in the data.
+ */
+ pvReqData = RTMemTmpAlloc(cbReq);
+ if (!pvReqData)
+ pvPageBuf = pvReqData = IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
+ if (RT_UNLIKELY(!pvReqData))
+ {
+ Log(("VbgdDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
+ return ENOMEM;
+ }
+ rc = copyin(pUser, pvReqData, Hdr.cbData);
+ if (RT_UNLIKELY(rc))
+ {
+ Log(("VbgdDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
+ (unsigned long long)pUser, pvReqData, Hdr.cbData, rc, iCmd));
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pvReqData);
+ return rc;
+ }
+ }
+ else
+ {
+ Log(("VbgdDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ size_t cbReqRet = 0;
+ int rc = VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pSession, pvReqData, cbReq, &cbReqRet);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * If not buffered, copy back the buffer before returning.
+ */
+ if (pUser)
+ {
+ if (cbReqRet > cbReq)
+ {
+ Log(("VbgdDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbReqRet, cbReq, iCmd));
+ cbReqRet = cbReq;
+ }
+ rc = copyout(pvReqData, pUser, cbReqRet);
+ if (RT_UNLIKELY(rc))
+ Log(("VbgdDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
+ pvReqData, (unsigned long long)pUser, cbReqRet, rc, iCmd));
+
+ /* cleanup */
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pvReqData);
+ }
+ else
+ rc = 0;
+ }
+ else
+ {
+ /*
+ * The request failed, just clean up.
+ */
+ if (pUser)
+ {
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pvReqData);
+ }
+
+ Log(("VbgdDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
+ rc = EINVAL;
+ }
+
+ Log2(("VbgdDarwinIOCtlSlow: returns %d\n", rc));
+ return rc;
+}
+
+
+/*
+ * The VBoxGuest IDC entry points.
+ *
+ * This code is shared with the other unixy OSes.
+ */
+#include "VBoxGuestIDC-unix.c.h"
+
+
+void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
+{
+ NOREF(pDevExt);
+}
+
+
+/**
+ * Callback for blah blah blah.
+ */
+IOReturn VbgdDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType, IOService * /* pProvider */, void * /* pvMessageArgument */, vm_size_t /* argSize */)
+{
+ LogFlow(("VBoxGuest: Got sleep/wake notice. Message type was %X\n", (uint)uMessageType));
+
+ if (uMessageType == kIOMessageSystemWillSleep)
+ RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
+ else if (uMessageType == kIOMessageSystemHasPoweredOn)
+ RTPowerSignalEvent(RTPOWEREVENT_RESUME);
+
+ acknowledgeSleepWakeNotification(pvRefCon);
+
+ return 0;
+}
+
+
+/**
+ * Converts an IPRT error code to a darwin error code.
+ *
+ * @returns corresponding darwin error code.
+ * @param rc IPRT status code.
+ */
+static int VbgdDarwinErr2DarwinErr(int rc)
+{
+ switch (rc)
+ {
+ case VINF_SUCCESS: return 0;
+ case VERR_GENERAL_FAILURE: return EACCES;
+ case VERR_INVALID_PARAMETER: return EINVAL;
+ case VERR_INVALID_MAGIC: return EILSEQ;
+ case VERR_INVALID_HANDLE: return ENXIO;
+ case VERR_INVALID_POINTER: return EFAULT;
+ case VERR_LOCK_FAILED: return ENOLCK;
+ case VERR_ALREADY_LOADED: return EEXIST;
+ case VERR_PERMISSION_DENIED: return EPERM;
+ case VERR_VERSION_MISMATCH: return ENOSYS;
+ }
+
+ return EPERM;
+}
+
+
+/*
+ *
+ * org_virtualbox_VBoxGuest
+ *
+ */
+
+/**
+ * Just a plug
+ */
+static void
+interruptHandler(OSObject *pOwner, IOInterruptEventSource *pSrc, int cInts)
+{
+ NOREF(pOwner);
+ NOREF(pSrc);
+ NOREF(cInts);
+}
+
+/**
+ * Callback triggered when interrupt occurs.
+ */
+static bool
+checkForInterrupt(OSObject *pOwner, IOFilterInterruptEventSource *pSrc)
+{
+ if (!pSrc)
+ return false;
+
+ bool fTaken = VBoxGuestCommonISR(&g_DevExt);
+ if (!fTaken)
+ printf("VBoxGuestCommonISR error\n");
+
+ return fTaken;
+}
+
+bool
+org_virtualbox_VBoxGuest::setupVmmDevInterrupts(IOService *pProvider)
+{
+ IOWorkLoop *pWorkLoop = (IOWorkLoop *)getWorkLoop();
+
+ if (!pWorkLoop)
+ return false;
+
+ m_pInterruptSrc = IOFilterInterruptEventSource::filterInterruptEventSource(this,
+ &interruptHandler,
+ &checkForInterrupt,
+ pProvider);
+
+ if (kIOReturnSuccess != pWorkLoop->addEventSource(m_pInterruptSrc))
+ {
+ m_pInterruptSrc->disable();
+ m_pInterruptSrc->release();
+ m_pInterruptSrc = 0;
+ return false;
+ }
+
+ m_pInterruptSrc->enable();
+
+ return true;
+}
+
+bool
+org_virtualbox_VBoxGuest::disableVmmDevInterrupts(void)
+{
+ IOWorkLoop *pWorkLoop = (IOWorkLoop *)getWorkLoop();
+
+ if (!pWorkLoop)
+ return false;
+
+ if (!m_pInterruptSrc)
+ return false;
+
+ m_pInterruptSrc->disable();
+ pWorkLoop->removeEventSource(m_pInterruptSrc);
+ m_pInterruptSrc->release();
+ m_pInterruptSrc = 0;
+
+ return true;
+}
+
+bool org_virtualbox_VBoxGuest::isVmmDev(IOPCIDevice *pIOPCIDevice)
+{
+ UInt16 uVendorId, uDeviceId;
+
+ if (!pIOPCIDevice)
+ return false;
+
+ uVendorId = m_pIOPCIDevice->configRead16(kIOPCIConfigVendorID);
+ uDeviceId = m_pIOPCIDevice->configRead16(kIOPCIConfigDeviceID);
+
+ if (uVendorId == VMMDEV_VENDORID && uDeviceId == VMMDEV_DEVICEID)
+ return true;
+
+ return true;
+}
+
+
+/**
+ * Start this service.
+ */
+bool org_virtualbox_VBoxGuest::start(IOService *pProvider)
+{
+ if (!IOService::start(pProvider))
+ return false;
+
+ /* Low level initialization should be performed only once */
+ if (!ASMAtomicCmpXchgBool(&g_fInstantiated, true, false))
+ {
+ IOService::stop(pProvider);
+ return false;
+ }
+
+ m_pIOPCIDevice = OSDynamicCast(IOPCIDevice, pProvider);
+ if (m_pIOPCIDevice)
+ {
+ if (isVmmDev(m_pIOPCIDevice))
+ {
+ /* Enable memory response from VMM device */
+ m_pIOPCIDevice->setMemoryEnable(true);
+ m_pIOPCIDevice->setIOEnable(true);
+
+ IOMemoryDescriptor *pMem = m_pIOPCIDevice->getDeviceMemoryWithIndex(0);
+ if (pMem)
+ {
+ IOPhysicalAddress IOPortBasePhys = pMem->getPhysicalAddress();
+ /* Check that returned value is from I/O port range (at least it is 16-bit lenght) */
+ if((IOPortBasePhys >> 16) == 0)
+ {
+
+ RTIOPORT IOPortBase = (RTIOPORT)IOPortBasePhys;
+ void *pvMMIOBase = NULL;
+ uint32_t cbMMIO = 0;
+ m_pMap = m_pIOPCIDevice->mapDeviceMemoryWithIndex(1);
+ if (m_pMap)
+ {
+ pvMMIOBase = (void *)m_pMap->getVirtualAddress();
+ cbMMIO = m_pMap->getLength();
+ }
+
+ int rc = VBoxGuestInitDevExt(&g_DevExt,
+ IOPortBase,
+ pvMMIOBase,
+ cbMMIO,
+#if ARCH_BITS == 64
+ VBOXOSTYPE_MacOS_x64,
+#else
+ VBOXOSTYPE_MacOS,
+#endif
+ 0);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbgdDarwinCharDevInit();
+ if (rc == KMOD_RETURN_SUCCESS)
+ {
+ if (setupVmmDevInterrupts(pProvider))
+ {
+ /* register the service. */
+ registerService();
+ LogRel(("VBoxGuest: Successfully started I/O kit class instance.\n"));
+ return true;
+ }
+
+ LogRel(("VBoxGuest: Failed to set up interrupts\n"));
+ VbgdDarwinCharDevRemove();
+ }
+ else
+ LogRel(("VBoxGuest: Failed to initialize character device (rc=%d).\n", rc));
+
+ VBoxGuestDeleteDevExt(&g_DevExt);
+ }
+ else
+ LogRel(("VBoxGuest: Failed to initialize common code (rc=%d).\n", rc));
+
+ if (m_pMap)
+ {
+ m_pMap->release();
+ m_pMap = NULL;
+ }
+ }
+ }
+ else
+ LogRel(("VBoxGuest: The device missing is the I/O port range (#0).\n"));
+ }
+ else
+ LogRel(("VBoxGuest: Not the VMMDev (%#x:%#x).\n",
+ m_pIOPCIDevice->configRead16(kIOPCIConfigVendorID), m_pIOPCIDevice->configRead16(kIOPCIConfigDeviceID)));
+ }
+ else
+ LogRel(("VBoxGuest: Provider is not an instance of IOPCIDevice.\n"));
+
+ ASMAtomicXchgBool(&g_fInstantiated, false);
+
+ IOService::stop(pProvider);
+
+ return false;
+}
+
+
+/**
+ * Stop this service.
+ */
+void org_virtualbox_VBoxGuest::stop(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_VBoxGuest::stop([%p], %p)\n", this, pProvider));
+
+ AssertReturnVoid(ASMAtomicReadBool(&g_fInstantiated));
+
+ /* Low level termination should be performed only once */
+ if (!disableVmmDevInterrupts())
+ LogRel(("vboxguest: unable to unregister interrupt handler\n"));
+
+ VbgdDarwinCharDevRemove();
+ VBoxGuestDeleteDevExt(&g_DevExt);
+
+ if (m_pMap)
+ {
+ m_pMap->release();
+ m_pMap = NULL;
+ }
+
+ IOService::stop(pProvider);
+
+ ASMAtomicWriteBool(&g_fInstantiated, false);
+
+ LogRel(("vboxguest module unloaded\n"));
+}
+
+
+/**
+ * Termination request.
+ *
+ * @return true if we're ok with shutting down now, false if we're not.
+ * @param fOptions Flags.
+ */
+bool org_virtualbox_VBoxGuest::terminate(IOOptionBits fOptions)
+{
+ bool fRc;
+ LogFlow(("org_virtualbox_VBoxGuest::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
+ KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
+ if ( KMOD_INFO_NAME.reference_count != 0
+ || ASMAtomicUoReadS32(&g_cSessions))
+ fRc = false;
+ else
+ fRc = IOService::terminate(fOptions);
+ LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
+ return fRc;
+}
+
+
+/*
+ *
+ * org_virtualbox_VBoxGuestClient
+ *
+ */
+
+
+/**
+ * Initializer called when the client opens the service.
+ */
+bool org_virtualbox_VBoxGuestClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
+{
+ LogFlow(("org_virtualbox_VBoxGuestClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
+ this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
+ AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
+
+ if (!OwningTask)
+ return false;
+ if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
+ {
+ m_Task = OwningTask;
+ m_pSession = NULL;
+ m_pProvider = NULL;
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Start the client service.
+ */
+bool org_virtualbox_VBoxGuestClient::start(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_VBoxGuestClient::start([%p], %p) (cur pid=%d proc=%p)\n",
+ this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
+ AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
+ ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
+ false);
+
+ if (IOUserClient::start(pProvider))
+ {
+ m_pProvider = OSDynamicCast(org_virtualbox_VBoxGuest, pProvider);
+ if (m_pProvider)
+ {
+ Assert(!m_pSession);
+
+ /*
+ * Create a new session.
+ */
+ int rc = VBoxGuestCreateUserSession(&g_DevExt, &m_pSession);
+ if (RT_SUCCESS(rc))
+ {
+ m_pSession->fOpened = false;
+ /* The fUnrestricted field is set on open. */
+
+ /*
+ * Insert it into the hash table, checking that there isn't
+ * already one for this process first. (One session per proc!)
+ */
+ unsigned iHash = SESSION_HASH(m_pSession->Process);
+ RTSpinlockAcquire(g_Spinlock);
+
+ PVBOXGUESTSESSION pCur = g_apSessionHashTab[iHash];
+ if (pCur && pCur->Process != m_pSession->Process)
+ {
+ do pCur = pCur->pNextHash;
+ while (pCur && pCur->Process != m_pSession->Process);
+ }
+ if (!pCur)
+ {
+ m_pSession->pNextHash = g_apSessionHashTab[iHash];
+ g_apSessionHashTab[iHash] = m_pSession;
+ m_pSession->pvVBoxGuestClient = this;
+ ASMAtomicIncS32(&g_cSessions);
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_ALREADY_LOADED;
+
+ RTSpinlockRelease(g_Spinlock);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("org_virtualbox_VBoxGuestClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
+ return true;
+ }
+
+ LogFlow(("org_virtualbox_VBoxGuestClient::start: already got a session for this process (%p)\n", pCur));
+ VBoxGuestCloseSession(&g_DevExt, m_pSession);
+ }
+
+ m_pSession = NULL;
+ LogFlow(("org_virtualbox_VBoxGuestClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
+ }
+ else
+ LogFlow(("org_virtualbox_VBoxGuestClient::start: %p isn't org_virtualbox_VBoxGuest\n", pProvider));
+ }
+ return false;
+}
+
+
+/**
+ * Common worker for clientClose and VBoxDrvDarwinClose.
+ */
+/* static */ void org_virtualbox_VBoxGuestClient::sessionClose(RTPROCESS Process)
+{
+ /*
+ * Find the session and remove it from the hash table.
+ *
+ * Note! Only one session per process. (Both start() and
+ * VbgdDarwinOpen makes sure this is so.)
+ */
+ const unsigned iHash = SESSION_HASH(Process);
+ RTSpinlockAcquire(g_Spinlock);
+ PVBOXGUESTSESSION pSession = g_apSessionHashTab[iHash];
+ if (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ g_apSessionHashTab[iHash] = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ ASMAtomicDecS32(&g_cSessions);
+ }
+ else
+ {
+ PVBOXGUESTSESSION pPrev = pSession;
+ pSession = pSession->pNextHash;
+ while (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ pPrev->pNextHash = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ ASMAtomicDecS32(&g_cSessions);
+ break;
+ }
+
+ /* next */
+ pPrev = pSession;
+ pSession = pSession->pNextHash;
+ }
+ }
+ }
+ RTSpinlockRelease(g_Spinlock);
+ if (!pSession)
+ {
+ Log(("VBoxGuestClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
+ return;
+ }
+
+ /*
+ * Remove it from the client object.
+ */
+ org_virtualbox_VBoxGuestClient *pThis = (org_virtualbox_VBoxGuestClient *)pSession->pvVBoxGuestClient;
+ pSession->pvVBoxGuestClient = NULL;
+ if (pThis)
+ {
+ Assert(pThis->m_pSession == pSession);
+ pThis->m_pSession = NULL;
+ }
+
+ /*
+ * Close the session.
+ */
+ VBoxGuestCloseSession(&g_DevExt, pSession);
+}
+
+
+/**
+ * Client exits normally.
+ */
+IOReturn org_virtualbox_VBoxGuestClient::clientClose(void)
+{
+ LogFlow(("org_virtualbox_VBoxGuestClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
+ AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
+
+ /*
+ * Clean up the session if it's still around.
+ *
+ * We cannot rely 100% on close, and in the case of a dead client
+ * we'll end up hanging inside vm_map_remove() if we postpone it.
+ */
+ if (m_pSession)
+ {
+ sessionClose(RTProcSelf());
+ Assert(!m_pSession);
+ }
+
+ m_pProvider = NULL;
+ terminate();
+
+ return kIOReturnSuccess;
+}
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-freebsd.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-freebsd.c
index 1720abb2..1552f715 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-freebsd.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-freebsd.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c
new file mode 100644
index 00000000..122df9e7
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c
@@ -0,0 +1,448 @@
+/* $Id: VBoxGuest-haiku-stubs.c $ */
+/** @file
+ * VBoxGuest kernel module, Haiku Guest Additions, stubs.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * This file provides stubs for calling VBox runtime functions through the vboxguest module.
+ * It should be linked into any driver or module that uses the VBox runtime, except vboxguest
+ * itself (which contains the actual library and therefore doesn't need stubs to call it).
+ */
+
+#include "VBoxGuest-haiku.h"
+#include "VBoxGuestInternal.h"
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/mem.h>
+#include <iprt/asm.h>
+#include <iprt/mp.h>
+#include <iprt/power.h>
+#include <iprt/thread.h>
+
+// >>> file('/tmp/stubs.c', 'w').writelines([re.sub(r'^(?P<returntype>[^(]+) \(\*_(?P<functionname>[A-Za-z0-9_]+)\)\((?P<params>[^)]+)\);', lambda m: '%s %s(%s)\n{\n %sg_VBoxGuest->_%s(%s);\n}\n' % (m.group(1), m.group(2), m.group(3), ('return ' if m.group(1) != 'void' else ''), m.group(2), (', '.join(a.split(' ')[-1].replace('*', '') for a in m.group(3).split(',')) if m.group(3) != 'void' else '')), f) for f in functions])
+
+struct vboxguest_module_info *g_VBoxGuest;
+
+size_t RTLogBackdoorPrintf(const char *pszFormat, ...)
+{
+ va_list args;
+ size_t cb;
+
+ va_start(args, pszFormat);
+ cb = g_VBoxGuest->_RTLogBackdoorPrintf(pszFormat, args);
+ va_end(args);
+
+ return cb;
+}
+size_t RTLogBackdoorPrintfV(const char *pszFormat, va_list args)
+{
+ return g_VBoxGuest->_RTLogBackdoorPrintfV(pszFormat, args);
+}
+int RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
+{
+ return g_VBoxGuest->_RTLogSetDefaultInstanceThread(pLogger, uKey);
+}
+int RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv)
+{
+ return g_VBoxGuest->_RTMemAllocExTag(cb, cbAlignment, fFlags, pszTag, ppv);
+}
+void* RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
+{
+ return g_VBoxGuest->_RTMemContAlloc(pPhys, cb);
+}
+void RTMemContFree(void *pv, size_t cb)
+{
+ g_VBoxGuest->_RTMemContFree(pv, cb);
+}
+void RTMemFreeEx(void *pv, size_t cb)
+{
+ g_VBoxGuest->_RTMemFreeEx(pv, cb);
+}
+bool RTMpIsCpuPossible(RTCPUID idCpu)
+{
+ return g_VBoxGuest->_RTMpIsCpuPossible(idCpu);
+}
+int RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
+{
+ return g_VBoxGuest->_RTMpNotificationDeregister(pfnCallback, pvUser);
+}
+int RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
+{
+ return g_VBoxGuest->_RTMpNotificationRegister(pfnCallback, pvUser);
+}
+int RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ return g_VBoxGuest->_RTMpOnAll(pfnWorker, pvUser1, pvUser2);
+}
+int RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ return g_VBoxGuest->_RTMpOnOthers(pfnWorker, pvUser1, pvUser2);
+}
+int RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ return g_VBoxGuest->_RTMpOnSpecific(idCpu, pfnWorker, pvUser1, pvUser2);
+}
+int RTPowerNotificationDeregister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser)
+{
+ return g_VBoxGuest->_RTPowerNotificationDeregister(pfnCallback, pvUser);
+}
+int RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser)
+{
+ return g_VBoxGuest->_RTPowerNotificationRegister(pfnCallback, pvUser);
+}
+int RTPowerSignalEvent(RTPOWEREVENT enmEvent)
+{
+ return g_VBoxGuest->_RTPowerSignalEvent(enmEvent);
+}
+void RTR0AssertPanicSystem(void)
+{
+ g_VBoxGuest->_RTR0AssertPanicSystem();
+}
+int RTR0Init(unsigned fReserved)
+{
+ return g_VBoxGuest->_RTR0Init(fReserved);
+}
+void* RTR0MemObjAddress(RTR0MEMOBJ MemObj)
+{
+ return g_VBoxGuest->_RTR0MemObjAddress(MemObj);
+}
+RTR3PTR RTR0MemObjAddressR3(RTR0MEMOBJ MemObj)
+{
+ return g_VBoxGuest->_RTR0MemObjAddressR3(MemObj);
+}
+int RTR0MemObjAllocContTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocContTag(pMemObj, cb, fExecutable, pszTag);
+}
+int RTR0MemObjAllocLowTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocLowTag(pMemObj, cb, fExecutable, pszTag);
+}
+int RTR0MemObjAllocPageTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocPageTag(pMemObj, cb, fExecutable, pszTag);
+}
+int RTR0MemObjAllocPhysExTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocPhysExTag(pMemObj, cb, PhysHighest, uAlignment, pszTag);
+}
+int RTR0MemObjAllocPhysNCTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocPhysNCTag(pMemObj, cb, PhysHighest, pszTag);
+}
+int RTR0MemObjAllocPhysTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjAllocPhysTag(pMemObj, cb, PhysHighest, pszTag);
+}
+int RTR0MemObjEnterPhysTag(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjEnterPhysTag(pMemObj, Phys, cb, uCachePolicy, pszTag);
+}
+int RTR0MemObjFree(RTR0MEMOBJ MemObj, bool fFreeMappings)
+{
+ return g_VBoxGuest->_RTR0MemObjFree(MemObj, fFreeMappings);
+}
+RTHCPHYS RTR0MemObjGetPagePhysAddr(RTR0MEMOBJ MemObj, size_t iPage)
+{
+ return g_VBoxGuest->_RTR0MemObjGetPagePhysAddr(MemObj, iPage);
+}
+bool RTR0MemObjIsMapping(RTR0MEMOBJ MemObj)
+{
+ return g_VBoxGuest->_RTR0MemObjIsMapping(MemObj);
+}
+int RTR0MemObjLockKernelTag(PRTR0MEMOBJ pMemObj, void *pv, size_t cb, uint32_t fAccess, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjLockKernelTag(pMemObj, pv, cb, fAccess, pszTag);
+}
+int RTR0MemObjLockUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjLockUserTag(pMemObj, R3Ptr, cb, fAccess, R0Process, pszTag);
+}
+int RTR0MemObjMapKernelExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt, size_t offSub, size_t cbSub, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjMapKernelExTag(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt, offSub, cbSub, pszTag);
+}
+int RTR0MemObjMapKernelTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjMapKernelTag(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt, pszTag);
+}
+int RTR0MemObjMapUserTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjMapUserTag(pMemObj, MemObjToMap, R3PtrFixed, uAlignment, fProt, R0Process, pszTag);
+}
+int RTR0MemObjProtect(RTR0MEMOBJ hMemObj, size_t offSub, size_t cbSub, uint32_t fProt)
+{
+ return g_VBoxGuest->_RTR0MemObjProtect(hMemObj, offSub, cbSub, fProt);
+}
+int RTR0MemObjReserveKernelTag(PRTR0MEMOBJ pMemObj, void *pvFixed, size_t cb, size_t uAlignment, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjReserveKernelTag(pMemObj, pvFixed, cb, uAlignment, pszTag);
+}
+int RTR0MemObjReserveUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process, const char *pszTag)
+{
+ return g_VBoxGuest->_RTR0MemObjReserveUserTag(pMemObj, R3PtrFixed, cb, uAlignment, R0Process, pszTag);
+}
+size_t RTR0MemObjSize(RTR0MEMOBJ MemObj)
+{
+ return g_VBoxGuest->_RTR0MemObjSize(MemObj);
+}
+RTR0PROCESS RTR0ProcHandleSelf(void)
+{
+ return g_VBoxGuest->_RTR0ProcHandleSelf();
+}
+void RTR0Term(void)
+{
+ g_VBoxGuest->_RTR0Term();
+}
+void RTR0TermForced(void)
+{
+ g_VBoxGuest->_RTR0TermForced();
+}
+RTPROCESS RTProcSelf(void)
+{
+ return g_VBoxGuest->_RTProcSelf();
+}
+uint32_t RTSemEventGetResolution(void)
+{
+ return g_VBoxGuest->_RTSemEventGetResolution();
+}
+uint32_t RTSemEventMultiGetResolution(void)
+{
+ return g_VBoxGuest->_RTSemEventMultiGetResolution();
+}
+int RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+ return g_VBoxGuest->_RTSemEventMultiWaitEx(hEventMultiSem, fFlags, uTimeout);
+}
+int RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return g_VBoxGuest->_RTSemEventMultiWaitExDebug(hEventMultiSem, fFlags, uTimeout, uId, pszFile, iLine, pszFunction);
+}
+int RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
+{
+ return g_VBoxGuest->_RTSemEventWaitEx(hEventSem, fFlags, uTimeout);
+}
+int RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return g_VBoxGuest->_RTSemEventWaitExDebug(hEventSem, fFlags, uTimeout, uId, pszFile, iLine, pszFunction);
+}
+bool RTThreadIsInInterrupt(RTTHREAD hThread)
+{
+ return g_VBoxGuest->_RTThreadIsInInterrupt(hThread);
+}
+void RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
+{
+ g_VBoxGuest->_RTThreadPreemptDisable(pState);
+}
+bool RTThreadPreemptIsEnabled(RTTHREAD hThread)
+{
+ return g_VBoxGuest->_RTThreadPreemptIsEnabled(hThread);
+}
+bool RTThreadPreemptIsPending(RTTHREAD hThread)
+{
+ return g_VBoxGuest->_RTThreadPreemptIsPending(hThread);
+}
+bool RTThreadPreemptIsPendingTrusty(void)
+{
+ return g_VBoxGuest->_RTThreadPreemptIsPendingTrusty();
+}
+bool RTThreadPreemptIsPossible(void)
+{
+ return g_VBoxGuest->_RTThreadPreemptIsPossible();
+}
+void RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
+{
+ g_VBoxGuest->_RTThreadPreemptRestore(pState);
+}
+uint32_t RTTimerGetSystemGranularity(void)
+{
+ return g_VBoxGuest->_RTTimerGetSystemGranularity();
+}
+int RTTimerReleaseSystemGranularity(uint32_t u32Granted)
+{
+ return g_VBoxGuest->_RTTimerReleaseSystemGranularity(u32Granted);
+}
+int RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
+{
+ return g_VBoxGuest->_RTTimerRequestSystemGranularity(u32Request, pu32Granted);
+}
+void RTSpinlockAcquire(RTSPINLOCK Spinlock)
+{
+ g_VBoxGuest->_RTSpinlockAcquire(Spinlock);
+}
+void RTSpinlockRelease(RTSPINLOCK Spinlock)
+{
+ g_VBoxGuest->_RTSpinlockRelease(Spinlock);
+}
+void RTSpinlockReleaseNoInts(RTSPINLOCK Spinlock)
+{
+ g_VBoxGuest->_RTSpinlockReleaseNoInts(Spinlock);
+}
+void* RTMemTmpAllocTag(size_t cb, const char *pszTag)
+{
+ return g_VBoxGuest->_RTMemTmpAllocTag(cb, pszTag);
+}
+void RTMemTmpFree(void *pv)
+{
+ g_VBoxGuest->_RTMemTmpFree(pv);
+}
+PRTLOGGER RTLogDefaultInstance(void)
+{
+ return g_VBoxGuest->_RTLogDefaultInstance();
+}
+PRTLOGGER RTLogRelDefaultInstance(void)
+{
+ return g_VBoxGuest->_RTLogRelDefaultInstance();
+}
+int RTErrConvertToErrno(int iErr)
+{
+ return g_VBoxGuest->_RTErrConvertToErrno(iErr);
+}
+int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, void *pvData, size_t cbData, size_t *pcbDataReturned)
+{
+ return g_VBoxGuest->_VBoxGuestCommonIOCtl(iFunction, pDevExt, pSession, pvData, cbData, pcbDataReturned);
+}
+int VBoxGuestCreateUserSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession)
+{
+ return g_VBoxGuest->_VBoxGuestCreateUserSession(pDevExt, ppSession);
+}
+void VBoxGuestCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ g_VBoxGuest->_VBoxGuestCloseSession(pDevExt, pSession);
+}
+void* VBoxGuestIDCOpen(uint32_t *pu32Version)
+{
+ return g_VBoxGuest->_VBoxGuestIDCOpen(pu32Version);
+}
+int VBoxGuestIDCClose(void *pvSession)
+{
+ return g_VBoxGuest->_VBoxGuestIDCClose(pvSession);
+}
+int VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
+{
+ return g_VBoxGuest->_VBoxGuestIDCCall(pvSession, iCmd, pvData, cbData, pcbDataReturned);
+}
+void RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ g_VBoxGuest->_RTAssertMsg1Weak(pszExpr, uLine, pszFile, pszFunction);
+}
+void RTAssertMsg2Weak(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ RTAssertMsg2WeakV(pszFormat, va);
+ va_end(va);
+}
+void RTAssertMsg2WeakV(const char *pszFormat, va_list va)
+{
+ g_VBoxGuest->_RTAssertMsg2WeakV(pszFormat, va);
+}
+bool RTAssertShouldPanic(void)
+{
+ return g_VBoxGuest->_RTAssertShouldPanic();
+}
+int RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
+{
+ return g_VBoxGuest->_RTSemFastMutexCreate(phFastMtx);
+}
+int RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
+{
+ return g_VBoxGuest->_RTSemFastMutexDestroy(hFastMtx);
+}
+int RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
+{
+ return g_VBoxGuest->_RTSemFastMutexRelease(hFastMtx);
+}
+int RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
+{
+ return g_VBoxGuest->_RTSemFastMutexRequest(hFastMtx);
+}
+int RTSemMutexCreate(PRTSEMMUTEX phFastMtx)
+{
+ return g_VBoxGuest->_RTSemMutexCreate(phFastMtx);
+}
+int RTSemMutexDestroy(RTSEMMUTEX hFastMtx)
+{
+ return g_VBoxGuest->_RTSemMutexDestroy(hFastMtx);
+}
+int RTSemMutexRelease(RTSEMMUTEX hFastMtx)
+{
+ return g_VBoxGuest->_RTSemMutexRelease(hFastMtx);
+}
+int RTSemMutexRequest(RTSEMMUTEX hFastMtx, RTMSINTERVAL cMillies)
+{
+ return g_VBoxGuest->_RTSemMutexRequest(hFastMtx, cMillies);
+}
+int RTHeapSimpleRelocate(RTHEAPSIMPLE hHeap, uintptr_t offDelta)
+{
+ return g_VBoxGuest->_RTHeapSimpleRelocate(hHeap, offDelta);
+}
+int RTHeapOffsetInit(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory)
+{
+ return g_VBoxGuest->_RTHeapOffsetInit(phHeap, pvMemory, cbMemory);
+}
+int RTHeapSimpleInit(PRTHEAPSIMPLE pHeap, void *pvMemory, size_t cbMemory)
+{
+ return g_VBoxGuest->_RTHeapSimpleInit(pHeap, pvMemory, cbMemory);
+}
+void* RTHeapOffsetAlloc(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment)
+{
+ return g_VBoxGuest->_RTHeapOffsetAlloc(hHeap, cb, cbAlignment);
+}
+void* RTHeapSimpleAlloc(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment)
+{
+ return g_VBoxGuest->_RTHeapSimpleAlloc(Heap, cb, cbAlignment);
+}
+void RTHeapOffsetFree(RTHEAPOFFSET hHeap, void *pv)
+{
+ g_VBoxGuest->_RTHeapOffsetFree(hHeap, pv);
+}
+void RTHeapSimpleFree(RTHEAPSIMPLE Heap, void *pv)
+{
+ g_VBoxGuest->_RTHeapSimpleFree(Heap, pv);
+}
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.c
new file mode 100644
index 00000000..5aa31702
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.c
@@ -0,0 +1,553 @@
+/* $Id: VBoxGuest-haiku.c $ */
+/** @file
+ * VBoxGuest kernel module, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define IN_VBOXGUEST
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <OS.h>
+#include <Drivers.h>
+#include <KernelExport.h>
+#include <PCI.h>
+
+#include "VBoxGuest-haiku.h"
+#include "VBoxGuestInternal.h"
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/mem.h>
+#include <iprt/memobj.h>
+#include <iprt/asm.h>
+#include <iprt/timer.h>
+#include <iprt/heap.h>
+
+#define MODULE_NAME VBOXGUEST_MODULE_NAME
+
+/*
+ * IRQ related functions.
+ */
+static void VBoxGuestHaikuRemoveIRQ(void *pvState);
+static int VBoxGuestHaikuAddIRQ(void *pvState);
+static int32 VBoxGuestHaikuISR(void *pvState);
+
+/*
+ * Available functions for kernel drivers.
+ */
+DECLVBGL(int) VBoxGuestHaikuServiceCall(void *pvSession, unsigned uCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+DECLVBGL(void *) VBoxGuestHaikuServiceOpen(uint32_t *pu32Version);
+DECLVBGL(int) VBoxGuestHaikuServiceClose(void *pvSession);
+DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version);
+DECLVBGL(int) VBoxGuestIDCClose(void *pvSession);
+DECLVBGL(int) VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+
+static status_t std_ops(int32 op, ...);
+
+static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
+
+int32 api_version = B_CUR_DRIVER_API_VERSION;
+
+/** List of cloned device. Managed by the kernel. */
+//static struct clonedevs *g_pVBoxGuestHaikuClones;
+/** The dev_clone event handler tag. */
+//static eventhandler_tag g_VBoxGuestHaikuEHTag;
+/** selinfo structure used for polling. */
+//static struct selinfo g_SelInfo;
+/** PCI Bus Manager Module */
+static pci_module_info *gPCI;
+
+static struct vboxguest_module_info g_VBoxGuest =
+{
+ {
+ MODULE_NAME,
+ 0,
+ std_ops
+ },
+ { 0 },
+ { 0 },
+ 0,
+ RTLogBackdoorPrintf,
+ RTLogBackdoorPrintfV,
+ RTLogSetDefaultInstanceThread,
+ RTMemAllocExTag,
+ RTMemContAlloc,
+ RTMemContFree,
+ RTMemFreeEx,
+ RTMpIsCpuPossible,
+ RTMpNotificationDeregister,
+ RTMpNotificationRegister,
+ RTMpOnAll,
+ RTMpOnOthers,
+ RTMpOnSpecific,
+ RTPowerNotificationDeregister,
+ RTPowerNotificationRegister,
+ RTPowerSignalEvent,
+ RTR0AssertPanicSystem,
+ RTR0Init,
+ RTR0MemObjAddress,
+ RTR0MemObjAddressR3,
+ RTR0MemObjAllocContTag,
+ RTR0MemObjAllocLowTag,
+ RTR0MemObjAllocPageTag,
+ RTR0MemObjAllocPhysExTag,
+ RTR0MemObjAllocPhysNCTag,
+ RTR0MemObjAllocPhysTag,
+ RTR0MemObjEnterPhysTag,
+ RTR0MemObjFree,
+ RTR0MemObjGetPagePhysAddr,
+ RTR0MemObjIsMapping,
+ RTR0MemObjLockKernelTag,
+ RTR0MemObjLockUserTag,
+ RTR0MemObjMapKernelExTag,
+ RTR0MemObjMapKernelTag,
+ RTR0MemObjMapUserTag,
+ RTR0MemObjProtect,
+ RTR0MemObjReserveKernelTag,
+ RTR0MemObjReserveUserTag,
+ RTR0MemObjSize,
+ RTR0ProcHandleSelf,
+ RTR0Term,
+ RTR0TermForced,
+ RTProcSelf,
+ RTSemEventGetResolution,
+ RTSemEventMultiGetResolution,
+ RTSemEventMultiWaitEx,
+ RTSemEventMultiWaitExDebug,
+ RTSemEventWaitEx,
+ RTSemEventWaitExDebug,
+ RTThreadIsInInterrupt,
+ RTThreadPreemptDisable,
+ RTThreadPreemptIsEnabled,
+ RTThreadPreemptIsPending,
+ RTThreadPreemptIsPendingTrusty,
+ RTThreadPreemptIsPossible,
+ RTThreadPreemptRestore,
+ RTTimerGetSystemGranularity,
+ RTTimerReleaseSystemGranularity,
+ RTTimerRequestSystemGranularity,
+ RTSpinlockAcquire,
+ RTSpinlockRelease,
+ RTSpinlockReleaseNoInts,
+ RTMemTmpAllocTag,
+ RTMemTmpFree,
+ RTLogDefaultInstance,
+ RTLogRelDefaultInstance,
+ RTErrConvertToErrno,
+ VBoxGuestCommonIOCtl,
+ VBoxGuestCreateUserSession,
+ VBoxGuestCloseSession,
+ VBoxGuestIDCOpen,
+ VBoxGuestIDCClose,
+ VBoxGuestIDCCall,
+ RTAssertMsg1Weak,
+ RTAssertMsg2Weak,
+ RTAssertMsg2WeakV,
+ RTAssertShouldPanic,
+ RTSemFastMutexCreate,
+ RTSemFastMutexDestroy,
+ RTSemFastMutexRelease,
+ RTSemFastMutexRequest,
+ RTSemMutexCreate,
+ RTSemMutexDestroy,
+ RTSemMutexRelease,
+ RTSemMutexRequest,
+ RTHeapSimpleRelocate,
+ RTHeapOffsetInit,
+ RTHeapSimpleInit,
+ RTHeapOffsetAlloc,
+ RTHeapSimpleAlloc,
+ RTHeapOffsetFree,
+ RTHeapSimpleFree
+};
+
+#if 0
+/**
+ * DEVFS event handler.
+ */
+static void VBoxGuestHaikuClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev)
+{
+ int iUnit;
+ int rc;
+
+ Log(("VBoxGuestHaikuClone: pszName=%s ppDev=%p\n", pszName, ppDev));
+
+ /*
+ * One device node per user, si_drv1 points to the session.
+ * /dev/vboxguest<N> where N = {0...255}.
+ */
+ if (!ppDev)
+ return;
+ if (strcmp(pszName, "vboxguest") == 0)
+ iUnit = -1;
+ else if (dev_stdclone(pszName, NULL, "vboxguest", &iUnit) != 1)
+ return;
+ if (iUnit >= 256)
+ {
+ Log(("VBoxGuestHaikuClone: iUnit=%d >= 256 - rejected\n", iUnit));
+ return;
+ }
+
+ Log(("VBoxGuestHaikuClone: pszName=%s iUnit=%d\n", pszName, iUnit));
+
+ rc = clone_create(&g_pVBoxGuestHaikuClones, &g_VBoxGuestHaikuDeviceHooks, &iUnit, ppDev, 0);
+ Log(("VBoxGuestHaikuClone: clone_create -> %d; iUnit=%d\n", rc, iUnit));
+ if (rc)
+ {
+ *ppDev = make_dev(&g_VBoxGuestHaikuDeviceHooks,
+ iUnit,
+ UID_ROOT,
+ GID_WHEEL,
+ 0644,
+ "vboxguest%d", iUnit);
+ if (*ppDev)
+ {
+ dev_ref(*ppDev);
+ (*ppDev)->si_flags |= SI_CHEAPCLONE;
+ Log(("VBoxGuestHaikuClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
+ *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2));
+ (*ppDev)->si_drv1 = (*ppDev)->si_drv2 = NULL;
+ }
+ else
+ Log(("VBoxGuestHaikuClone: make_dev iUnit=%d failed\n", iUnit));
+ }
+ else
+ Log(("VBoxGuestHaikuClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
+ *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2));
+}
+#endif
+
+
+static status_t VBoxGuestHaikuDetach(void)
+{
+ struct VBoxGuestDeviceState *pState = &sState;
+
+ if (cUsers > 0)
+ return EBUSY;
+
+ /*
+ * Reverse what we did in VBoxGuestHaikuAttach.
+ */
+ VBoxGuestHaikuRemoveIRQ(pState);
+
+ if (pState->iVMMDevMemAreaId)
+ delete_area(pState->iVMMDevMemAreaId);
+
+ VBoxGuestDeleteDevExt(&g_DevExt);
+
+#ifdef DO_LOG
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogSetDefaultInstance(NULL);
+// RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+
+ RTSpinlockDestroy(g_Spinlock);
+ g_Spinlock = NIL_RTSPINLOCK;
+
+ RTR0Term();
+ return B_OK;
+}
+
+
+/**
+ * Interrupt service routine.
+ *
+ * @returns Whether the interrupt was from VMMDev.
+ * @param pvState Opaque pointer to the device state.
+ */
+static int32 VBoxGuestHaikuISR(void *pvState)
+{
+ LogFlow((MODULE_NAME ":VBoxGuestHaikuISR pvState=%p\n", pvState));
+
+ bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
+ if (fOurIRQ)
+ return B_HANDLED_INTERRUPT;
+ return B_UNHANDLED_INTERRUPT;
+}
+
+
+void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
+{
+ LogFlow((MODULE_NAME "::NativeISRMousePollEvent:\n"));
+
+ status_t err = B_OK;
+ //dprintf(MODULE_NAME ": isr mouse\n");
+
+ /*
+ * Wake up poll waiters.
+ */
+ //selwakeup(&g_SelInfo);
+ //XXX:notify_select_event();
+ RTSpinlockAcquire(g_Spinlock);
+
+ if (sState.selectSync)
+ {
+ //dprintf(MODULE_NAME ": isr mouse: notify\n");
+ notify_select_event(sState.selectSync, sState.selectEvent);
+ sState.selectEvent = (uint8_t)0;
+ sState.selectRef = (uint32_t)0;
+ sState.selectSync = NULL;
+ }
+ else
+ err = B_ERROR;
+
+ RTSpinlockRelease(g_Spinlock);
+}
+
+
+/**
+ * Sets IRQ for VMMDev.
+ *
+ * @returns Haiku error code.
+ * @param pvState Pointer to the state info structure.
+ */
+static int VBoxGuestHaikuAddIRQ(void *pvState)
+{
+ status_t err;
+ struct VBoxGuestDeviceState *pState = (struct VBoxGuestDeviceState *)pvState;
+
+ AssertReturn(pState, VERR_INVALID_PARAMETER);
+
+ err = install_io_interrupt_handler(pState->iIrqResId, VBoxGuestHaikuISR, pState, 0);
+ if (err == B_OK)
+ return VINF_SUCCESS;
+ return VERR_DEV_IO_ERROR;
+}
+
+
+/**
+ * Removes IRQ for VMMDev.
+ *
+ * @param pvState Opaque pointer to the state info structure.
+ */
+static void VBoxGuestHaikuRemoveIRQ(void *pvState)
+{
+ struct VBoxGuestDeviceState *pState = (struct VBoxGuestDeviceState *)pvState;
+ AssertPtr(pState);
+
+ remove_io_interrupt_handler(pState->iIrqResId, VBoxGuestHaikuISR, pState);
+}
+
+
+static status_t VBoxGuestHaikuAttach(const pci_info *pDevice)
+{
+ status_t status;
+ int rc = VINF_SUCCESS;
+ int iResId = 0;
+ struct VBoxGuestDeviceState *pState = &sState;
+ static const char *const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ PRTLOGGER pRelLogger;
+
+ AssertReturn(pDevice, B_BAD_VALUE);
+
+ cUsers = 0;
+
+ /*
+ * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
+ */
+ rc = RTR0Init(0);
+ if (RT_FAILURE(rc))
+ {
+ /** @todo r=ramshankar: use dprintf here. */
+ LogFunc(("RTR0Init failed.\n"));
+ return ENXIO;
+ }
+
+ rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestHaiku");
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VBoxGuestHaikuAttach: RTSpinlock create failed. rc=%Rrc\n", rc));
+ return ENXIO;
+ }
+
+#ifdef DO_LOG
+ /*
+ * Create the release log.
+ * (We do that here instead of common code because we want to log
+ * early failures using the LogRel macro.)
+ */
+ rc = RTLogCreate(&pRelLogger, 0 | RTLOGFLAGS_PREFIX_THREAD /* fFlags */, "all",
+ "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
+ RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
+ dprintf(MODULE_NAME ": RTLogCreate: %d\n", rc);
+ if (RT_SUCCESS(rc))
+ {
+ //RTLogGroupSettings(pRelLogger, g_szLogGrp);
+ //RTLogFlags(pRelLogger, g_szLogFlags);
+ //RTLogDestinations(pRelLogger, "/var/log/vboxguest.log");
+ RTLogRelSetDefaultInstance(pRelLogger);
+ RTLogSetDefaultInstance(pRelLogger); //XXX
+ }
+#endif
+
+ /*
+ * Allocate I/O port resource.
+ */
+ pState->uIOPortBase = pDevice->u.h0.base_registers[0];
+ /* @todo check flags for IO? */
+ if (pState->uIOPortBase)
+ {
+ /*
+ * Map the MMIO region.
+ */
+ uint32 phys = pDevice->u.h0.base_registers[1];
+ /* @todo Check flags for mem? */
+ pState->VMMDevMemSize = pDevice->u.h0.base_register_sizes[1];
+ pState->iVMMDevMemAreaId = map_physical_memory("VirtualBox Guest MMIO", phys, pState->VMMDevMemSize,
+ B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
+ &pState->pMMIOBase);
+ if (pState->iVMMDevMemAreaId > 0 && pState->pMMIOBase)
+ {
+ /*
+ * Call the common device extension initializer.
+ */
+ rc = VBoxGuestInitDevExt(&g_DevExt, pState->uIOPortBase, pState->pMMIOBase, pState->VMMDevMemSize,
+#if ARCH_BITS == 64
+ VBOXOSTYPE_Haiku_x64,
+#else
+ VBOXOSTYPE_Haiku,
+#endif
+ VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add IRQ of VMMDev.
+ */
+ pState->iIrqResId = pDevice->u.h0.interrupt_line;
+ rc = VBoxGuestHaikuAddIRQ(pState);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel((MODULE_NAME ": loaded successfully\n"));
+ return B_OK;
+ }
+
+ LogRel((MODULE_NAME ":VBoxGuestInitDevExt failed.\n"));
+ VBoxGuestDeleteDevExt(&g_DevExt);
+ }
+ else
+ LogRel((MODULE_NAME ":VBoxGuestHaikuAddIRQ failed.\n"));
+ }
+ else
+ LogRel((MODULE_NAME ":MMIO region setup failed.\n"));
+ }
+ else
+ LogRel((MODULE_NAME ":IOport setup failed.\n"));
+
+ RTR0Term();
+ return ENXIO;
+}
+
+
+static status_t VBoxGuestHaikuProbe(pci_info *pDevice)
+{
+ if ((pDevice->vendor_id == VMMDEV_VENDORID) && (pDevice->device_id == VMMDEV_DEVICEID))
+ return B_OK;
+
+ return ENXIO;
+}
+
+
+status_t init_module(void)
+{
+ status_t err = B_ENTRY_NOT_FOUND;
+ pci_info info;
+ int ix = 0;
+
+ err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+ if (err != B_OK)
+ return err;
+
+ while ((*gPCI->get_nth_pci_info)(ix++, &info) == B_OK)
+ {
+ if (VBoxGuestHaikuProbe(&info) == 0)
+ {
+ /* We found it */
+ err = VBoxGuestHaikuAttach(&info);
+ return err;
+ }
+ }
+
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+void uninit_module(void)
+{
+ VBoxGuestHaikuDetach();
+ put_module(B_PCI_MODULE_NAME);
+}
+
+
+static status_t std_ops(int32 op, ...)
+{
+ switch (op)
+ {
+ case B_MODULE_INIT:
+ return init_module();
+
+ case B_MODULE_UNINIT:
+ {
+ uninit_module();
+ return B_OK;
+ }
+
+ default:
+ return B_ERROR;
+ }
+}
+
+
+_EXPORT module_info *modules[] =
+{
+ (module_info *)&g_VBoxGuest,
+ NULL
+};
+
+/* Common code that depend on g_DevExt. */
+#include "VBoxGuestIDC-unix.c.h"
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.h
new file mode 100644
index 00000000..d577448c
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku.h
@@ -0,0 +1,226 @@
+/* $Id: VBoxGuest-haiku.h $ */
+/** @file
+ * VBoxGuest kernel module, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef ___VBoxGuest_haiku_h
+#define ___VBoxGuest_haiku_h
+
+#include <OS.h>
+#include <Drivers.h>
+#include <drivers/module.h>
+
+#include "VBoxGuestInternal.h"
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/mem.h>
+#include <iprt/asm.h>
+#include <iprt/mp.h>
+#include <iprt/power.h>
+#include <iprt/thread.h>
+
+/** The module name. */
+#define VBOXGUEST_MODULE_NAME "generic/vboxguest"
+
+struct VBoxGuestDeviceState
+{
+ /** Resource ID of the I/O port */
+ int iIOPortResId;
+ /** Pointer to the I/O port resource. */
+// struct resource *pIOPortRes;
+ /** Start address of the IO Port. */
+ uint16_t uIOPortBase;
+ /** Resource ID of the MMIO area */
+ area_id iVMMDevMemAreaId;
+ /** Pointer to the MMIO resource. */
+// struct resource *pVMMDevMemRes;
+ /** Handle of the MMIO resource. */
+// bus_space_handle_t VMMDevMemHandle;
+ /** Size of the memory area. */
+ size_t VMMDevMemSize;
+ /** Mapping of the register space */
+ void *pMMIOBase;
+ /** IRQ number */
+ int iIrqResId;
+ /** IRQ resource handle. */
+// struct resource *pIrqRes;
+ /** Pointer to the IRQ handler. */
+// void *pfnIrqHandler;
+ /** VMMDev version */
+ uint32_t u32Version;
+
+ /** The (only) select data we wait on. */
+ //XXX: should leave in pSession ?
+ uint8_t selectEvent;
+ uint32_t selectRef;
+ void *selectSync;
+};
+
+struct vboxguest_module_info
+{
+ module_info module;
+
+ VBOXGUESTDEVEXT devExt;
+ struct VBoxGuestDeviceState _sState;
+ volatile uint32_t _cUsers;
+
+ size_t(*_RTLogBackdoorPrintf)(const char *pszFormat, ...);
+ size_t(*_RTLogBackdoorPrintfV)(const char *pszFormat, va_list args);
+ int (*_RTLogSetDefaultInstanceThread)(PRTLOGGER pLogger, uintptr_t uKey);
+ int (*_RTMemAllocExTag)(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv);
+ void* (*_RTMemContAlloc)(PRTCCPHYS pPhys, size_t cb);
+ void (*_RTMemContFree)(void *pv, size_t cb);
+ void (*_RTMemFreeEx)(void *pv, size_t cb);
+ bool (*_RTMpIsCpuPossible)(RTCPUID idCpu);
+ int (*_RTMpNotificationDeregister)(PFNRTMPNOTIFICATION pfnCallback, void *pvUser);
+ int (*_RTMpNotificationRegister)(PFNRTMPNOTIFICATION pfnCallback, void *pvUser);
+ int (*_RTMpOnAll)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+ int (*_RTMpOnOthers)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+ int (*_RTMpOnSpecific)(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+ int (*_RTPowerNotificationDeregister)(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser);
+ int (*_RTPowerNotificationRegister)(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser);
+ int (*_RTPowerSignalEvent)(RTPOWEREVENT enmEvent);
+ void (*_RTR0AssertPanicSystem)(void);
+ int (*_RTR0Init)(unsigned fReserved);
+ void* (*_RTR0MemObjAddress)(RTR0MEMOBJ MemObj);
+ RTR3PTR(*_RTR0MemObjAddressR3)(RTR0MEMOBJ MemObj);
+ int (*_RTR0MemObjAllocContTag)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag);
+ int (*_RTR0MemObjAllocLowTag)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag);
+ int (*_RTR0MemObjAllocPageTag)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag);
+ int (*_RTR0MemObjAllocPhysExTag)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment, const char *pszTag);
+ int (*_RTR0MemObjAllocPhysNCTag)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag);
+ int (*_RTR0MemObjAllocPhysTag)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag);
+ int (*_RTR0MemObjEnterPhysTag)(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy, const char *pszTag);
+ int (*_RTR0MemObjFree)(RTR0MEMOBJ MemObj, bool fFreeMappings);
+ RTHCPHYS(*_RTR0MemObjGetPagePhysAddr)(RTR0MEMOBJ MemObj, size_t iPage);
+ bool (*_RTR0MemObjIsMapping)(RTR0MEMOBJ MemObj);
+ int (*_RTR0MemObjLockKernelTag)(PRTR0MEMOBJ pMemObj, void *pv, size_t cb, uint32_t fAccess, const char *pszTag);
+ int (*_RTR0MemObjLockUserTag)(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess,
+ RTR0PROCESS R0Process, const char *pszTag);
+ int (*_RTR0MemObjMapKernelExTag)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub, const char *pszTag);
+ int (*_RTR0MemObjMapKernelTag)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed,
+ size_t uAlignment, unsigned fProt, const char *pszTag);
+ int (*_RTR0MemObjMapUserTag)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed,
+ size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, const char *pszTag);
+ int (*_RTR0MemObjProtect)(RTR0MEMOBJ hMemObj, size_t offSub, size_t cbSub, uint32_t fProt);
+ int (*_RTR0MemObjReserveKernelTag)(PRTR0MEMOBJ pMemObj, void *pvFixed, size_t cb, size_t uAlignment, const char *pszTag);
+ int (*_RTR0MemObjReserveUserTag)(PRTR0MEMOBJ pMemObj, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment,
+ RTR0PROCESS R0Process, const char *pszTag);
+ size_t(*_RTR0MemObjSize)(RTR0MEMOBJ MemObj);
+ RTR0PROCESS(*_RTR0ProcHandleSelf)(void);
+ void (*_RTR0Term)(void);
+ void (*_RTR0TermForced)(void);
+ RTPROCESS(*_RTProcSelf)(void);
+ uint32_t(*_RTSemEventGetResolution)(void);
+ uint32_t(*_RTSemEventMultiGetResolution)(void);
+ int (*_RTSemEventMultiWaitEx)(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout);
+ int (*_RTSemEventMultiWaitExDebug)(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL);
+ int (*_RTSemEventWaitEx)(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout);
+ int (*_RTSemEventWaitExDebug)(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL);
+ bool (*_RTThreadIsInInterrupt)(RTTHREAD hThread);
+ void (*_RTThreadPreemptDisable)(PRTTHREADPREEMPTSTATE pState);
+ bool (*_RTThreadPreemptIsEnabled)(RTTHREAD hThread);
+ bool (*_RTThreadPreemptIsPending)(RTTHREAD hThread);
+ bool (*_RTThreadPreemptIsPendingTrusty)(void);
+ bool (*_RTThreadPreemptIsPossible)(void);
+ void (*_RTThreadPreemptRestore)(PRTTHREADPREEMPTSTATE pState);
+ uint32_t(*_RTTimerGetSystemGranularity)(void);
+ int (*_RTTimerReleaseSystemGranularity)(uint32_t u32Granted);
+ int (*_RTTimerRequestSystemGranularity)(uint32_t u32Request, uint32_t *pu32Granted);
+ void (*_RTSpinlockAcquire)(RTSPINLOCK Spinlock);
+ void (*_RTSpinlockRelease)(RTSPINLOCK Spinlock);
+ void (*_RTSpinlockReleaseNoInts)(RTSPINLOCK Spinlock);
+ void* (*_RTMemTmpAllocTag)(size_t cb, const char *pszTag);
+ void (*_RTMemTmpFree)(void *pv);
+ PRTLOGGER(*_RTLogDefaultInstance)(void);
+ PRTLOGGER(*_RTLogRelDefaultInstance)(void);
+ int (*_RTErrConvertToErrno)(int iErr);
+ int (*_VBoxGuestCommonIOCtl)(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ void *pvData, size_t cbData, size_t *pcbDataReturned);
+ int (*_VBoxGuestCreateUserSession)(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession);
+ void (*_VBoxGuestCloseSession)(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
+ void* (*_VBoxGuestIDCOpen)(uint32_t *pu32Version);
+ int (*_VBoxGuestIDCClose)(void *pvSession);
+ int (*_VBoxGuestIDCCall)(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+ void (*_RTAssertMsg1Weak)(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction);
+ void (*_RTAssertMsg2Weak)(const char *pszFormat, ...);
+ void (*_RTAssertMsg2WeakV)(const char *pszFormat, va_list va);
+ bool (*_RTAssertShouldPanic)(void);
+ int (*_RTSemFastMutexCreate)(PRTSEMFASTMUTEX phFastMtx);
+ int (*_RTSemFastMutexDestroy)(RTSEMFASTMUTEX hFastMtx);
+ int (*_RTSemFastMutexRelease)(RTSEMFASTMUTEX hFastMtx);
+ int (*_RTSemFastMutexRequest)(RTSEMFASTMUTEX hFastMtx);
+ int (*_RTSemMutexCreate)(PRTSEMMUTEX phFastMtx);
+ int (*_RTSemMutexDestroy)(RTSEMMUTEX hFastMtx);
+ int (*_RTSemMutexRelease)(RTSEMMUTEX hFastMtx);
+ int (*_RTSemMutexRequest)(RTSEMMUTEX hFastMtx, RTMSINTERVAL cMillies);
+ int (*_RTHeapSimpleRelocate)(RTHEAPSIMPLE hHeap, uintptr_t offDelta);
+ int (*_RTHeapOffsetInit)(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory);
+ int (*_RTHeapSimpleInit)(PRTHEAPSIMPLE pHeap, void *pvMemory, size_t cbMemory);
+ void* (*_RTHeapOffsetAlloc)(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment);
+ void* (*_RTHeapSimpleAlloc)(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment);
+ void (*_RTHeapOffsetFree)(RTHEAPOFFSET hHeap, void *pv);
+ void (*_RTHeapSimpleFree)(RTHEAPSIMPLE Heap, void *pv);
+};
+
+
+#ifdef IN_VBOXGUEST
+#define g_DevExt (g_VBoxGuest.devExt)
+#define cUsers (g_VBoxGuest._cUsers)
+#define sState (g_VBoxGuest._sState)
+#else
+#define g_DevExt (g_VBoxGuest->devExt)
+#define cUsers (g_VBoxGuest->_cUsers)
+#define sState (g_VBoxGuest->_sState)
+extern struct vboxguest_module_info *g_VBoxGuest;
+#endif
+
+#endif /* ___VBoxGuest_haiku_h */
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
index b4270bae..a4824893 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
@@ -1,4 +1,4 @@
-/* $Rev: 80789 $ */
+/* $Rev: 88900 $ */
/** @file
* VBoxGuest - Linux specifics.
*
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -196,7 +196,11 @@ static struct miscdevice g_MiscDeviceUser =
/** PCI hotplug structure. */
-static const struct pci_device_id __devinitdata g_VBoxGuestPciId[] =
+static const struct pci_device_id
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+__devinitdata
+#endif
+g_VBoxGuestPciId[] =
{
{
vendor: VMMDEV_VENDORID,
@@ -936,9 +940,9 @@ void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
* Wake up everyone that's in a poll() and post anyone that has
* subscribed to async notifications.
*/
- Log(("VBoxGuestNativeISRMousePollEvent: wake_up_all\n"));
+ Log3(("VBoxGuestNativeISRMousePollEvent: wake_up_all\n"));
wake_up_all(&g_PollEventQueue);
- Log(("VBoxGuestNativeISRMousePollEvent: kill_fasync\n"));
+ Log3(("VBoxGuestNativeISRMousePollEvent: kill_fasync\n"));
kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
/* Report events to the kernel input device */
@@ -957,7 +961,7 @@ void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
# endif
}
#endif
- Log(("VBoxGuestNativeISRMousePollEvent: done\n"));
+ Log3(("VBoxGuestNativeISRMousePollEvent: done\n"));
}
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp
index a74f5595..c4ba2219 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -19,7 +19,7 @@
*
* VBoxDrv - OS/2 specifics.
*
- * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ * Copyright (c) 2007-2012 knut st. osmundsen <bird-src-spam@anduin.net>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.def b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.def
index 4728686e..15c04914 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.def
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.def
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2007 Oracle Corporation
+; Copyright (C) 2007-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
index a94e3848..7c7ff3fc 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
@@ -696,6 +696,8 @@ static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cr
* which are not really failures that require logging.
*/
Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", Cmd, rc));
+ if (rc == VERR_PERMISSION_DENIED) /* RTErrConvertToErrno() below will ring-0 debug assert if we don't do this. */
+ rc = VERR_ACCESS_DENIED;
rc = RTErrConvertToErrno(rc);
}
*pVal = rc;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.conf b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.conf
index 6c23af13..1e2c814f 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.conf
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.conf
@@ -1,7 +1,7 @@
#
# OpenSolaris Guest Driver Configuration
#
-# Copyright (C) 2007-2010 Oracle Corporation
+# Copyright (C) 2007-2012 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-legacy.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-legacy.cpp
index 5f1ce5d7..3dd55441 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-legacy.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-legacy.cpp
@@ -1,8 +1,10 @@
+/* $Id: VBoxGuest-win-legacy.cpp $ */
/** @file
- *
* VBoxGuest-win-legacy - Windows NT4 specifics.
- *
- * Copyright (C) 2010 Oracle Corporation
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -22,15 +24,12 @@
#include <VBox/log.h>
#include <VBox/version.h>
#include <VBox/VBoxGuestLib.h>
+#include <iprt/string.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-
-/* Reenable logging, this was #undef'ed on iprt/log.h for RING0. */
-#define LOG_ENABLED
-
#ifndef PCI_MAX_BUSES
# define PCI_MAX_BUSES 256
#endif
@@ -40,13 +39,12 @@
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN
-NTSTATUS vboxguestwinnt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath);
-static NTSTATUS vboxguestwinnt4FindPCIDevice(PULONG pBusNumber, PPCI_SLOT_NUMBER pSlotNumber);
+static NTSTATUS vbgdNt4FindPciDevice(PULONG pulBusNumber, PPCI_SLOT_NUMBER pSlotNumber);
RT_C_DECLS_END
#ifdef ALLOC_PRAGMA
-#pragma alloc_text (INIT, vboxguestwinnt4CreateDevice)
-#pragma alloc_text (INIT, vboxguestwinnt4FindPCIDevice)
+# pragma alloc_text(INIT, vbgdNt4CreateDevice)
+# pragma alloc_text(INIT, vbgdNt4FindPciDevice)
#endif
@@ -55,97 +53,86 @@ RT_C_DECLS_END
*
* @returns NT status code.
*
- * @param pDrvObj
- * @param pDevObj
- * @param pRegPath
+ * @param pDrvObj The driver object.
+ * @param pDevObj Unused. NULL. Dunno why it's here, makes no sense.
+ * @param pRegPath The driver registry path.
*/
-NTSTATUS vboxguestwinnt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
+NTSTATUS vbgdNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
{
- int vrc = VINF_SUCCESS;
- NTSTATUS rc = STATUS_SUCCESS;
-
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: pDrvObj=%p, pDevObj=%p, pRegPath=%p\n",
- pDrvObj, pDevObj, pRegPath));
+ Log(("VBoxGuest::vbgdNt4CreateDevice: pDrvObj=%p, pDevObj=%p, pRegPath=%p\n", pDrvObj, pDevObj, pRegPath));
/*
* Find our virtual PCI device
*/
- ULONG uBusNumber, uSlotNumber;
- rc = vboxguestwinnt4FindPCIDevice(&uBusNumber, (PCI_SLOT_NUMBER*)&uSlotNumber);
+ ULONG uBusNumber;
+ PCI_SLOT_NUMBER SlotNumber;
+ NTSTATUS rc = vbgdNt4FindPciDevice(&uBusNumber, &SlotNumber);
if (NT_ERROR(rc))
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device not found!\n"));
-
- bool fSymbolicLinkCreated = false;
- UNICODE_STRING szDosName;
- PDEVICE_OBJECT pDeviceObject = NULL;
- if (NT_SUCCESS(rc))
{
- /*
- * Create device.
- */
- UNICODE_STRING szDevName;
- RtlInitUnicodeString(&szDevName, VBOXGUEST_DEVICE_NAME_NT);
- rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
- if (NT_SUCCESS(rc))
- {
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device created\n"));
-
- RtlInitUnicodeString(&szDosName, VBOXGUEST_DEVICE_NAME_DOS);
- rc = IoCreateSymbolicLink(&szDosName, &szDevName);
- if (NT_SUCCESS(rc))
- {
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Symlink created\n"));
- fSymbolicLinkCreated = true;
- }
- else
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
- }
- else
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Device not found!\n"));
+ return rc;
}
/*
- * Setup the device extension.
+ * Create device.
*/
- PVBOXGUESTDEVEXT pDevExt = NULL;
+ UNICODE_STRING szDevName;
+ RtlInitUnicodeString(&szDevName, VBOXGUEST_DEVICE_NAME_NT);
+ PDEVICE_OBJECT pDeviceObject = NULL;
+ rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
if (NT_SUCCESS(rc))
{
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Setting up device extension ...\n"));
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Device created\n"));
- pDevExt = (PVBOXGUESTDEVEXT)pDeviceObject->DeviceExtension;
- RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
- }
+ UNICODE_STRING DosName;
+ RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
+ rc = IoCreateSymbolicLink(&DosName, &szDevName);
+ if (NT_SUCCESS(rc))
+ {
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Symlink created\n"));
- if (NT_SUCCESS(rc) && pDevExt)
- {
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device extension created\n"));
+ /*
+ * Setup the device extension.
+ */
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Setting up device extension ...\n"));
- /* Store a reference to ourself. */
- pDevExt->win.s.pDeviceObject = pDeviceObject;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
+ RT_ZERO(*pDevExt);
- /* Store bus and slot number we've queried before. */
- pDevExt->win.s.busNumber = uBusNumber;
- pDevExt->win.s.slotNumber = uSlotNumber;
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Device extension created\n"));
- #ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
- rc = hlpRegisterBugCheckCallback(pDevExt);
- #endif
- }
+ /* Store a reference to ourself. */
+ pDevExt->pDeviceObject = pDeviceObject;
- /* Do the actual VBox init ... */
- if (NT_SUCCESS(rc))
- rc = vboxguestwinInit(pDrvObj, pDeviceObject, pRegPath);
+ /* Store bus and slot number we've queried before. */
+ pDevExt->busNumber = uBusNumber;
+ pDevExt->slotNumber = SlotNumber.u.AsULONG;
- /* Clean up in case of errors. */
- if (NT_ERROR(rc))
- {
- if (fSymbolicLinkCreated && szDosName.Length > 0)
- IoDeleteSymbolicLink(&szDosName);
- if (pDeviceObject)
- IoDeleteDevice(pDeviceObject);
- }
+#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
+ rc = hlpRegisterBugCheckCallback(pDevExt);
+#endif
- Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Returning rc = 0x%x\n", rc));
+ /* Do the actual VBox init ... */
+ if (NT_SUCCESS(rc))
+ {
+ rc = vbgdNtInit(pDrvObj, pDeviceObject, pRegPath);
+ if (NT_SUCCESS(rc))
+ {
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Returning rc = 0x%x (succcess)\n", rc));
+ return rc;
+ }
+
+ /* bail out */
+ }
+ IoDeleteSymbolicLink(&DosName);
+ }
+ else
+ Log(("VBoxGuest::vbgdNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
+ IoDeleteDevice(pDeviceObject);
+ }
+ else
+ Log(("VBoxGuest::vbgdNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
+ Log(("VBoxGuest::vbgdNt4CreateDevice: Returning rc = 0x%x\n", rc));
return rc;
}
@@ -155,70 +142,57 @@ NTSTATUS vboxguestwinnt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDev
*
* @returns NT status code.
*
- * @param pBusNumber
- * @param pSlotNumber
- *
+ * @param pulBusNumber Where to return the bus number on success.
+ * @param pSlotNumber Where to return the slot number on success.
*/
-static NTSTATUS vboxguestwinnt4FindPCIDevice(PULONG pBusNumber, PPCI_SLOT_NUMBER pSlotNumber)
+static NTSTATUS vbgdNt4FindPciDevice(PULONG pulBusNumber, PPCI_SLOT_NUMBER pSlotNumber)
{
- NTSTATUS rc;
-
- ULONG busNumber;
- ULONG deviceNumber;
- ULONG functionNumber;
- PCI_SLOT_NUMBER slotNumber;
- PCI_COMMON_CONFIG pciData;
-
- Log(("VBoxGuest::vboxguestwinnt4FindPCIDevice\n"));
+ Log(("VBoxGuest::vbgdNt4FindPciDevice\n"));
- rc = STATUS_DEVICE_DOES_NOT_EXIST;
- slotNumber.u.AsULONG = 0;
+ PCI_SLOT_NUMBER SlotNumber;
+ SlotNumber.u.AsULONG = 0;
/* Scan each bus. */
- for (busNumber = 0; busNumber < PCI_MAX_BUSES; busNumber++)
+ for (ULONG ulBusNumber = 0; ulBusNumber < PCI_MAX_BUSES; ulBusNumber++)
{
/* Scan each device. */
- for (deviceNumber = 0; deviceNumber < PCI_MAX_DEVICES; deviceNumber++)
+ for (ULONG deviceNumber = 0; deviceNumber < PCI_MAX_DEVICES; deviceNumber++)
{
- slotNumber.u.bits.DeviceNumber = deviceNumber;
+ SlotNumber.u.bits.DeviceNumber = deviceNumber;
/* Scan each function (not really required...). */
- for (functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++)
+ for (ULONG functionNumber = 0; functionNumber < PCI_MAX_FUNCTION; functionNumber++)
{
- slotNumber.u.bits.FunctionNumber = functionNumber;
+ SlotNumber.u.bits.FunctionNumber = functionNumber;
/* Have a look at what's in this slot. */
- if (!HalGetBusData(PCIConfiguration, busNumber, slotNumber.u.AsULONG,
- &pciData, sizeof(ULONG)))
+ PCI_COMMON_CONFIG PciData;
+ if (!HalGetBusData(PCIConfiguration, ulBusNumber, SlotNumber.u.AsULONG, &PciData, sizeof(ULONG)))
{
/* No such bus, we're done with it. */
deviceNumber = PCI_MAX_DEVICES;
break;
}
- if (pciData.VendorID == PCI_INVALID_VENDORID)
- {
+ if (PciData.VendorID == PCI_INVALID_VENDORID)
/* We have to proceed to the next function. */
continue;
- }
/* Check if it's another device. */
- if ((pciData.VendorID != VMMDEV_VENDORID) ||
- (pciData.DeviceID != VMMDEV_DEVICEID))
- {
+ if ( PciData.VendorID != VMMDEV_VENDORID
+ || PciData.DeviceID != VMMDEV_DEVICEID)
continue;
- }
/* Hooray, we've found it! */
- Log(("VBoxGuest::vboxguestwinnt4FindPCIDevice: Device found!\n"));
+ Log(("VBoxGuest::vbgdNt4FindPciDevice: Device found!\n"));
- *pBusNumber = busNumber;
- *pSlotNumber = slotNumber;
- rc = STATUS_SUCCESS;
+ *pulBusNumber = ulBusNumber;
+ *pSlotNumber = SlotNumber;
+ return STATUS_SUCCESS;
}
}
}
- return rc;
+ return STATUS_DEVICE_DOES_NOT_EXIST;
}
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp
index fb844b78..73ec6ff4 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp
@@ -1,8 +1,10 @@
+/* $Id: VBoxGuest-win-pnp.cpp $ */
/** @file
- *
* VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
- *
- * Copyright (C) 2010 Oracle Corporation
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,38 +29,29 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-extern winVersion_t g_winVersion;
-
RT_C_DECLS_BEGIN
-static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
-static NTSTATUS vboxguestwinPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
-static VOID vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
+static NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
+static NTSTATUS vbgdNtPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
+static VOID vbgdNtShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
RT_C_DECLS_END
#ifdef ALLOC_PRAGMA
-#pragma alloc_text (PAGE, vboxguestwinPnP)
-#pragma alloc_text (PAGE, vboxguestwinPower)
-#pragma alloc_text (PAGE, vboxguestwinSendIrpSynchronously)
-#pragma alloc_text (PAGE, vboxguestwinShowDeviceResources)
+# pragma alloc_text(PAGE, vbgdNtPnP)
+# pragma alloc_text(PAGE, vbgdNtPower)
+# pragma alloc_text(PAGE, vbgdNtSendIrpSynchronously)
+# pragma alloc_text(PAGE, vbgdNtShowDeviceResources)
#endif
-/* Reenable logging, this was #undef'ed on iprt/log.h for RING0. */
-#define LOG_ENABLED
-
-
-/*******************************************************************************
-* Internal Functions *
-*******************************************************************************/
/**
* Irp completion routine for PnP Irps we send.
*
* @param pDevObj Device object.
* @param pIrp Request packet.
- * @param event Semaphore.
+ * @param pEvent Semaphore.
* @return NT status code
*/
-static NTSTATUS vboxguestwinPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
+static NTSTATUS vbgdNtPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
{
KeSetEvent(pEvent, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
@@ -73,21 +66,21 @@ static NTSTATUS vboxguestwinPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PK
* @param fStrict When set, returns an error if the IRP gives an error.
* @return NT status code
*/
-static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
+static NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
{
- KEVENT event;
+ KEVENT Event;
- KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);
- IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vboxguestwinPnpIrpComplete,
- &event, TRUE, TRUE, TRUE);
+ IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vbgdNtPnpIrpComplete,
+ &Event, TRUE, TRUE, TRUE);
NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
if (rc == STATUS_PENDING)
{
- KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
rc = pIrp->IoStatus.Status;
}
@@ -97,7 +90,7 @@ static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pI
rc = STATUS_SUCCESS;
}
- Log(("VBoxGuest::vboxguestwinSendIrpSynchronously: Returning 0x%x\n", rc));
+ Log(("VBoxGuest::vbgdNtSendIrpSynchronously: Returning 0x%x\n", rc));
return rc;
}
@@ -108,13 +101,13 @@ static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pI
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
-NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
- PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
#ifdef LOG_ENABLED
- static char* aszFnctName[] =
+ static char *s_apszFnctName[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
@@ -130,7 +123,7 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
- "",
+ "IRP_MN_0xE",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
@@ -141,10 +134,8 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
};
- Log(("VBoxGuest::vboxguestwinGuestPnp: MinorFunction: %s\n",
- pStack->MinorFunction < (sizeof(aszFnctName) / sizeof(aszFnctName[0]))
- ? aszFnctName[pStack->MinorFunction]
- : "Unknown"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: MinorFunction: %s\n",
+ pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
#endif
NTSTATUS rc = STATUS_SUCCESS;
@@ -152,50 +143,50 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
case IRP_MN_START_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n"));
/* This must be handled first by the lower driver. */
- rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
+ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
if ( NT_SUCCESS(rc)
&& NT_SUCCESS(pIrp->IoStatus.Status))
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
pStack->Parameters.StartDevice.AllocatedResources));
if (!pStack->Parameters.StartDevice.AllocatedResources)
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
- pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
+ pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
rc = STATUS_UNSUCCESSFUL;
}
else
{
- rc = vboxguestwinInit(pDevObj, pIrp);
+ rc = vbgdNtInit(pDevObj, pIrp);
}
}
if (NT_ERROR(rc))
{
- Log(("VBoxGuest::vboxguestwinGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
+ Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
/* Need to unmap memory in case of errors ... */
- vboxguestwinUnmapVMMDevMemory(pDevExt);
+ vbgdNtUnmapVMMDevMemory(pDevExt);
}
break;
}
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
/* This must be handled first by the lower driver. */
- rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
+ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
- if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE)
+ if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGREMOVE)
{
/* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
- pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
+ pDevExt->devState = pDevExt->prevDevState;
}
/* Complete the IRP. */
@@ -204,7 +195,7 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_SURPRISE_REMOVAL:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED);
@@ -218,7 +209,7 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
/* Do not complete the IRP. */
return rc;
@@ -226,12 +217,12 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_QUERY_REMOVE_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
- Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
rc = STATUS_UNSUCCESSFUL;
-#endif /* VBOX_REBOOT_ON_UNINSTALL */
+#endif
if (NT_SUCCESS(rc))
{
@@ -242,8 +233,8 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
- Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
+ Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
/* we must not do anything the IRP after doing IoSkip & CallDriver
* since the driver below us will complete (or already have completed) the IRP.
@@ -257,14 +248,15 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_REMOVE_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
/* Free hardware resources. */
- /* @todo this should actually free I/O ports, interrupts, etc. */
- rc = vboxguestwinCleanup(pDevObj);
- Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: vboxguestwinCleanup rc = 0x%08X\n", rc));
+ /** @todo this should actually free I/O ports, interrupts, etc.
+ * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */
+ rc = vbgdNtCleanup(pDevObj);
+ Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup rc = 0x%08X\n", rc));
/*
* We need to send the remove down the stack before we detach,
@@ -275,28 +267,28 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
- Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
+ Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
- IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
+ IoDetachDevice(pDevExt->pNextLowerDriver);
- Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
/* Destroy device extension and clean up everything else. */
- VBoxGuestDeleteDevExt(pDevExt);
+ VBoxGuestDeleteDevExt(&pDevExt->Core);
/* Remove DOS device + symbolic link. */
UNICODE_STRING win32Name;
RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
IoDeleteSymbolicLink(&win32Name);
- Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
/* Last action: Delete our device! pDevObj is *not* failed
* anymore after this call! */
IoDeleteDevice(pDevObj);
- Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Device removed!\n"));
/* Propagating rc from IoCallDriver. */
return rc; /* Make sure that we don't do anything below here anymore! */
@@ -304,15 +296,15 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_CANCEL_STOP_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
/* This must be handled first by the lower driver. */
- rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
+ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
- if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
+ if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGSTOP)
{
/* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
- pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
+ pDevExt->devState = pDevExt->prevDevState;
}
/* Complete the IRP. */
@@ -321,12 +313,12 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_QUERY_STOP_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
- Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
+ Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-#endif /* VBOX_REBOOT_ON_UNINSTALL */
+#endif
if (NT_SUCCESS(rc))
{
@@ -337,8 +329,8 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
- Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
+ Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
/* we must not do anything with the IRP after doing IoSkip & CallDriver
* since the driver below us will complete (or already have completed) the IRP.
@@ -352,22 +344,23 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case IRP_MN_STOP_DEVICE:
{
- Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n"));
+ Log(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
/* Free hardware resources. */
- /* @todo this should actually free I/O ports, interrupts, etc. */
- rc = vboxguestwinCleanup(pDevObj);
- Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
+ /** @todo this should actually free I/O ports, interrupts, etc.
+ * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */
+ rc = vbgdNtCleanup(pDevObj);
+ Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
/* Pass to the lower driver. */
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
- Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
+ Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
return rc;
}
@@ -375,7 +368,7 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
default:
{
IoSkipCurrentIrpStackLocation(pIrp);
- rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
+ rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
return rc;
}
}
@@ -383,7 +376,7 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
pIrp->IoStatus.Status = rc;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- Log(("VBoxGuest::vboxguestwinGuestPnp: Returning with rc = 0x%x\n", rc));
+ Log(("VBoxGuest::vbgdNtGuestPnp: Returning with rc = 0x%x\n", rc));
return rc;
}
@@ -396,19 +389,17 @@ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pIrp IO request packet.
* @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
*/
-NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
- IN PIRP pIrp, IN PVOID pContext)
+static NTSTATUS vbgdNtPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
{
- PIO_STACK_LOCATION pIrpSp;
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
+#ifdef VBOX_STRICT
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pContext;
+ PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- ASSERT(pDevExt);
- ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
+ Assert(pDevExt);
- pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
if (pIrpSp)
{
- ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
+ Assert(pIrpSp->MajorFunction == IRP_MJ_POWER);
if (NT_SUCCESS(pIrp->IoStatus.Status))
{
switch (pIrpSp->MinorFunction)
@@ -429,6 +420,7 @@ NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
}
}
}
+#endif
return STATUS_SUCCESS;
}
@@ -441,56 +433,55 @@ NTSTATUS vboxguestwinPowerComplete(IN PDEVICE_OBJECT pDevObj,
* @param pDevObj device object
* @param pIrp IRP
*/
-NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
- POWER_STATE_TYPE powerType;
- POWER_STATE powerState;
- POWER_ACTION powerAction;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
+ POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
+ POWER_STATE PowerState = pStack->Parameters.Power.State;
+ POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
- Log(("VBoxGuest::vboxguestwinGuestPower\n"));
-
- powerType = pStack->Parameters.Power.Type;
- powerAction = pStack->Parameters.Power.ShutdownType;
- powerState = pStack->Parameters.Power.State;
+ Log(("VBoxGuest::vbgdNtGuestPower\n"));
switch (pStack->MinorFunction)
{
case IRP_MN_SET_POWER:
{
- Log(("VBoxGuest::vboxguestwinGuestPower: IRP_MN_SET_POWER, type= %d\n", powerType));
- switch (powerType)
+ Log(("VBoxGuest::vbgdNtGuestPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
+ switch (enmPowerType)
{
case SystemPowerState:
{
- Log(("VBoxGuest::vboxguestwinGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
+ Log(("VBoxGuest::vbgdNtGuestPower: SystemPowerState, action = %d, state = %d/%d\n",
+ enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
- switch (powerAction)
+ switch (enmPowerAction)
{
case PowerActionSleep:
/* System now is in a working state. */
- if (powerState.SystemState == PowerSystemWorking)
+ if (PowerState.SystemState == PowerSystemWorking)
{
if ( pDevExt
- && pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
+ && pDevExt->LastSystemPowerAction == PowerActionHibernate)
{
- Log(("VBoxGuest::vboxguestwinGuestPower: Returning from hibernation!\n"));
- int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt, vboxguestwinVersionToOSType(g_winVersion));
+ Log(("VBoxGuest::vbgdNtGuestPower: Returning from hibernation!\n"));
+ int rc = VBoxGuestReinitDevExtAfterHibernation(&pDevExt->Core,
+ vbgdNtVersionToOSType(g_enmVbgdNtVer));
if (RT_FAILURE(rc))
- Log(("VBoxGuest::vboxguestwinGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
+ Log(("VBoxGuest::vbgdNtGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
}
}
break;
case PowerActionShutdownReset:
{
- Log(("VBoxGuest::vboxguestwinGuestPower: Power action reset!\n"));
+ Log(("VBoxGuest::vbgdNtGuestPower: Power action reset!\n"));
/* Tell the VMM that we no longer support mouse pointer integration. */
VMMDevReqMouseStatus *pReq = NULL;
- int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
+ int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
+ VMMDevReq_SetMouseStatus);
if (RT_SUCCESS(vrc))
{
pReq->mouseFeatures = 0;
@@ -500,8 +491,7 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
vrc = VbglGRPerform(&pReq->header);
if (RT_FAILURE(vrc))
{
- Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
- "vrc = %Rrc\n", vrc));
+ Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
}
VbglGRFree(&pReq->header);
@@ -515,12 +505,12 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case PowerActionShutdown:
case PowerActionShutdownOff:
{
- Log(("VBoxGuest::vboxguestwinGuestPower: Power action shutdown!\n"));
- if (powerState.SystemState >= PowerSystemShutdown)
+ Log(("VBoxGuest::vbgdNtGuestPower: Power action shutdown!\n"));
+ if (PowerState.SystemState >= PowerSystemShutdown)
{
- Log(("VBoxGuest::vboxguestwinGuestPower: Telling the VMMDev to close the VM ...\n"));
+ Log(("VBoxGuest::vbgdNtGuestPower: Telling the VMMDev to close the VM ...\n"));
- VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
+ VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
int vrc = VERR_NOT_IMPLEMENTED;
if (pReq)
{
@@ -530,10 +520,7 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
vrc = VbglGRPerform(&pReq->header);
}
if (RT_FAILURE(vrc))
- {
- Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. "
- "vrc = %Rrc\n", vrc));
- }
+ Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
/* No need to do cleanup here; at this point we should've been
* turned off by VMMDev already! */
@@ -543,7 +530,7 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case PowerActionHibernate:
- Log(("VBoxGuest::vboxguestwinGuestPower: Power action hibernate!\n"));
+ Log(("VBoxGuest::vbgdNtGuestPower: Power action hibernate!\n"));
break;
}
@@ -552,7 +539,7 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* This becomes handy when we return from hibernation for example.
*/
if (pDevExt)
- pDevExt->win.s.LastSystemPowerAction = powerAction;
+ pDevExt->LastSystemPowerAction = enmPowerAction;
break;
}
@@ -566,21 +553,22 @@ NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
}
/*
- * Whether we are completing or relaying this power IRP,
- * we must call PoStartNextPowerIrp.
+ * Whether we are completing or relaying this power IRP,
+ * we must call PoStartNextPowerIrp.
*/
PoStartNextPowerIrp(pIrp);
/*
- * Send the IRP down the driver stack,
- * using PoCallDriver (not IoCallDriver, as for non-power irps).
+ * Send the IRP down the driver stack, using PoCallDriver
+ * (not IoCallDriver, as for non-power irps).
*/
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,
- vboxguestwinPowerComplete,
+ vbgdNtPowerComplete,
(PVOID)pDevExt,
TRUE,
TRUE,
TRUE);
- return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
+ return PoCallDriver(pDevExt->pNextLowerDriver, pIrp);
}
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
index 9299ae5b..d4ba77b2 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
@@ -1,8 +1,10 @@
+/* $Id: VBoxGuest-win.cpp $ */
/** @file
- *
* VBoxGuest - Windows specifics.
- *
- * Copyright (C) 2010 Oracle Corporation
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -25,6 +27,7 @@
#include <VBox/log.h>
#include <VBox/VBoxGuestLib.h>
+#include <iprt/string.h>
/*
* XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist
@@ -35,22 +38,23 @@
# undef ExFreePool
#endif
+
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN
-static NTSTATUS vboxguestwinAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
-static void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj);
-static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinRegistryReadDWORD(ULONG ulRoot, PCWSTR pwszPath, PWSTR pwszName, PULONG puValue);
-static NTSTATUS vboxguestwinSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-static NTSTATUS vboxguestwinNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj);
+static void vbgdNtUnload(PDRIVER_OBJECT pDrvObj);
+static NTSTATUS vbgdNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtRegistryReadDWORD(ULONG ulRoot, PCWSTR pwszPath, PWSTR pwszName, PULONG puValue);
+static NTSTATUS vbgdNtSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS vbgdNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
#ifdef DEBUG
-static void vboxguestwinDoTests(void);
+static void vbgdNtDoTests(void);
#endif
RT_C_DECLS_END
@@ -63,19 +67,24 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
RT_C_DECLS_END
#ifdef ALLOC_PRAGMA
-#pragma alloc_text (INIT, DriverEntry)
-#pragma alloc_text (PAGE, vboxguestwinAddDevice)
-#pragma alloc_text (PAGE, vboxguestwinUnload)
-#pragma alloc_text (PAGE, vboxguestwinCreate)
-#pragma alloc_text (PAGE, vboxguestwinClose)
-#pragma alloc_text (PAGE, vboxguestwinIOCtl)
-#pragma alloc_text (PAGE, vboxguestwinShutdown)
-#pragma alloc_text (PAGE, vboxguestwinNotSupportedStub)
-#pragma alloc_text (PAGE, vboxguestwinScanPCIResourceList)
+# pragma alloc_text(INIT, DriverEntry)
+# pragma alloc_text(PAGE, vbgdNtAddDevice)
+# pragma alloc_text(PAGE, vbgdNtUnload)
+# pragma alloc_text(PAGE, vbgdNtCreate)
+# pragma alloc_text(PAGE, vbgdNtClose)
+# pragma alloc_text(PAGE, vbgdNtShutdown)
+# pragma alloc_text(PAGE, vbgdNtNotSupportedStub)
+# pragma alloc_text(PAGE, vbgdNtScanPCIResourceList)
#endif
-/** The detected Windows version. */
-winVersion_t g_winVersion;
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The detected NT (windows) version. */
+VBGDNTVER g_enmVbgdNtVer = VBGDNTVER_INVALID;
+
+
/**
* Driver entry point.
@@ -90,61 +99,70 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
Log(("VBoxGuest::DriverEntry. Driver built: %s %s\n", __DATE__, __TIME__));
- ULONG majorVersion;
- ULONG minorVersion;
- ULONG buildNumber;
- BOOLEAN bCheckedBuild = PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL);
- Log(("VBoxGuest::DriverEntry: Running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber));
- if (bCheckedBuild)
+ /*
+ * Check if the the NT version is supported and initializing
+ * g_enmVbgdNtVer in the process.
+ */
+ ULONG ulMajorVer;
+ ULONG ulMinorVer;
+ ULONG ulBuildNo;
+ BOOLEAN fCheckedBuild = PsGetVersion(&ulMajorVer, &ulMinorVer, &ulBuildNo, NULL);
+ Log(("VBoxGuest::DriverEntry: Running on Windows NT version %u.%u, build %u\n", ulMajorVer, ulMinorVer, ulBuildNo));
+ if (fCheckedBuild)
Log(("VBoxGuest::DriverEntry: Running on a Windows checked build (debug)!\n"));
#ifdef DEBUG
- vboxguestwinDoTests();
+ vbgdNtDoTests();
#endif
- switch (majorVersion)
+ switch (ulMajorVer)
{
case 6: /* Windows Vista or Windows 7 (based on minor ver) */
- switch (minorVersion)
+ switch (ulMinorVer)
{
case 0: /* Note: Also could be Windows 2008 Server! */
- g_winVersion = WINVISTA;
+ g_enmVbgdNtVer = VBGDNTVER_WINVISTA;
break;
case 1: /* Note: Also could be Windows 2008 Server R2! */
- g_winVersion = WIN7;
+ g_enmVbgdNtVer = VBGDNTVER_WIN7;
break;
case 2:
- g_winVersion = WIN8;
+ g_enmVbgdNtVer = VBGDNTVER_WIN8;
+ break;
+ case 3:
+ g_enmVbgdNtVer = VBGDNTVER_WIN81;
break;
default:
- Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n",
- majorVersion, minorVersion));
+ Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n", ulMajorVer, ulMinorVer));
rc = STATUS_DRIVER_UNABLE_TO_LOAD;
break;
}
break;
case 5:
- switch (minorVersion)
+ switch (ulMinorVer)
{
case 2:
- g_winVersion = WIN2K3;
+ g_enmVbgdNtVer = VBGDNTVER_WIN2K3;
break;
case 1:
- g_winVersion = WINXP;
+ g_enmVbgdNtVer = VBGDNTVER_WINXP;
break;
case 0:
- g_winVersion = WIN2K;
+ g_enmVbgdNtVer = VBGDNTVER_WIN2K;
break;
default:
- Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n",
- majorVersion, minorVersion));
+ Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n", ulMajorVer, ulMinorVer));
rc = STATUS_DRIVER_UNABLE_TO_LOAD;
}
break;
case 4:
- g_winVersion = WINNT4;
+ g_enmVbgdNtVer = VBGDNTVER_WINNT4;
break;
default:
- Log(("VBoxGuest::DriverEntry: At least Windows NT4 required!\n"));
+ if (ulMajorVer < 4)
+ Log(("VBoxGuest::DriverEntry: At least Windows NT4 required! (%u.%u)\n", ulMajorVer, ulMinorVer));
+ else
+ Log(("VBoxGuest::DriverEntry: Too new version %u.%u!\n", ulMajorVer, ulMinorVer));
rc = STATUS_DRIVER_UNABLE_TO_LOAD;
+ break;
}
if (NT_SUCCESS(rc))
@@ -152,21 +170,21 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
/*
* Setup the driver entry points in pDrvObj.
*/
- pDrvObj->DriverUnload = vboxguestwinUnload;
- pDrvObj->MajorFunction[IRP_MJ_CREATE] = vboxguestwinCreate;
- pDrvObj->MajorFunction[IRP_MJ_CLOSE] = vboxguestwinClose;
- pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vboxguestwinIOCtl;
- pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vboxguestwinInternalIOCtl;
- pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = vboxguestwinShutdown;
- pDrvObj->MajorFunction[IRP_MJ_READ] = vboxguestwinNotSupportedStub;
- pDrvObj->MajorFunction[IRP_MJ_WRITE] = vboxguestwinNotSupportedStub;
+ pDrvObj->DriverUnload = vbgdNtUnload;
+ pDrvObj->MajorFunction[IRP_MJ_CREATE] = vbgdNtCreate;
+ pDrvObj->MajorFunction[IRP_MJ_CLOSE] = vbgdNtClose;
+ pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vbgdNtIOCtl;
+ pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = vbgdNtInternalIOCtl;
+ pDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = vbgdNtShutdown;
+ pDrvObj->MajorFunction[IRP_MJ_READ] = vbgdNtNotSupportedStub;
+ pDrvObj->MajorFunction[IRP_MJ_WRITE] = vbgdNtNotSupportedStub;
#ifdef TARGET_NT4
- rc = vboxguestwinnt4CreateDevice(pDrvObj, NULL /* pDevObj */, pRegPath);
+ rc = vbgdNt4CreateDevice(pDrvObj, NULL /* pDevObj */, pRegPath);
#else
- pDrvObj->MajorFunction[IRP_MJ_PNP] = vboxguestwinPnP;
- pDrvObj->MajorFunction[IRP_MJ_POWER] = vboxguestwinPower;
- pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vboxguestwinSystemControl;
- pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)vboxguestwinAddDevice;
+ pDrvObj->MajorFunction[IRP_MJ_PNP] = vbgdNtPnP;
+ pDrvObj->MajorFunction[IRP_MJ_POWER] = vbgdNtPower;
+ pDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vbgdNtSystemControl;
+ pDrvObj->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE)vbgdNtAddDevice;
#endif
}
@@ -183,84 +201,79 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
* @param pDrvObj Driver object
* @param pDevObj Device object
*/
-static NTSTATUS vboxguestwinAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
+static NTSTATUS vbgdNtAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj)
{
NTSTATUS rc;
- Log(("VBoxGuest::vboxguestwinGuestAddDevice\n"));
+ Log(("VBoxGuest::vbgdNtGuestAddDevice\n"));
/*
* Create device.
*/
+ UNICODE_STRING DevName;
+ RtlInitUnicodeString(&DevName, VBOXGUEST_DEVICE_NAME_NT);
PDEVICE_OBJECT pDeviceObject = NULL;
- PVBOXGUESTDEVEXT pDevExt = NULL;
- UNICODE_STRING devName;
- UNICODE_STRING win32Name;
- RtlInitUnicodeString(&devName, VBOXGUEST_DEVICE_NAME_NT);
- rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
+ rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
if (NT_SUCCESS(rc))
{
/*
* Create symbolic link (DOS devices).
*/
- RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
- rc = IoCreateSymbolicLink(&win32Name, &devName);
+ UNICODE_STRING DosName;
+ RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
+ rc = IoCreateSymbolicLink(&DosName, &DevName);
if (NT_SUCCESS(rc))
{
/*
* Setup the device extension.
*/
- pDevExt = (PVBOXGUESTDEVEXT)pDeviceObject->DeviceExtension;
- RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
+ RT_ZERO(*pDevExt);
- KeInitializeSpinLock(&pDevExt->win.s.MouseEventAccessLock);
+ KeInitializeSpinLock(&pDevExt->MouseEventAccessLock);
- pDevExt->win.s.pDeviceObject = pDeviceObject;
- pDevExt->win.s.prevDevState = STOPPED;
- pDevExt->win.s.devState = STOPPED;
+ pDevExt->pDeviceObject = pDeviceObject;
+ pDevExt->prevDevState = STOPPED;
+ pDevExt->devState = STOPPED;
- pDevExt->win.s.pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
- if (pDevExt->win.s.pNextLowerDriver == NULL)
+ pDevExt->pNextLowerDriver = IoAttachDeviceToDeviceStack(pDeviceObject, pDevObj);
+ if (pDevExt->pNextLowerDriver != NULL)
{
- Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
- rc = STATUS_DEVICE_NOT_CONNECTED;
- }
- }
- else
- Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoCreateSymbolicLink failed with rc=%#x!\n", rc));
- }
- else
- Log(("VBoxGuest::vboxguestwinGuestAddDevice: IoCreateDevice failed with rc=%#x!\n", rc));
-
- if (NT_SUCCESS(rc))
- {
- /*
- * If we reached this point we're fine with the basic driver setup,
- * so continue to init our own things.
- */
+ /*
+ * If we reached this point we're fine with the basic driver setup,
+ * so continue to init our own things.
+ */
#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
- vboxguestwinBugCheckCallback(pDevExt); /* Ignore failure! */
+ vbgdNtBugCheckCallback(pDevExt); /* Ignore failure! */
#endif
- /* VBoxGuestPower is pageable; ensure we are not called at elevated IRQL */
- pDeviceObject->Flags |= DO_POWER_PAGABLE;
+ if (NT_SUCCESS(rc))
+ {
+ /* VBoxGuestPower is pageable; ensure we are not called at elevated IRQL */
+ pDeviceObject->Flags |= DO_POWER_PAGABLE;
- /* Driver is ready now. */
- pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
- }
+ /* Driver is ready now. */
+ pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ Log(("VBoxGuest::vbgdNtGuestAddDevice: returning with rc = 0x%x (success)\n", rc));
+ return rc;
+ }
- /* Cleanup on error. */
- if (NT_ERROR(rc))
- {
- if (pDevExt)
- {
- if (pDevExt->win.s.pNextLowerDriver)
- IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
+ IoDetachDevice(pDevExt->pNextLowerDriver);
+ }
+ else
+ {
+ Log(("VBoxGuest::vbgdNtGuestAddDevice: IoAttachDeviceToDeviceStack did not give a nextLowerDriver!\n"));
+ rc = STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ /* bail out */
+ IoDeleteSymbolicLink(&DosName);
}
- IoDeleteSymbolicLink(&win32Name);
- if (pDeviceObject)
- IoDeleteDevice(pDeviceObject);
+ else
+ Log(("VBoxGuest::vbgdNtGuestAddDevice: IoCreateSymbolicLink failed with rc=%#x!\n", rc));
+ IoDeleteDevice(pDeviceObject);
}
-
- Log(("VBoxGuest::vboxguestwinGuestAddDevice: returning with rc = 0x%x\n", rc));
+ else
+ Log(("VBoxGuest::vbgdNtGuestAddDevice: IoCreateDevice failed with rc=%#x!\n", rc));
+ Log(("VBoxGuest::vbgdNtGuestAddDevice: returning with rc = 0x%x\n", rc));
return rc;
}
#endif
@@ -271,17 +284,16 @@ static NTSTATUS vboxguestwinAddDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDe
*
* @param pResourceList list of device resources.
*/
-static void vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList)
+static void vbgdNtShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList)
{
#ifdef LOG_ENABLED
- PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = pResourceList->PartialDescriptors;
- ULONG nres = pResourceList->Count;
- ULONG i;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pResource = pResourceList->PartialDescriptors;
+ ULONG cResources = pResourceList->Count;
- for (i = 0; i < nres; ++i, ++resource)
+ for (ULONG i = 0; i < cResources; ++i, ++pResource)
{
- ULONG uType = resource->Type;
- static char* aszName[] =
+ ULONG uType = pResource->Type;
+ static char const * const s_apszName[] =
{
"CmResourceTypeNull",
"CmResourceTypePort",
@@ -295,28 +307,27 @@ static void vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceL
"CmResourceTypeSubAllocateFrom",
};
- Log(("VBoxGuest::vboxguestwinShowDeviceResources: Type %s",
- uType < (sizeof(aszName) / sizeof(aszName[0]))
- ? aszName[uType] : "Unknown"));
+ Log(("VBoxGuest::vbgdNtShowDeviceResources: Type %s",
+ uType < RT_ELEMENTS(s_apszName) ? s_apszName[uType] : "Unknown"));
switch (uType)
{
case CmResourceTypePort:
case CmResourceTypeMemory:
- Log(("VBoxGuest::vboxguestwinShowDeviceResources: Start %8X%8.8lX length %X\n",
- resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
- resource->u.Port.Length));
+ Log(("VBoxGuest::vbgdNtShowDeviceResources: Start %8X%8.8lX length %X\n",
+ pResource->u.Port.Start.HighPart, pResource->u.Port.Start.LowPart,
+ pResource->u.Port.Length));
break;
case CmResourceTypeInterrupt:
- Log(("VBoxGuest::vboxguestwinShowDeviceResources: Level %X, Vector %X, Affinity %X\n",
- resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
- resource->u.Interrupt.Affinity));
+ Log(("VBoxGuest::vbgdNtShowDeviceResources: Level %X, Vector %X, Affinity %X\n",
+ pResource->u.Interrupt.Level, pResource->u.Interrupt.Vector,
+ pResource->u.Interrupt.Affinity));
break;
case CmResourceTypeDma:
- Log(("VBoxGuest::vboxguestwinShowDeviceResources: Channel %d, Port %X\n",
- resource->u.Dma.Channel, resource->u.Dma.Port));
+ Log(("VBoxGuest::vbgdNtShowDeviceResources: Channel %d, Port %X\n",
+ pResource->u.Dma.Channel, pResource->u.Dma.Port));
break;
default:
@@ -335,24 +346,24 @@ static void vboxguestwinShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceL
* @param pIrp Request packet.
*/
#ifndef TARGET_NT4
-NTSTATUS vboxguestwinInit(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtInit(PDEVICE_OBJECT pDevObj, PIRP pIrp)
#else
-NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
+NTSTATUS vbgdNtInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
#endif
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
#ifndef TARGET_NT4
- PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
#endif
- Log(("VBoxGuest::vboxguestwinInit\n"));
+ Log(("VBoxGuest::vbgdNtInit\n"));
int rc = STATUS_SUCCESS;
#ifdef TARGET_NT4
/*
* Let's have a look at what our PCI adapter offers.
*/
- Log(("VBoxGuest::vboxguestwinInit: Starting to scan PCI resources of VBoxGuest ...\n"));
+ Log(("VBoxGuest::vbgdNtInit: Starting to scan PCI resources of VBoxGuest ...\n"));
/* Assign the PCI resources. */
PCM_RESOURCE_LIST pResourceList = NULL;
@@ -360,18 +371,17 @@ NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICO
RtlInitUnicodeString(&classNameString, L"VBoxGuestAdapter");
rc = HalAssignSlotResources(pRegPath, &classNameString,
pDrvObj, pDevObj,
- PCIBus, pDevExt->win.s.busNumber, pDevExt->win.s.slotNumber,
+ PCIBus, pDevExt->busNumber, pDevExt->slotNumber,
&pResourceList);
if (pResourceList && pResourceList->Count > 0)
- vboxguestwinShowDeviceResources(&pResourceList->List[0].PartialResourceList);
+ vbgdNtShowDeviceResources(&pResourceList->List[0].PartialResourceList);
if (NT_SUCCESS(rc))
- rc = vboxguestwinScanPCIResourceList(pResourceList, pDevExt);
+ rc = vbgdNtScanPCIResourceList(pResourceList, pDevExt);
#else
if (pStack->Parameters.StartDevice.AllocatedResources->Count > 0)
- vboxguestwinShowDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
+ vbgdNtShowDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
if (NT_SUCCESS(rc))
- rc = vboxguestwinScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
- pDevExt);
+ rc = vbgdNtScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated, pDevExt);
#endif
if (NT_SUCCESS(rc))
{
@@ -381,40 +391,40 @@ NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICO
*/
void *pvMMIOBase = NULL;
uint32_t cbMMIO = 0;
- rc = vboxguestwinMapVMMDevMemory(pDevExt,
- pDevExt->win.s.vmmDevPhysMemoryAddress,
- pDevExt->win.s.vmmDevPhysMemoryLength,
- &pvMMIOBase,
- &cbMMIO);
+ rc = vbgdNtMapVMMDevMemory(pDevExt,
+ pDevExt->vmmDevPhysMemoryAddress,
+ pDevExt->vmmDevPhysMemoryLength,
+ &pvMMIOBase,
+ &cbMMIO);
if (NT_SUCCESS(rc))
{
- pDevExt->pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
+ pDevExt->Core.pVMMDevMemory = (VMMDevMemory *)pvMMIOBase;
- Log(("VBoxGuest::vboxguestwinInit: pvMMIOBase = 0x%p, pDevExt = 0x%p, pDevExt->pVMMDevMemory = 0x%p\n",
- pvMMIOBase, pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));
+ Log(("VBoxGuest::vbgdNtInit: pvMMIOBase = 0x%p, pDevExt = 0x%p, pDevExt->Core.pVMMDevMemory = 0x%p\n",
+ pvMMIOBase, pDevExt, pDevExt ? pDevExt->Core.pVMMDevMemory : NULL));
- int vrc = VBoxGuestInitDevExt(pDevExt,
- pDevExt->IOPortBase,
+ int vrc = VBoxGuestInitDevExt(&pDevExt->Core,
+ pDevExt->Core.IOPortBase,
pvMMIOBase, cbMMIO,
- vboxguestwinVersionToOSType(g_winVersion),
+ vbgdNtVersionToOSType(g_enmVbgdNtVer),
VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
if (RT_FAILURE(vrc))
{
- Log(("VBoxGuest::vboxguestwinInit: Could not init device extension, rc = %Rrc!\n", vrc));
+ Log(("VBoxGuest::vbgdNtInit: Could not init device extension, rc = %Rrc!\n", vrc));
rc = STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
else
- Log(("VBoxGuest::vboxguestwinInit: Could not map physical address of VMMDev, rc = 0x%x!\n", rc));
+ Log(("VBoxGuest::vbgdNtInit: Could not map physical address of VMMDev, rc = 0x%x!\n", rc));
}
if (NT_SUCCESS(rc))
{
- int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->win.s.pPowerStateRequest,
- sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
+ int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->pPowerStateRequest,
+ sizeof(VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
if (RT_FAILURE(vrc))
{
- Log(("VBoxGuest::vboxguestwinInit: Alloc for pPowerStateRequest failed, rc = %Rrc\n", vrc));
+ Log(("VBoxGuest::vbgdNtInit: Alloc for pPowerStateRequest failed, rc = %Rrc\n", vrc));
rc = STATUS_UNSUCCESSFUL;
}
}
@@ -424,68 +434,68 @@ NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICO
/*
* Register DPC and ISR.
*/
- Log(("VBoxGuest::vboxguestwinInit: Initializing DPC/ISR ...\n"));
+ Log(("VBoxGuest::vbgdNtInit: Initializing DPC/ISR ...\n"));
- IoInitializeDpcRequest(pDevExt->win.s.pDeviceObject, vboxguestwinDpcHandler);
+ IoInitializeDpcRequest(pDevExt->pDeviceObject, vbgdNtDpcHandler);
#ifdef TARGET_NT4
ULONG uInterruptVector;
KIRQL irqLevel;
/* Get an interrupt vector. */
/* Only proceed if the device provides an interrupt. */
- if ( pDevExt->win.s.interruptLevel
- || pDevExt->win.s.interruptVector)
+ if ( pDevExt->interruptLevel
+ || pDevExt->interruptVector)
{
- Log(("VBoxGuest::vboxguestwinInit: Getting interrupt vector (HAL): Bus: %u, IRQL: %u, Vector: %u\n",
- pDevExt->win.s.busNumber, pDevExt->win.s.interruptLevel, pDevExt->win.s.interruptVector));
+ Log(("VBoxGuest::vbgdNtInit: Getting interrupt vector (HAL): Bus: %u, IRQL: %u, Vector: %u\n",
+ pDevExt->busNumber, pDevExt->interruptLevel, pDevExt->interruptVector));
uInterruptVector = HalGetInterruptVector(PCIBus,
- pDevExt->win.s.busNumber,
- pDevExt->win.s.interruptLevel,
- pDevExt->win.s.interruptVector,
+ pDevExt->busNumber,
+ pDevExt->interruptLevel,
+ pDevExt->interruptVector,
&irqLevel,
- &pDevExt->win.s.interruptAffinity);
- Log(("VBoxGuest::vboxguestwinInit: HalGetInterruptVector returns vector %u\n", uInterruptVector));
+ &pDevExt->interruptAffinity);
+ Log(("VBoxGuest::vbgdNtInit: HalGetInterruptVector returns vector %u\n", uInterruptVector));
if (uInterruptVector == 0)
- Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n"));
+ Log(("VBoxGuest::vbgdNtInit: No interrupt vector found!\n"));
}
else
- Log(("VBoxGuest::vboxguestwinInit: Device does not provide an interrupt!\n"));
+ Log(("VBoxGuest::vbgdNtInit: Device does not provide an interrupt!\n"));
#endif
- if (pDevExt->win.s.interruptVector)
+ if (pDevExt->interruptVector)
{
- Log(("VBoxGuest::vboxguestwinInit: Connecting interrupt ...\n"));
+ Log(("VBoxGuest::vbgdNtInit: Connecting interrupt ...\n"));
- rc = IoConnectInterrupt(&pDevExt->win.s.pInterruptObject, /* Out: interrupt object. */
- (PKSERVICE_ROUTINE)vboxguestwinIsrHandler, /* Our ISR handler. */
- pDevExt, /* Device context. */
- NULL, /* Optional spinlock. */
+ rc = IoConnectInterrupt(&pDevExt->pInterruptObject, /* Out: interrupt object. */
+ (PKSERVICE_ROUTINE)vbgdNtIsrHandler, /* Our ISR handler. */
+ pDevExt, /* Device context. */
+ NULL, /* Optional spinlock. */
#ifdef TARGET_NT4
- uInterruptVector, /* Interrupt vector. */
- irqLevel, /* Interrupt level. */
- irqLevel, /* Interrupt level. */
+ uInterruptVector, /* Interrupt vector. */
+ irqLevel, /* Interrupt level. */
+ irqLevel, /* Interrupt level. */
#else
- pDevExt->win.s.interruptVector, /* Interrupt vector. */
- (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */
- (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */
+ pDevExt->interruptVector, /* Interrupt vector. */
+ (KIRQL)pDevExt->interruptLevel, /* Interrupt level. */
+ (KIRQL)pDevExt->interruptLevel, /* Interrupt level. */
#endif
- pDevExt->win.s.interruptMode, /* LevelSensitive or Latched. */
- TRUE, /* Shareable interrupt. */
- pDevExt->win.s.interruptAffinity, /* CPU affinity. */
- FALSE); /* Don't save FPU stack. */
+ pDevExt->interruptMode, /* LevelSensitive or Latched. */
+ TRUE, /* Shareable interrupt. */
+ pDevExt->interruptAffinity, /* CPU affinity. */
+ FALSE); /* Don't save FPU stack. */
if (NT_ERROR(rc))
- Log(("VBoxGuest::vboxguestwinInit: Could not connect interrupt, rc = 0x%x\n", rc));
+ Log(("VBoxGuest::vbgdNtInit: Could not connect interrupt, rc = 0x%x\n", rc));
}
else
- Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n"));
+ Log(("VBoxGuest::vbgdNtInit: No interrupt vector found!\n"));
}
#ifdef VBOX_WITH_HGCM
- Log(("VBoxGuest::vboxguestwinInit: Allocating kernel session data ...\n"));
- int vrc = VBoxGuestCreateKernelSession(pDevExt, &pDevExt->win.s.pKernelSession);
+ Log(("VBoxGuest::vbgdNtInit: Allocating kernel session data ...\n"));
+ int vrc = VBoxGuestCreateKernelSession(&pDevExt->Core, &pDevExt->pKernelSession);
if (RT_FAILURE(vrc))
{
- Log(("VBoxGuest::vboxguestwinInit: Failed to allocated kernel session data! rc = %Rrc\n", rc));
+ Log(("VBoxGuest::vbgdNtInit: Failed to allocated kernel session data! rc = %Rrc\n", rc));
rc = STATUS_UNSUCCESSFUL;
}
#endif
@@ -493,25 +503,25 @@ NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICO
if (RT_SUCCESS(rc))
{
ULONG ulValue = 0;
- NTSTATUS s = vboxguestwinRegistryReadDWORD(RTL_REGISTRY_SERVICES, L"VBoxGuest", L"LoggingEnabled",
- &ulValue);
- if (NT_SUCCESS(s))
+ NTSTATUS rcNt = vbgdNtRegistryReadDWORD(RTL_REGISTRY_SERVICES, L"VBoxGuest", L"LoggingEnabled", &ulValue);
+ if (NT_SUCCESS(rcNt))
{
- pDevExt->fLoggingEnabled = ulValue >= 0xFF;
- if (pDevExt->fLoggingEnabled)
+ pDevExt->Core.fLoggingEnabled = ulValue >= 0xFF;
+ if (pDevExt->Core.fLoggingEnabled)
Log(("Logging to release log enabled (0x%x)", ulValue));
}
/* Ready to rumble! */
- Log(("VBoxGuest::vboxguestwinInit: Device is ready!\n"));
+ Log(("VBoxGuest::vbgdNtInit: Device is ready!\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, WORKING);
}
else
- {
- pDevExt->win.s.pInterruptObject = NULL;
- }
+ pDevExt->pInterruptObject = NULL;
- Log(("VBoxGuest::vboxguestwinInit: Returned with rc = 0x%x\n", rc));
+ /** @todo r=bird: The error cleanup here is completely missing. We'll leak a
+ * whole bunch of things... */
+
+ Log(("VBoxGuest::vbgdNtInit: Returned with rc = 0x%x\n", rc));
return rc;
}
@@ -522,38 +532,38 @@ NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICO
*
* @param pDrvObj Driver object.
*/
-NTSTATUS vboxguestwinCleanup(PDEVICE_OBJECT pDevObj)
+NTSTATUS vbgdNtCleanup(PDEVICE_OBJECT pDevObj)
{
- Log(("VBoxGuest::vboxguestwinCleanup\n"));
+ Log(("VBoxGuest::vbgdNtCleanup\n"));
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
if (pDevExt)
{
#if 0 /* @todo: test & enable cleaning global session data */
#ifdef VBOX_WITH_HGCM
- if (pDevExt->win.s.pKernelSession)
+ if (pDevExt->pKernelSession)
{
- VBoxGuestCloseSession(pDevExt, pDevExt->win.s.pKernelSession);
- pDevExt->win.s.pKernelSession = NULL;
+ VBoxGuestCloseSession(pDevExt, pDevExt->pKernelSession);
+ pDevExt->pKernelSession = NULL;
}
#endif
#endif
- if (pDevExt->win.s.pInterruptObject)
+ if (pDevExt->pInterruptObject)
{
- IoDisconnectInterrupt(pDevExt->win.s.pInterruptObject);
- pDevExt->win.s.pInterruptObject = NULL;
+ IoDisconnectInterrupt(pDevExt->pInterruptObject);
+ pDevExt->pInterruptObject = NULL;
}
- /* @todo: cleanup the rest stuff */
+ /** @todo: cleanup the rest stuff */
#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
hlpDeregisterBugCheckCallback(pDevExt); /* ignore failure! */
#endif
/* According to MSDN we have to unmap previously mapped memory. */
- vboxguestwinUnmapVMMDevMemory(pDevExt);
+ vbgdNtUnmapVMMDevMemory(pDevExt);
}
return STATUS_SUCCESS;
}
@@ -564,11 +574,11 @@ NTSTATUS vboxguestwinCleanup(PDEVICE_OBJECT pDevObj)
*
* @param pDrvObj Driver object.
*/
-static void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj)
+static void vbgdNtUnload(PDRIVER_OBJECT pDrvObj)
{
- Log(("VBoxGuest::vboxguestwinGuestUnload\n"));
+ Log(("VBoxGuest::vbgdNtGuestUnload\n"));
#ifdef TARGET_NT4
- vboxguestwinCleanup(pDrvObj->DeviceObject);
+ vbgdNtCleanup(pDrvObj->DeviceObject);
/* Destroy device extension and clean up everything else. */
if (pDrvObj->DeviceObject && pDrvObj->DeviceObject->DeviceExtension)
@@ -578,18 +588,18 @@ static void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj)
* I don't think it's possible to unload a driver which processes have
* opened, at least we'll blindly assume that here.
*/
- UNICODE_STRING win32Name;
- RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
- NTSTATUS rc = IoDeleteSymbolicLink(&win32Name);
+ UNICODE_STRING DosName;
+ RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
+ NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
IoDeleteDevice(pDrvObj->DeviceObject);
-#else /* TARGET_NT4 */
+#else /* !TARGET_NT4 */
/* On a PnP driver this routine will be called after
* IRP_MN_REMOVE_DEVICE (where we already did the cleanup),
* so don't do anything here (yet). */
-#endif
+#endif /* !TARGET_NT4 */
- Log(("VBoxGuest::vboxguestwinGuestUnload: returning\n"));
+ Log(("VBoxGuest::vbgdNtGuestUnload: returning\n"));
}
@@ -599,19 +609,18 @@ static void vboxguestwinUnload(PDRIVER_OBJECT pDrvObj)
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
-static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+static NTSTATUS vbgdNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
/** @todo AssertPtrReturn(pIrp); */
- PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
/** @todo AssertPtrReturn(pStack); */
- PFILE_OBJECT pFileObj = pStack->FileObject;
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
- NTSTATUS rc = STATUS_SUCCESS;
+ PFILE_OBJECT pFileObj = pStack->FileObject;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
+ NTSTATUS rc = STATUS_SUCCESS;
- if (pDevExt->win.s.devState != WORKING)
+ if (pDevExt->devState != WORKING)
{
- Log(("VBoxGuest::vboxguestwinGuestCreate: device is not working currently: %d!\n",
- pDevExt->win.s.devState));
+ Log(("VBoxGuest::vbgdNtGuestCreate: device is not working currently: %d!\n", pDevExt->devState));
rc = STATUS_UNSUCCESSFUL;
}
else if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
@@ -620,7 +629,7 @@ static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* We are not remotely similar to a directory...
* (But this is possible.)
*/
- Log(("VBoxGuest::vboxguestwinGuestCreate: Uhm, we're not a directory!\n"));
+ Log(("VBoxGuest::vbgdNtGuestCreate: Uhm, we're not a directory!\n"));
rc = STATUS_NOT_A_DIRECTORY;
}
else
@@ -628,7 +637,7 @@ static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
#ifdef VBOX_WITH_HGCM
if (pFileObj)
{
- Log(("VBoxGuest::vboxguestwinGuestCreate: File object type = %d\n",
+ Log(("VBoxGuest::vbgdNtGuestCreate: File object type = %d\n",
pFileObj->Type));
int vrc;
@@ -639,12 +648,12 @@ static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* Create a session object if we have a valid file object. This session object
* exists for every R3 process.
*/
- vrc = VBoxGuestCreateUserSession(pDevExt, &pSession);
+ vrc = VBoxGuestCreateUserSession(&pDevExt->Core, &pSession);
}
else
{
/* ... otherwise we've been called from R0! */
- vrc = VBoxGuestCreateKernelSession(pDevExt, &pSession);
+ vrc = VBoxGuestCreateKernelSession(&pDevExt->Core, &pSession);
}
if (RT_SUCCESS(vrc))
pFileObj->FsContext = pSession;
@@ -657,7 +666,7 @@ static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
pIrp->IoStatus.Status = rc;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- Log(("VBoxGuest::vboxguestwinGuestCreate: Returning 0x%x\n", rc));
+ Log(("VBoxGuest::vbgdNtGuestCreate: Returning 0x%x\n", rc));
return rc;
}
@@ -668,20 +677,20 @@ static NTSTATUS vboxguestwinCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
-static NTSTATUS vboxguestwinClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+static NTSTATUS vbgdNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
- PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
- PFILE_OBJECT pFileObj = pStack->FileObject;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PFILE_OBJECT pFileObj = pStack->FileObject;
- Log(("VBoxGuest::vboxguestwinGuestClose: pDevExt=0x%p pFileObj=0x%p FsContext=0x%p\n",
+ Log(("VBoxGuest::vbgdNtGuestClose: pDevExt=0x%p pFileObj=0x%p FsContext=0x%p\n",
pDevExt, pFileObj, pFileObj->FsContext));
#ifdef VBOX_WITH_HGCM
/* Close both, R0 and R3 sessions. */
PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
if (pSession)
- VBoxGuestCloseSession(pDevExt, pSession);
+ VBoxGuestCloseSession(&pDevExt->Core, pSession);
#endif
pFileObj->FsContext = NULL;
@@ -699,16 +708,16 @@ static NTSTATUS vboxguestwinClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
-static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+static NTSTATUS vbgdNtIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS Status = STATUS_SUCCESS;
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
unsigned int uCmd = (unsigned int)pStack->Parameters.DeviceIoControl.IoControlCode;
char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* All requests are buffered. */
size_t cbData = pStack->Parameters.DeviceIoControl.InputBufferLength;
- unsigned cbOut = 0;
+ size_t cbOut = 0;
/* Do we have a file object associated?*/
PFILE_OBJECT pFileObj = pStack->FileObject;
@@ -716,7 +725,7 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
if (pFileObj) /* ... then we might have a session object as well! */
pSession = (PVBOXGUESTSESSION)pFileObj->FsContext;
- Log(("VBoxGuest::vboxguestwinIOCtl: uCmd=%u, pDevExt=0x%p, pSession=0x%p\n",
+ Log(("VBoxGuest::vbgdNtIOCtl: uCmd=%u, pDevExt=0x%p, pSession=0x%p\n",
uCmd, pDevExt, pSession));
/* We don't have a session associated with the file object? So this seems
@@ -725,8 +734,8 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* shall have its own context of course, no hacks, pleeease. */
if (pSession == NULL)
{
- Log(("VBoxGuest::vboxguestwinIOCtl: Using kernel session data ...\n"));
- pSession = pDevExt->win.s.pKernelSession;
+ Log(("VBoxGuest::vbgdNtIOCtl: Using kernel session data ...\n"));
+ pSession = pDevExt->pKernelSession;
}
/*
@@ -739,14 +748,14 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
case VBOXGUEST_IOCTL_ENABLE_VRDP_SESSION:
{
- LogRel(("VBoxGuest::vboxguestwinIOCtl: ENABLE_VRDP_SESSION: Currently: %sabled\n",
+ LogRel(("VBoxGuest::vbgdNtIOCtl: ENABLE_VRDP_SESSION: Currently: %sabled\n",
pDevExt->fVRDPEnabled? "en": "dis"));
if (!pDevExt->fVRDPEnabled)
{
KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
pDevExt->fVRDPEnabled = true;
- LogRel(("VBoxGuest::vboxguestwinIOCtl: ENABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
+ LogRel(("VBoxGuest::vbgdNtIOCtl: ENABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
pSharedUserData->ActiveConsoleId));
pDevExt->ulOldActiveConsoleId = pSharedUserData->ActiveConsoleId;
pSharedUserData->ActiveConsoleId = 2;
@@ -756,14 +765,14 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
case VBOXGUEST_IOCTL_DISABLE_VRDP_SESSION:
{
- LogRel(("VBoxGuest::vboxguestwinIOCtl: DISABLE_VRDP_SESSION: Currently: %sabled\n",
+ LogRel(("VBoxGuest::vbgdNtIOCtl: DISABLE_VRDP_SESSION: Currently: %sabled\n",
pDevExt->fVRDPEnabled? "en": "dis"));
if (pDevExt->fVRDPEnabled)
{
KUSER_SHARED_DATA *pSharedUserData = (KUSER_SHARED_DATA *)KI_USER_SHARED_DATA;
pDevExt->fVRDPEnabled = false;
- Log(("VBoxGuest::vboxguestwinIOCtl: DISABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
+ Log(("VBoxGuest::vbgdNtIOCtl: DISABLE_VRDP_SESSION: Current active console ID: 0x%08X\n",
pSharedUserData->ActiveConsoleId));
pSharedUserData->ActiveConsoleId = pDevExt->ulOldActiveConsoleId;
pDevExt->ulOldActiveConsoleId = 0;
@@ -780,16 +789,16 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* Process the common IOCtls.
*/
size_t cbDataReturned;
- int vrc = VBoxGuestCommonIOCtl(uCmd, pDevExt, pSession, pBuf, cbData, &cbDataReturned);
+ int vrc = VBoxGuestCommonIOCtl(uCmd, &pDevExt->Core, pSession, pBuf, cbData, &cbDataReturned);
- Log(("VBoxGuest::vboxguestwinGuestDeviceControl: rc=%Rrc, pBuf=0x%p, cbData=%u, cbDataReturned=%u\n",
+ Log(("VBoxGuest::vbgdNtGuestDeviceControl: rc=%Rrc, pBuf=0x%p, cbData=%u, cbDataReturned=%u\n",
vrc, pBuf, cbData, cbDataReturned));
if (RT_SUCCESS(vrc))
{
if (RT_UNLIKELY(cbDataReturned > cbData))
{
- Log(("VBoxGuest::vboxguestwinGuestDeviceControl: Too much output data %u - expected %u!\n", cbDataReturned, cbData));
+ Log(("VBoxGuest::vbgdNtGuestDeviceControl: Too much output data %u - expected %u!\n", cbDataReturned, cbData));
cbDataReturned = cbData;
Status = STATUS_BUFFER_TOO_SMALL;
}
@@ -800,9 +809,9 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
if ( vrc == VERR_NOT_SUPPORTED
|| vrc == VERR_INVALID_PARAMETER)
- {
Status = STATUS_INVALID_PARAMETER;
- }
+ else if (vrc == VERR_OUT_OF_RANGE)
+ Status = STATUS_INVALID_BUFFER_SIZE;
else
Status = STATUS_UNSUCCESSFUL;
}
@@ -815,32 +824,29 @@ static NTSTATUS vboxguestwinIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- //Log(("VBoxGuest::vboxguestwinGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
+ //Log(("VBoxGuest::vbgdNtGuestDeviceControl: returned cbOut=%d rc=%#x\n", cbOut, Status));
return Status;
}
/**
* Internal Device I/O Control entry point.
*
- * We do not want to allow some IOCTLs to be originated from user mode, this is
- * why we have a different entry point for internal IOCTLs.
- *
* @param pDevObj Device object.
* @param pIrp Request packet.
- *
- * @todo r=bird: This is no need for this extra function for the purpose of
- * securing an IOCTL from user space access. VBoxGuestCommonIOCtl
- * has a way to do this already, see VBOXGUEST_IOCTL_GETVMMDEVPORT.
*/
-static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+static NTSTATUS vbgdNtInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS Status = STATUS_SUCCESS;
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
unsigned int uCmd = (unsigned int)pStack->Parameters.DeviceIoControl.IoControlCode;
bool fProcessed = false;
unsigned Info = 0;
+ /*
+ * Override common behavior of some operations.
+ */
+ /** @todo r=bird: Better to add dedicated worker functions for this! */
switch (uCmd)
{
case VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK:
@@ -859,9 +865,9 @@ static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
/* we need a lock here to avoid concurrency with the set event functionality */
KIRQL OldIrql;
- KeAcquireSpinLock(&pDevExt->win.s.MouseEventAccessLock, &OldIrql);
- pDevExt->MouseNotifyCallback = *pInfo;
- KeReleaseSpinLock(&pDevExt->win.s.MouseEventAccessLock, OldIrql);
+ KeAcquireSpinLock(&pDevExt->MouseEventAccessLock, &OldIrql);
+ pDevExt->Core.MouseNotifyCallback = *pInfo;
+ KeReleaseSpinLock(&pDevExt->MouseEventAccessLock, OldIrql);
Status = STATUS_SUCCESS;
break;
@@ -870,8 +876,6 @@ static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
default:
break;
}
-
-
if (fProcessed)
{
pIrp->IoStatus.Status = Status;
@@ -881,7 +885,10 @@ static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
return Status;
}
- return vboxguestwinIOCtl(pDevObj, pIrp);
+ /*
+ * No override, go to common code.
+ */
+ return vbgdNtIOCtl(pDevObj, pIrp);
}
@@ -892,16 +899,16 @@ static NTSTATUS vboxguestwinInternalIOCtl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pDevObj Device object.
* @param pIrp IRP.
*/
-NTSTATUS vboxguestwinSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
- Log(("VBoxGuest::vboxguestwinGuestSystemControl\n"));
+ Log(("VBoxGuest::vbgdNtGuestSystemControl\n"));
/* Always pass it on to the next driver. */
IoSkipCurrentIrpStackLocation(pIrp);
- return IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
+ return IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
}
@@ -912,13 +919,13 @@ NTSTATUS vboxguestwinSystemControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pDevObj Device object.
* @param pIrp IRP.
*/
-NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
- Log(("VBoxGuest::vboxguestwinGuestShutdown\n"));
+ Log(("VBoxGuest::vbgdNtGuestShutdown\n"));
- VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
+ VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
if (pReq)
{
pReq->header.requestType = VMMDevReq_SetPowerStatus;
@@ -927,7 +934,7 @@ NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
int rc = VbglGRPerform(&pReq->header);
if (RT_FAILURE(rc))
{
- Log(("VBoxGuest::vboxguestwinGuestShutdown: Error performing request to VMMDev! "
+ Log(("VBoxGuest::vbgdNtGuestShutdown: Error performing request to VMMDev! "
"rc = %Rrc\n", rc));
}
}
@@ -942,9 +949,9 @@ NTSTATUS vboxguestwinShutdown(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pDevObj Device object.
* @param pIrp IRP.
*/
-NTSTATUS vboxguestwinNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+NTSTATUS vbgdNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
- Log(("VBoxGuest::vboxguestwinGuestNotSupportedStub\n"));
+ Log(("VBoxGuest::vbgdNtGuestNotSupportedStub\n"));
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
@@ -962,28 +969,28 @@ NTSTATUS vboxguestwinNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
* @param pIrp Interrupt request packet.
* @param pContext Context specific pointer.
*/
-void vboxguestwinDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
+void vbgdNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
- Log(("VBoxGuest::vboxguestwinGuestDpcHandler: pDevExt=0x%p\n", pDevExt));
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
+ Log(("VBoxGuest::vbgdNtGuestDpcHandler: pDevExt=0x%p\n", pDevExt));
/* test & reset the counter */
- if (ASMAtomicXchgU32(&pDevExt->u32MousePosChangedSeq, 0))
+ if (ASMAtomicXchgU32(&pDevExt->Core.u32MousePosChangedSeq, 0))
{
/* we need a lock here to avoid concurrency with the set event ioctl handler thread,
* i.e. to prevent the event from destroyed while we're using it */
Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
- KeAcquireSpinLockAtDpcLevel(&pDevExt->win.s.MouseEventAccessLock);
+ KeAcquireSpinLockAtDpcLevel(&pDevExt->MouseEventAccessLock);
- if (pDevExt->MouseNotifyCallback.pfnNotify)
- pDevExt->MouseNotifyCallback.pfnNotify(pDevExt->MouseNotifyCallback.pvUser);
+ if (pDevExt->Core.MouseNotifyCallback.pfnNotify)
+ pDevExt->Core.MouseNotifyCallback.pfnNotify(pDevExt->Core.MouseNotifyCallback.pvUser);
- KeReleaseSpinLockFromDpcLevel(&pDevExt->win.s.MouseEventAccessLock);
+ KeReleaseSpinLockFromDpcLevel(&pDevExt->MouseEventAccessLock);
}
/* Process the wake-up list we were asked by the scheduling a DPC
- * in vboxguestwinIsrHandler(). */
- VBoxGuestWaitDoWakeUps(pDevExt);
+ * in vbgdNtIsrHandler(). */
+ VBoxGuestWaitDoWakeUps(&pDevExt->Core);
}
@@ -994,35 +1001,35 @@ void vboxguestwinDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID
* @param pInterrupt Interrupt that was triggered.
* @param pServiceContext Context specific pointer.
*/
-BOOLEAN vboxguestwinIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
+BOOLEAN vbgdNtIsrHandler(PKINTERRUPT pInterrupt, PVOID pServiceContext)
{
- PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pServiceContext;
+ PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pServiceContext;
if (pDevExt == NULL)
return FALSE;
- /*Log(("VBoxGuest::vboxguestwinGuestIsrHandler: pDevExt = 0x%p, pVMMDevMemory = 0x%p\n",
+ /*Log(("VBoxGuest::vbgdNtGuestIsrHandler: pDevExt = 0x%p, pVMMDevMemory = 0x%p\n",
pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL));*/
/* Enter the common ISR routine and do the actual work. */
- BOOLEAN fIRQTaken = VBoxGuestCommonISR(pDevExt);
+ BOOLEAN fIRQTaken = VBoxGuestCommonISR(&pDevExt->Core);
/* If we need to wake up some events we do that in a DPC to make
* sure we're called at the right IRQL. */
if (fIRQTaken)
{
- Log(("VBoxGuest::vboxguestwinGuestIsrHandler: IRQ was taken! pInterrupt = 0x%p, pDevExt = 0x%p\n",
+ Log(("VBoxGuest::vbgdNtGuestIsrHandler: IRQ was taken! pInterrupt = 0x%p, pDevExt = 0x%p\n",
pInterrupt, pDevExt));
- if (ASMAtomicUoReadU32(&pDevExt->u32MousePosChangedSeq) || !RTListIsEmpty(&pDevExt->WakeUpList))
+ if (ASMAtomicUoReadU32(&pDevExt->Core.u32MousePosChangedSeq) || !RTListIsEmpty(&pDevExt->Core.WakeUpList))
{
- Log(("VBoxGuest::vboxguestwinGuestIsrHandler: Requesting DPC ...\n"));
- IoRequestDpc(pDevExt->win.s.pDeviceObject, pDevExt->win.s.pCurrentIrp, NULL);
+ Log(("VBoxGuest::vbgdNtGuestIsrHandler: Requesting DPC ...\n"));
+ IoRequestDpc(pDevExt->pDeviceObject, pDevExt->pCurrentIrp, NULL);
}
}
return fIRQTaken;
}
-/*
+/**
* Overridden routine for mouse polling events.
*
* @param pDevExt Device extension structure.
@@ -1047,8 +1054,7 @@ void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
* not specified in ulRoot), on output this will retrieve the looked up
* registry value if found.
*/
-NTSTATUS vboxguestwinRegistryReadDWORD(ULONG ulRoot, PCWSTR pwszPath, PWSTR pwszName,
- PULONG puValue)
+NTSTATUS vbgdNtRegistryReadDWORD(ULONG ulRoot, PCWSTR pwszPath, PWSTR pwszName, PULONG puValue)
{
if (!pwszPath || !pwszName || !puValue)
return STATUS_INVALID_PARAMETER;
@@ -1079,17 +1085,17 @@ NTSTATUS vboxguestwinRegistryReadDWORD(ULONG ulRoot, PCWSTR pwszPath, PWSTR pwsz
* @param pResList Resource list
* @param pDevExt Device extension
*/
-NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTDEVEXT pDevExt)
+NTSTATUS vbgdNtScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTDEVEXTWIN pDevExt)
{
/* Enumerate the resource list. */
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Found %d resources\n",
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Found %d resources\n",
pResList->List->PartialResourceList.Count));
NTSTATUS rc = STATUS_SUCCESS;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialData = NULL;
ULONG rangeCount = 0;
ULONG cMMIORange = 0;
- PVBOXGUESTWINBASEADDRESS pBaseAddress = pDevExt->win.s.pciBaseAddress;
+ PVBOXGUESTWINBASEADDRESS pBaseAddress = pDevExt->pciBaseAddress;
for (ULONG i = 0; i < pResList->List->PartialResourceList.Count; i++)
{
pPartialData = &pResList->List->PartialResourceList.PartialDescriptors[i];
@@ -1100,14 +1106,15 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
/* Overflow protection. */
if (rangeCount < PCI_TYPE0_ADDRESSES)
{
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: I/O range: Base = %08x:%08x, Length = %08x\n",
- pPartialData->u.Port.Start.HighPart,
- pPartialData->u.Port.Start.LowPart,
- pPartialData->u.Port.Length));
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: I/O range: Base = %08x:%08x, Length = %08x\n",
+ pPartialData->u.Port.Start.HighPart,
+ pPartialData->u.Port.Start.LowPart,
+ pPartialData->u.Port.Length));
/* Save the IO port base. */
- /** @todo Not so good. */
- pDevExt->IOPortBase = (RTIOPORT)pPartialData->u.Port.Start.LowPart;
+ /** @todo Not so good.
+ * Update/bird: What is not so good? That we just consider the last range? */
+ pDevExt->Core.IOPortBase = (RTIOPORT)pPartialData->u.Port.Start.LowPart;
/* Save resource information. */
pBaseAddress->RangeStart = pPartialData->u.Port.Start;
@@ -1115,10 +1122,10 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
pBaseAddress->RangeInMemory = FALSE;
pBaseAddress->ResourceMapped = FALSE;
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: I/O range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
- pPartialData->u.Port.Start.HighPart,
- pPartialData->u.Port.Start.LowPart,
- pPartialData->u.Port.Length));
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: I/O range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
+ pPartialData->u.Port.Start.HighPart,
+ pPartialData->u.Port.Start.LowPart,
+ pPartialData->u.Port.Length));
/* Next item ... */
rangeCount++; pBaseAddress++;
@@ -1128,25 +1135,21 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
case CmResourceTypeInterrupt:
{
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Interrupt: Level = %x, Vector = %x, Mode = %x\n",
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Interrupt: Level = %x, Vector = %x, Mode = %x\n",
pPartialData->u.Interrupt.Level,
pPartialData->u.Interrupt.Vector,
pPartialData->Flags));
/* Save information. */
- pDevExt->win.s.interruptLevel = pPartialData->u.Interrupt.Level;
- pDevExt->win.s.interruptVector = pPartialData->u.Interrupt.Vector;
- pDevExt->win.s.interruptAffinity = pPartialData->u.Interrupt.Affinity;
+ pDevExt->interruptLevel = pPartialData->u.Interrupt.Level;
+ pDevExt->interruptVector = pPartialData->u.Interrupt.Vector;
+ pDevExt->interruptAffinity = pPartialData->u.Interrupt.Affinity;
/* Check interrupt mode. */
if (pPartialData->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
- {
- pDevExt->win.s.interruptMode = Latched;
- }
+ pDevExt->interruptMode = Latched;
else
- {
- pDevExt->win.s.interruptMode = LevelSensitive;
- }
+ pDevExt->interruptMode = LevelSensitive;
break;
}
@@ -1155,7 +1158,7 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
/* Overflow protection. */
if (rangeCount < PCI_TYPE0_ADDRESSES)
{
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Memory range: Base = %08x:%08x, Length = %08x\n",
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Memory range: Base = %08x:%08x, Length = %08x\n",
pPartialData->u.Memory.Start.HighPart,
pPartialData->u.Memory.Start.LowPart,
pPartialData->u.Memory.Length));
@@ -1166,8 +1169,8 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
&& (pPartialData->Flags & VBOX_CM_PRE_VISTA_MASK) == CM_RESOURCE_MEMORY_READ_WRITE)
{
/* Save physical MMIO base + length for VMMDev. */
- pDevExt->win.s.vmmDevPhysMemoryAddress = pPartialData->u.Memory.Start;
- pDevExt->win.s.vmmDevPhysMemoryLength = (ULONG)pPartialData->u.Memory.Length;
+ pDevExt->vmmDevPhysMemoryAddress = pPartialData->u.Memory.Start;
+ pDevExt->vmmDevPhysMemoryLength = (ULONG)pPartialData->u.Memory.Length;
/* Save resource information. */
pBaseAddress->RangeStart = pPartialData->u.Memory.Start;
@@ -1175,7 +1178,7 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
pBaseAddress->RangeInMemory = TRUE;
pBaseAddress->ResourceMapped = FALSE;
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Memory range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Memory range for VMMDev found! Base = %08x:%08x, Length = %08x\n",
pPartialData->u.Memory.Start.HighPart,
pPartialData->u.Memory.Start.LowPart,
pPartialData->u.Memory.Length));
@@ -1185,7 +1188,7 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
}
else
{
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Ignoring memory: Flags = %08x\n",
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Ignoring memory: Flags = %08x\n",
pPartialData->Flags));
}
}
@@ -1194,14 +1197,14 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
default:
{
- Log(("VBoxGuest::vboxguestwinScanPCIResourceList: Unhandled resource found, type = %d\n", pPartialData->Type));
+ Log(("VBoxGuest::vbgdNtScanPCIResourceList: Unhandled resource found, type = %d\n", pPartialData->Type));
break;
}
}
}
/* Memorize the number of resources found. */
- pDevExt->win.s.pciAddressCount = rangeCount;
+ pDevExt->pciAddressCount = rangeCount;
return rc;
}
@@ -1212,48 +1215,46 @@ NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTD
* @return NTSTATUS
*
* @param pDevExt The device extension.
- * @param physicalAdr Physical address to map.
- * @param ulLength Length (in bytes) to map.
+ * @param PhysAddr Physical address to map.
+ * @param cbToMap Number of bytes to map.
* @param ppvMMIOBase Pointer of mapped I/O base.
* @param pcbMMIO Length of mapped I/O base.
*/
-NTSTATUS vboxguestwinMapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt, PHYSICAL_ADDRESS physicalAdr, ULONG ulLength,
- void **ppvMMIOBase, uint32_t *pcbMMIO)
+NTSTATUS vbgdNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
+ void **ppvMMIOBase, uint32_t *pcbMMIO)
{
AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
AssertPtrReturn(ppvMMIOBase, VERR_INVALID_POINTER);
/* pcbMMIO is optional. */
NTSTATUS rc = STATUS_SUCCESS;
- if (physicalAdr.LowPart > 0) /* We're mapping below 4GB. */
+ if (PhysAddr.LowPart > 0) /* We're mapping below 4GB. */
{
- VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(physicalAdr, ulLength, MmNonCached);
- Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: pVMMDevMemory = 0x%x\n", pVMMDevMemory));
+ VMMDevMemory *pVMMDevMemory = (VMMDevMemory *)MmMapIoSpace(PhysAddr, cbToMap, MmNonCached);
+ Log(("VBoxGuest::vbgdNtMapVMMDevMemory: pVMMDevMemory = 0x%x\n", pVMMDevMemory));
if (pVMMDevMemory)
{
- Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: VMMDevMemory: Version = 0x%x, Size = %d\n",
+ Log(("VBoxGuest::vbgdNtMapVMMDevMemory: VMMDevMemory: Version = 0x%x, Size = %d\n",
pVMMDevMemory->u32Version, pVMMDevMemory->u32Size));
/* Check version of the structure; do we have the right memory version? */
- if (pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
- {
- Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: Wrong version (%u), refusing operation!\n",
- pVMMDevMemory->u32Version));
-
- /* Not our version, refuse operation and unmap the memory. */
- vboxguestwinUnmapVMMDevMemory(pDevExt);
- rc = STATUS_UNSUCCESSFUL;
- }
- else
+ if (pVMMDevMemory->u32Version == VMMDEV_MEMORY_VERSION)
{
/* Save results. */
*ppvMMIOBase = pVMMDevMemory;
if (pcbMMIO) /* Optional. */
*pcbMMIO = pVMMDevMemory->u32Size;
- Log(("VBoxGuest::vboxguestwinMapVMMDevMemory: VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n",
+ Log(("VBoxGuest::vbgdNtMapVMMDevMemory: VMMDevMemory found and mapped! pvMMIOBase = 0x%p\n",
*ppvMMIOBase));
}
+ else
+ {
+ /* Not our version, refuse operation and unmap the memory. */
+ Log(("VBoxGuest::vbgdNtMapVMMDevMemory: Wrong version (%u), refusing operation!\n", pVMMDevMemory->u32Version));
+ vbgdNtUnmapVMMDevMemory(pDevExt);
+ rc = STATUS_UNSUCCESSFUL;
+ }
}
else
rc = STATUS_UNSUCCESSFUL;
@@ -1267,34 +1268,34 @@ NTSTATUS vboxguestwinMapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt, PHYSICAL_ADDRESS
*
* @param pDevExt The device extension.
*/
-void vboxguestwinUnmapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt)
+void vbgdNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt)
{
- Log(("VBoxGuest::vboxguestwinUnmapVMMDevMemory: pVMMDevMemory = 0x%x\n", pDevExt->pVMMDevMemory));
- if (pDevExt->pVMMDevMemory)
+ Log(("VBoxGuest::vbgdNtUnmapVMMDevMemory: pVMMDevMemory = 0x%x\n", pDevExt->Core.pVMMDevMemory));
+ if (pDevExt->Core.pVMMDevMemory)
{
- MmUnmapIoSpace((void*)pDevExt->pVMMDevMemory, pDevExt->win.s.vmmDevPhysMemoryLength);
- pDevExt->pVMMDevMemory = NULL;
+ MmUnmapIoSpace((void*)pDevExt->Core.pVMMDevMemory, pDevExt->vmmDevPhysMemoryLength);
+ pDevExt->Core.pVMMDevMemory = NULL;
}
- pDevExt->win.s.vmmDevPhysMemoryAddress.QuadPart = 0;
- pDevExt->win.s.vmmDevPhysMemoryLength = 0;
+ pDevExt->vmmDevPhysMemoryAddress.QuadPart = 0;
+ pDevExt->vmmDevPhysMemoryLength = 0;
}
-VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
+VBOXOSTYPE vbgdNtVersionToOSType(VBGDNTVER enmNtVer)
{
VBOXOSTYPE enmOsType;
- switch (winVer)
+ switch (enmNtVer)
{
- case WINNT4:
+ case VBGDNTVER_WINNT4:
enmOsType = VBOXOSTYPE_WinNT4;
break;
- case WIN2K:
+ case VBGDNTVER_WIN2K:
enmOsType = VBOXOSTYPE_Win2k;
break;
- case WINXP:
+ case VBGDNTVER_WINXP:
#if ARCH_BITS == 64
enmOsType = VBOXOSTYPE_WinXP_x64;
#else
@@ -1302,7 +1303,7 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
#endif
break;
- case WIN2K3:
+ case VBGDNTVER_WIN2K3:
#if ARCH_BITS == 64
enmOsType = VBOXOSTYPE_Win2k3_x64;
#else
@@ -1310,7 +1311,7 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
#endif
break;
- case WINVISTA:
+ case VBGDNTVER_WINVISTA:
#if ARCH_BITS == 64
enmOsType = VBOXOSTYPE_WinVista_x64;
#else
@@ -1318,7 +1319,7 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
#endif
break;
- case WIN7:
+ case VBGDNTVER_WIN7:
#if ARCH_BITS == 64
enmOsType = VBOXOSTYPE_Win7_x64;
#else
@@ -1326,7 +1327,7 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
#endif
break;
- case WIN8:
+ case VBGDNTVER_WIN8:
#if ARCH_BITS == 64
enmOsType = VBOXOSTYPE_Win8_x64;
#else
@@ -1334,6 +1335,14 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
#endif
break;
+ case VBGDNTVER_WIN81:
+#if ARCH_BITS == 64
+ enmOsType = VBOXOSTYPE_Win81_x64;
+#else
+ enmOsType = VBOXOSTYPE_Win81;
+#endif
+ break;
+
default:
/* We don't know, therefore NT family. */
enmOsType = VBOXOSTYPE_WinNT;
@@ -1350,8 +1359,7 @@ VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer)
static uint32_t vboxugestwinAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32Mask)
{
AssertPtrReturn(pu32Bits, 0);
- LogFlowFunc(("*pu32Bits=0x%x, u32Mask=0x%x\n", *(long *)pu32Bits,
- u32Mask));
+ LogFlowFunc(("*pu32Bits=0x%x, u32Mask=0x%x\n", *(uint32_t *)pu32Bits, u32Mask));
uint32_t u32Result = 0;
uint32_t u32WorkingMask = u32Mask;
int iBitOffset = ASMBitFirstSetU32 (u32WorkingMask);
@@ -1369,8 +1377,7 @@ static uint32_t vboxugestwinAtomicBitsTestAndClear(void *pu32Bits, uint32_t u32M
}
-static void vboxguestwinTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits,
- uint32_t u32Exp)
+static void vbgdNtTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t u32Bits, uint32_t u32Exp)
{
ULONG u32Bits2 = u32Bits;
uint32_t u32Result = vboxugestwinAtomicBitsTestAndClear(&u32Bits2, u32Mask);
@@ -1385,104 +1392,134 @@ static void vboxguestwinTestAtomicTestAndClearBitsU32(uint32_t u32Mask, uint32_t
}
-static void vboxguestwinDoTests()
+static void vbgdNtDoTests(void)
{
- vboxguestwinTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
- vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0, 0);
- vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
- vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
- vboxguestwinTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
- vboxguestwinTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x00, 0x23, 0);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x11, 0, 0);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x11, 0x22, 0);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x11, 0x23, 0x1);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x11, 0x32, 0x10);
+ vbgdNtTestAtomicTestAndClearBitsU32(0x22, 0x23, 0x22);
}
#endif /* DEBUG */
#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
-#pragma pack(1)
+
+/*
+ * DPC latency checker.
+ */
+
+/**
+ * One DPC latency sample.
+ */
typedef struct DPCSAMPLE
{
- LARGE_INTEGER PerfDelta;
- LARGE_INTEGER PerfCounter;
- LARGE_INTEGER PerfFrequency;
- uint64_t u64TSC;
+ LARGE_INTEGER PerfDelta;
+ LARGE_INTEGER PerfCounter;
+ LARGE_INTEGER PerfFrequency;
+ uint64_t u64TSC;
} DPCSAMPLE;
+AssertCompileSize(DPCSAMPLE, 4*8);
+/**
+ * The DPC latency measurement workset.
+ */
typedef struct DPCDATA
{
- KDPC Dpc;
- KTIMER Timer;
- KSPIN_LOCK SpinLock;
+ KDPC Dpc;
+ KTIMER Timer;
+ KSPIN_LOCK SpinLock;
+
+ ULONG ulTimerRes;
- ULONG ulTimerRes;
+ bool volatile fFinished;
- LARGE_INTEGER DueTime;
+ /** The timer interval (relative). */
+ LARGE_INTEGER DueTime;
- BOOLEAN fFinished;
+ LARGE_INTEGER PerfCounterPrev;
- LARGE_INTEGER PerfCounterPrev;
+ /** Align the sample array on a 64 byte boundrary just for the off chance
+ * that we'll get cache line aligned memory backing this structure. */
+ uint32_t auPadding[ARCH_BITS == 32 ? 5 : 7];
- int iSampleCount;
- DPCSAMPLE aSamples[8192];
+ int cSamples;
+ DPCSAMPLE aSamples[8192];
} DPCDATA;
-#pragma pack(1)
-#define VBOXGUEST_DPC_TAG 'DPCS'
+AssertCompileMemberAlignment(DPCDATA, aSamples, 64);
+
+# define VBOXGUEST_DPC_TAG 'DPCS'
+
-static VOID DPCDeferredRoutine(struct _KDPC *Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
+/**
+ * DPC callback routine for the DPC latency measurement code.
+ *
+ * @param pDpc The DPC, not used.
+ * @param pvDeferredContext Pointer to the DPCDATA.
+ * @param SystemArgument1 System use, ignored.
+ * @param SystemArgument2 System use, ignored.
+ */
+static VOID vbgdNtDpcLatencyCallback(PKDPC pDpc, PVOID pvDeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
- DPCDATA *pData = (DPCDATA *)DeferredContext;
+ DPCDATA *pData = (DPCDATA *)pvDeferredContext;
KeAcquireSpinLockAtDpcLevel(&pData->SpinLock);
- if (pData->iSampleCount >= RT_ELEMENTS(pData->aSamples))
+ if (pData->cSamples >= RT_ELEMENTS(pData->aSamples))
+ pData->fFinished = true;
+ else
{
- pData->fFinished = 1;
- KeReleaseSpinLockFromDpcLevel(&pData->SpinLock);
- return;
- }
-
- DPCSAMPLE *pSample = &pData->aSamples[pData->iSampleCount++];
+ DPCSAMPLE *pSample = &pData->aSamples[pData->cSamples++];
- pSample->u64TSC = ASMReadTSC();
- pSample->PerfCounter = KeQueryPerformanceCounter(&pSample->PerfFrequency);
- pSample->PerfDelta.QuadPart = pSample->PerfCounter.QuadPart - pData->PerfCounterPrev.QuadPart;
+ pSample->u64TSC = ASMReadTSC();
+ pSample->PerfCounter = KeQueryPerformanceCounter(&pSample->PerfFrequency);
+ pSample->PerfDelta.QuadPart = pSample->PerfCounter.QuadPart - pData->PerfCounterPrev.QuadPart;
- pData->PerfCounterPrev.QuadPart = pSample->PerfCounter.QuadPart;
+ pData->PerfCounterPrev.QuadPart = pSample->PerfCounter.QuadPart;
- KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
+ KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
+ }
KeReleaseSpinLockFromDpcLevel(&pData->SpinLock);
}
-int VBoxGuestCommonIOCtl_DPC(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
- void *pvData, size_t cbData, size_t *pcbDataReturned)
-{
- int rc = VINF_SUCCESS;
- /* Allocate a non paged memory for samples and related data. */
+/**
+ * Handles the DPC latency checker request.
+ *
+ * @returns VBox status code.
+ */
+int VbgdNtIOCtl_DpcLatencyChecker(void)
+{
+ /*
+ * Allocate a block of non paged memory for samples and related data.
+ */
DPCDATA *pData = (DPCDATA *)ExAllocatePoolWithTag(NonPagedPool, sizeof(DPCDATA), VBOXGUEST_DPC_TAG);
-
if (!pData)
{
RTLogBackdoorPrintf("VBoxGuest: DPC: DPCDATA allocation failed.\n");
return VERR_NO_MEMORY;
}
- KeInitializeDpc(&pData->Dpc, DPCDeferredRoutine, pData);
+ /*
+ * Initialize the data.
+ */
+ KeInitializeDpc(&pData->Dpc, vbgdNtDpcLatencyCallback, pData);
KeInitializeTimer(&pData->Timer);
KeInitializeSpinLock(&pData->SpinLock);
- pData->fFinished = 0;
- pData->iSampleCount = 0;
+ pData->fFinished = false;
+ pData->cSamples = 0;
pData->PerfCounterPrev.QuadPart = 0;
pData->ulTimerRes = ExSetTimerResolution(1000 * 10, 1);
pData->DueTime.QuadPart = -(int64_t)pData->ulTimerRes / 10;
- /* Start the DPC measurements. */
+ /*
+ * Start the DPC measurements and wait for a full set.
+ */
KeSetTimer(&pData->Timer, pData->DueTime, &pData->Dpc);
while (!pData->fFinished)
@@ -1494,22 +1531,25 @@ int VBoxGuestCommonIOCtl_DPC(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSessio
ExSetTimerResolution(0, 0);
- /* Log everything to the host. */
+ /*
+ * Log everything to the host.
+ */
RTLogBackdoorPrintf("DPC: ulTimerRes = %d\n", pData->ulTimerRes);
- int i;
- for (i = 0; i < pData->iSampleCount; i++)
+ for (int i = 0; i < pData->cSamples; i++)
{
DPCSAMPLE *pSample = &pData->aSamples[i];
RTLogBackdoorPrintf("[%d] pd %lld pc %lld pf %lld t %lld\n",
- i,
- pSample->PerfDelta.QuadPart,
- pSample->PerfCounter.QuadPart,
- pSample->PerfFrequency.QuadPart,
- pSample->u64TSC);
+ i,
+ pSample->PerfDelta.QuadPart,
+ pSample->PerfCounter.QuadPart,
+ pSample->PerfFrequency.QuadPart,
+ pSample->u64TSC);
}
ExFreePoolWithTag(pData, VBOXGUEST_DPC_TAG);
- return rc;
+ return VINF_SUCCESS;
}
+
#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
+
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
index a3b02659..aee63677 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
@@ -1,8 +1,10 @@
+/* $Id: VBoxGuest-win.h $ */
/** @file
- *
* VBoxGuest - Windows specifics.
- *
- * Copyright (C) 2010 Oracle Corporation
+ */
+
+/*
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -16,9 +18,6 @@
#ifndef ___VBoxGuest_win_h
#define ___VBoxGuest_win_h
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
#include <iprt/cdefs.h>
@@ -37,14 +36,9 @@ RT_C_DECLS_END
#include <VBox/VMMDev.h>
#include <VBox/VBoxGuest.h>
+#include "VBoxGuestInternal.h"
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-
-/** Pointer to the VBoxGuest per session data. */
-typedef struct VBOXGUESTSESSION *PVBOXGUESTSESSION;
/** Possible device states for our state machine. */
enum DEVSTATE
@@ -77,6 +71,8 @@ typedef struct VBOXGUESTWINBASEADDRESS
/** Windows-specific device extension bits. */
typedef struct VBOXGUESTDEVEXTWIN
{
+ VBOXGUESTDEVEXT Core;
+
/** Our functional driver object. */
PDEVICE_OBJECT pDeviceObject;
/** Top of the stack. */
@@ -119,64 +115,69 @@ typedef struct VBOXGUESTDEVEXTWIN
VMMDevEvents *pIrqAckEvents;
/** Pre-allocated kernel session data. This is needed
- * for handling kernel IOCtls. */
- PVBOXGUESTSESSION pKernelSession;
+ * for handling kernel IOCtls. */
+ struct VBOXGUESTSESSION *pKernelSession;
/** Spinlock protecting MouseNotifyCallback. Required since the consumer is
* in a DPC callback and not the ISR. */
KSPIN_LOCK MouseEventAccessLock;
} VBOXGUESTDEVEXTWIN, *PVBOXGUESTDEVEXTWIN;
-#define VBOXGUEST_UPDATE_DEVSTATE(_pDevExt, _newDevState) do { \
- (_pDevExt)->win.s.prevDevState = (_pDevExt)->win.s.devState; \
- (_pDevExt)->win.s.devState = (_newDevState); \
-} while (0)
-
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
+/** NT (windows) version identifier. */
+typedef enum VBGDNTVER
+{
+ VBGDNTVER_INVALID = 0,
+ VBGDNTVER_WINNT4,
+ VBGDNTVER_WIN2K,
+ VBGDNTVER_WINXP,
+ VBGDNTVER_WIN2K3,
+ VBGDNTVER_WINVISTA,
+ VBGDNTVER_WIN7,
+ VBGDNTVER_WIN8,
+ VBGDNTVER_WIN81,
+} VBGDNTVER;
+extern VBGDNTVER g_enmVbgdNtVer;
+
+
+#define VBOXGUEST_UPDATE_DEVSTATE(a_pDevExt, a_newDevState) \
+ do { \
+ (a_pDevExt)->prevDevState = (a_pDevExt)->devState; \
+ (a_pDevExt)->devState = (a_newDevState); \
+ } while (0)
/** CM_RESOURCE_MEMORY_* flags which were used on XP or earlier. */
#define VBOX_CM_PRE_VISTA_MASK (0x3f)
-/** Windows version identifier. */
-typedef enum
-{
- WINNT4 = 1,
- WIN2K = 2,
- WINXP = 3,
- WIN2K3 = 4,
- WINVISTA = 5,
- WIN7 = 6,
- WIN8 = 7
-} winVersion_t;
-extern winVersion_t winVersion;
-
-
-/*******************************************************************************
-* Declared prototypes for helper routines used in both (PnP and legacy) *
-* driver versions. *
-*******************************************************************************/
-#include "VBoxGuestInternal.h"
RT_C_DECLS_BEGIN
+
#ifdef TARGET_NT4
-NTSTATUS vboxguestwinnt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath);
-NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath);
+NTSTATUS vbgdNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath);
#else
-NTSTATUS vboxguestwinInit(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+NTSTATUS vbgdNtInit(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+NTSTATUS vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+NTSTATUS vbgdNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp);
#endif
-NTSTATUS vboxguestwinCleanup(PDEVICE_OBJECT pDevObj);
-NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp);
-VOID vboxguestwinDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext);
-BOOLEAN vboxguestwinIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext);
-NTSTATUS vboxguestwinScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTDEVEXT pDevExt);
-NTSTATUS vboxguestwinMapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt, PHYSICAL_ADDRESS physicalAdr, ULONG ulLength,
- void **ppvMMIOBase, uint32_t *pcbMMIO);
-void vboxguestwinUnmapVMMDevMemory(PVBOXGUESTDEVEXT pDevExt);
-VBOXOSTYPE vboxguestwinVersionToOSType(winVersion_t winVer);
-NTSTATUS vboxguestwinPower(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+
+/** @name Common routines used in both (PnP and legacy) driver versions.
+ * @{
+ */
+#ifdef TARGET_NT4
+NTSTATUS vbgdNtInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath);
+#else
+NTSTATUS vbgdNtInit(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+#endif
+NTSTATUS vbgdNtCleanup(PDEVICE_OBJECT pDevObj);
+VOID vbgdNtDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext);
+BOOLEAN vbgdNtIsrHandler(PKINTERRUPT interrupt, PVOID serviceContext);
+NTSTATUS vbgdNtScanPCIResourceList(PCM_RESOURCE_LIST pResList, PVBOXGUESTDEVEXTWIN pDevExt);
+NTSTATUS vbgdNtMapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt, PHYSICAL_ADDRESS PhysAddr, ULONG cbToMap,
+ void **ppvMMIOBase, uint32_t *pcbMMIO);
+void vbgdNtUnmapVMMDevMemory(PVBOXGUESTDEVEXTWIN pDevExt);
+VBOXOSTYPE vbgdNtVersionToOSType(VBGDNTVER enmNtVer);
+/** @} */
+
RT_C_DECLS_END
#ifdef TARGET_NT4
@@ -184,9 +185,9 @@ RT_C_DECLS_END
* XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist
* on NT4, so... The same for ExAllocatePool.
*/
-#undef ExAllocatePool
-#undef ExFreePool
+# undef ExAllocatePool
+# undef ExFreePool
#endif
-#endif /* ___VBoxGuest_win_h */
+#endif /* !___VBoxGuest_win_h */
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
index 594e0921..b1ffd3ba 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2012 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -54,7 +54,7 @@
# include <Windows.h>
# endif
#endif
-#if defined(RT_OS_SOLARIS)
+#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
# include <iprt/rand.h>
#endif
@@ -70,17 +70,61 @@ static void testSetMouseStatus(void);
#endif
static int VBoxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures);
-#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
-int VBoxGuestCommonIOCtl_DPC(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
- void *pvData, size_t cbData, size_t *pcbDataReturned);
-#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
+static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags);
+
+#define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
+
+DECLINLINE(uint32_t) VBoxGuestCommonGetHandledEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ if (!pDevExt->u32AcquireModeGuestCaps)
+ return VMMDEV_EVENT_VALID_EVENT_MASK;
+
+ uint32_t u32AllowedGuestCaps = pSession->u32AquiredGuestCaps | (VMMDEV_EVENT_VALID_EVENT_MASK & ~pDevExt->u32AcquireModeGuestCaps);
+ uint32_t u32CleanupEvents = VBOXGUEST_ACQUIRE_STYLE_EVENTS;
+ if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)
+ u32CleanupEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
+ if (u32AllowedGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
+ u32CleanupEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
+
+ return VMMDEV_EVENT_VALID_EVENT_MASK & ~u32CleanupEvents;
+}
+
+DECLINLINE(uint32_t) VBoxGuestCommonGetAndCleanPendingEventsLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fReqEvents)
+{
+ uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents & VBoxGuestCommonGetHandledEventsLocked(pDevExt, pSession);
+ if (fMatches)
+ ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
+ return fMatches;
+}
+
+DECLINLINE(bool) VBoxGuestCommonGuestCapsModeSet(PVBOXGUESTDEVEXT pDevExt, uint32_t fCaps, bool fAcquire, uint32_t *pu32OtherVal)
+{
+ uint32_t *pVal = fAcquire ? &pDevExt->u32AcquireModeGuestCaps : &pDevExt->u32SetModeGuestCaps;
+ const uint32_t fNotVal = !fAcquire ? pDevExt->u32AcquireModeGuestCaps : pDevExt->u32SetModeGuestCaps;
+ bool fResult = true;
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+
+ if (!(fNotVal & fCaps))
+ *pVal |= fCaps;
+ else
+ {
+ AssertMsgFailed(("trying to change caps mode\n"));
+ fResult = false;
+ }
+
+ RTSpinlockReleaseNoInts(pDevExt->EventSpinlock);
+
+ if (pu32OtherVal)
+ *pu32OtherVal = fNotVal;
+ return fResult;
+}
/*******************************************************************************
* Global Variables *
*******************************************************************************/
static const size_t cbChangeMemBalloonReq = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
-#if defined(RT_OS_SOLARIS)
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
/**
* Drag in the rest of IRPT since we share it with the
* rest of the kernel modules on Solaris.
@@ -100,7 +144,7 @@ PFNRT g_apfnVBoxGuestIPRTDeps[] =
(PFNRT)RTSemMutexIsOwned,
NULL
};
-#endif /* RT_OS_SOLARIS */
+#endif /* RT_OS_DARWIN || RT_OS_SOLARIS */
/**
@@ -418,7 +462,7 @@ static int vboxGuestSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBal
pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAllocZ(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
if (!pDevExt->MemBalloon.paMemObj)
{
- LogRel(("VBoxGuestSetBalloonSizeKernel: no memory for paMemObj!\n"));
+ LogRel(("vboxGuestSetBalloonSizeKernel: no memory for paMemObj!\n"));
return VERR_NO_MEMORY;
}
}
@@ -706,6 +750,20 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
int rc, rc2;
unsigned i;
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ /*
+ * Create the release log.
+ */
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ PRTLOGGER pRelLogger;
+ rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
+ "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
+ if (RT_SUCCESS(rc))
+ RTLogRelSetDefaultInstance(pRelLogger);
+ /** @todo Add native hook for getting logger config parameters and setting
+ * them. On linux we should use the module parameter stuff... */
+#endif
+
/*
* Adjust fFixedEvents.
*/
@@ -772,6 +830,10 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size, cbMMIO));
}
+ pDevExt->u32AcquireModeGuestCaps = 0;
+ pDevExt->u32SetModeGuestCaps = 0;
+ pDevExt->u32GuestCaps = 0;
+
/*
* Create the wait and session spinlocks as well as the ballooning mutex.
*/
@@ -856,6 +918,11 @@ int VBoxGuestInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
rc2 = RTSemFastMutexDestroy(pDevExt->MemBalloon.hMtx); AssertRC(rc2);
rc2 = RTSpinlockDestroy(pDevExt->EventSpinlock); AssertRC(rc2);
rc2 = RTSpinlockDestroy(pDevExt->SessionSpinlock); AssertRC(rc2);
+
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
return rc; /* (failed) */
}
@@ -925,6 +992,12 @@ void VBoxGuestDeleteDevExt(PVBOXGUESTDEVEXT pDevExt)
pDevExt->IOPortBase = 0;
pDevExt->pIrqAckEvents = NULL;
+
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+
}
@@ -987,7 +1060,7 @@ int VBoxGuestCreateKernelSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *pp
return VINF_SUCCESS;
}
-
+static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
/**
* Closes a VBoxGuest session.
@@ -1001,6 +1074,10 @@ void VBoxGuestCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
Log(("VBoxGuestCloseSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
+ VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE);
+
+ VBoxGuestCommonIOCtl_CancelAllWaitEvents(pDevExt, pSession);
+
#ifdef VBOX_WITH_HGCM
for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
if (pSession->aHGCMClientIds[i])
@@ -1291,13 +1368,12 @@ int VBoxGuestCommonIOCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGu
*
* @returns VINF_SUCCESS if we've left the spinlock and can return immediately.
*/
-DECLINLINE(int) WaitEventCheckCondition(PVBOXGUESTDEVEXT pDevExt, VBoxGuestWaitEventInfo *pInfo,
+DECLINLINE(int) WaitEventCheckCondition(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestWaitEventInfo *pInfo,
int iEvent, const uint32_t fReqEvents)
{
- uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents;
+ uint32_t fMatches = VBoxGuestCommonGetAndCleanPendingEventsLocked(pDevExt, pSession, fReqEvents);
if (fMatches)
{
- ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
RTSpinlockReleaseNoInts(pDevExt->EventSpinlock);
pInfo->u32EventFlagsOut = fMatches;
@@ -1333,7 +1409,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE
iEvent = ASMBitFirstSetU32(fReqEvents) - 1;
if (RT_UNLIKELY(iEvent < 0))
{
- Log(("VBoxGuestCommonIOCtl: WAITEVENT: Invalid input mask %#x!!\n", fReqEvents));
+ LogRel(("VBoxGuestCommonIOCtl: WAITEVENT: Invalid input mask %#x!!\n", fReqEvents));
return VERR_INVALID_PARAMETER;
}
@@ -1341,7 +1417,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE
* Check the condition up front, before doing the wait-for-event allocations.
*/
RTSpinlockAcquire(pDevExt->EventSpinlock);
- rc = WaitEventCheckCondition(pDevExt, pInfo, iEvent, fReqEvents);
+ rc = WaitEventCheckCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
if (rc == VINF_SUCCESS)
return rc;
@@ -1364,7 +1440,7 @@ static int VBoxGuestCommonIOCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSE
*/
RTSpinlockAcquire(pDevExt->EventSpinlock);
RTListAppend(&pDevExt->WaitList, &pWait->ListNode);
- rc = WaitEventCheckCondition(pDevExt, pInfo, iEvent, fReqEvents);
+ rc = WaitEventCheckCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
if (rc == VINF_SUCCESS)
{
VBoxGuestWaitFreeUnlocked(pDevExt, pWait);
@@ -1465,6 +1541,7 @@ static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PV
}
RTSpinlockReleaseNoInts(pDevExt->EventSpinlock);
Assert(rc == 0);
+ NOREF(rc);
#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
VBoxGuestWaitDoWakeUps(pDevExt);
@@ -1481,7 +1558,7 @@ static int VBoxGuestCommonIOCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PV
* @param enmType The request type.
* @param pReqHdr The request.
*/
-static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevRequestType enmType,
+static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VMMDevRequestType enmType,
VMMDevRequestHeader const *pReqHdr)
{
/*
@@ -1541,12 +1618,34 @@ static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevReque
case VMMDevReq_GetPageSharingStatus:
case VMMDevReq_DebugIsPageShared:
case VMMDevReq_ReportGuestStats:
+ case VMMDevReq_ReportGuestUserState:
case VMMDevReq_GetStatisticsChangeRequest:
case VMMDevReq_ChangeMemBalloon:
enmRequired = kLevel_TrustedUsers;
break;
/*
+ * Anyone. But not for CapsAcquire mode
+ */
+ case VMMDevReq_SetGuestCapabilities:
+ {
+ VMMDevReqGuestCapabilities2 *pCaps = (VMMDevReqGuestCapabilities2*)pReqHdr;
+ uint32_t fAcquireCaps = 0;
+ if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, pCaps->u32OrMask, false, &fAcquireCaps))
+ {
+ AssertFailed();
+ LogRel(("calling caps set for acquired caps %d\n", pCaps->u32OrMask));
+ enmRequired = kLevel_NoOne;
+ break;
+ }
+ /* hack to adjust the notcaps.
+ * @todo: move to a better place
+ * user-mode apps are allowed to pass any mask to the notmask,
+ * the driver cleans up them accordingly */
+ pCaps->u32NotMask &= ~fAcquireCaps;
+ /* do not break, make it fall through to the below enmRequired setting */
+ }
+ /*
* Anyone.
*/
case VMMDevReq_GetMouseStatus:
@@ -1563,11 +1662,11 @@ static int VBoxGuestCheckIfVMMReqAllowed(PVBOXGUESTSESSION pSession, VMMDevReque
case VMMDevReq_VideoModeSupported:
case VMMDevReq_GetHeightReduction:
case VMMDevReq_GetDisplayChangeRequest2:
- case VMMDevReq_SetGuestCapabilities:
case VMMDevReq_VideoModeSupported2:
case VMMDevReq_VideoAccelEnable:
case VMMDevReq_VideoAccelFlush:
case VMMDevReq_VideoSetVisibleRegion:
+ case VMMDevReq_GetDisplayChangeRequestEx:
case VMMDevReq_GetSeamlessChangeRequest:
case VMMDevReq_GetVRDPChangeRequest:
case VMMDevReq_LogString:
@@ -1641,13 +1740,13 @@ static int VBoxGuestCommonIOCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTS
if (cbReq < cbMinSize)
{
- Log(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n",
+ LogRel(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n",
cbReq, cbMinSize, enmType));
return VERR_INVALID_PARAMETER;
}
if (cbReq > cbData)
{
- Log(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n",
+ LogRel(("VBoxGuestCommonIOCtl: VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n",
cbData, cbReq, enmType));
return VERR_INVALID_PARAMETER;
}
@@ -1659,7 +1758,7 @@ static int VBoxGuestCommonIOCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTS
return rc;
}
- rc = VBoxGuestCheckIfVMMReqAllowed(pSession, enmType, pReqHdr);
+ rc = VBoxGuestCheckIfVMMReqAllowed(pDevExt, pSession, enmType, pReqHdr);
if (RT_FAILURE(rc))
{
Log(("VBoxGuestCommonIOCtl: VMMREQUEST: Operation not allowed! type=%#x rc=%Rrc\n", enmType, rc));
@@ -1974,7 +2073,7 @@ static int VBoxGuestCommonIOCtl_HGCMCall(PVBOXGUESTDEVEXT pDevExt,
if (cbData < cbActual)
{
LogRel(("VBoxGuestCommonIOCtl: HGCM_CALL: cbData=%#zx (%zu) required size is %#zx (%zu)\n",
- cbData, cbActual));
+ cbData, cbData, cbActual, cbActual));
return VERR_INVALID_PARAMETER;
}
@@ -2283,6 +2382,9 @@ static int VBoxGuestCommonIOCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGU
RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ /* For all the bits which the guest is allowed to set, check whether the
+ * requested value is different to the current one and adjust the global
+ * usage counter and if appropriate the global state if so. */
for (i = 0; i < sizeof(fFeatures) * 8; i++)
{
if (RT_BIT_32(i) & VMMDEV_MOUSE_GUEST_MASK)
@@ -2417,6 +2519,170 @@ static int VBoxGuestCommonIOCtl_Log(PVBOXGUESTDEVEXT pDevExt, const char *pch, s
return VINF_SUCCESS;
}
+static bool VBoxGuestCommonGuestCapsValidateValues(uint32_t fCaps)
+{
+ if (fCaps & (~(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING | VMMDEV_GUEST_SUPPORTS_GRAPHICS)))
+ return false;
+
+ return true;
+}
+
+static void VBoxGuestCommonCheckEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fGenFakeEvents)
+{
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ uint32_t fEvents = fGenFakeEvents | pDevExt->f32PendingEvents;
+ PVBOXGUESTWAIT pWait;
+ PVBOXGUESTWAIT pSafe;
+
+ RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
+ {
+ uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession);
+ if ( (pWait->fReqEvents & fEvents & fHandledEvents)
+ && !pWait->fResEvents)
+ {
+ pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
+ Assert(!(fGenFakeEvents & pWait->fResEvents) || pSession == pWait->pSession);
+ fEvents &= ~pWait->fResEvents;
+ RTListNodeRemove(&pWait->ListNode);
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
+#else
+ RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
+ int rc = RTSemEventMultiSignal(pWait->Event);
+ AssertRC(rc);
+#endif
+ if (!fEvents)
+ break;
+ }
+ }
+ ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
+
+ RTSpinlockReleaseNoInts(pDevExt->EventSpinlock);
+
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ VBoxGuestWaitDoWakeUps(pDevExt);
+#endif
+}
+
+static int VBoxGuestCommonGuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags)
+{
+ uint32_t fSetCaps = 0;
+
+ if (!VBoxGuestCommonGuestCapsValidateValues(fOrMask))
+ {
+ LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid fOrMask\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if ( enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
+ && enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_NONE)
+ {
+ LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- invalid enmFlags %d\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!VBoxGuestCommonGuestCapsModeSet(pDevExt, fOrMask, true, &fSetCaps))
+ {
+ LogRel(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- calling caps acquire for set caps\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_STATE;
+ }
+
+ if (enmFlags & VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE)
+ {
+ Log(("VBoxGuestCommonGuestCapsAcquire: pSession(0x%p), OR(0x%x), NOT(0x%x), flags(0x%x) -- configured acquire caps: 0x%x\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VINF_SUCCESS;
+ }
+
+ /* the fNotMask no need to have all values valid,
+ * invalid ones will simply be ignored */
+ uint32_t fCurrentOwnedCaps;
+ uint32_t fSessionNotCaps;
+ uint32_t fSessionOrCaps;
+ uint32_t fOtherConflictingCaps;
+
+ fNotMask &= ~fOrMask;
+
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+
+ fCurrentOwnedCaps = pSession->u32AquiredGuestCaps;
+ fSessionNotCaps = fCurrentOwnedCaps & fNotMask;
+ fSessionOrCaps = fOrMask & ~fCurrentOwnedCaps;
+ fOtherConflictingCaps = pDevExt->u32GuestCaps & ~fCurrentOwnedCaps;
+ fOtherConflictingCaps &= fSessionOrCaps;
+
+ if (!fOtherConflictingCaps)
+ {
+ if (fSessionOrCaps)
+ {
+ pSession->u32AquiredGuestCaps |= fSessionOrCaps;
+ pDevExt->u32GuestCaps |= fSessionOrCaps;
+ }
+
+ if (fSessionNotCaps)
+ {
+ pSession->u32AquiredGuestCaps &= ~fSessionNotCaps;
+ pDevExt->u32GuestCaps &= ~fSessionNotCaps;
+ }
+ }
+
+ RTSpinlockReleaseNoInts(pDevExt->EventSpinlock);
+
+ if (fOtherConflictingCaps)
+ {
+ Log(("VBoxGuest: Caps 0x%x were busy\n", fOtherConflictingCaps));
+ return VERR_RESOURCE_BUSY;
+ }
+
+ /* now do host notification outside the lock */
+ if (!fSessionOrCaps && !fSessionNotCaps)
+ {
+ /* no changes, return */
+ return VINF_SUCCESS;
+ }
+
+ int rc = VBoxGuestSetGuestCapabilities(fSessionOrCaps, fSessionNotCaps);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VBoxGuestCommonGuestCapsAcquire: VBoxGuestSetGuestCapabilities failed, rc=%Rrc\n", rc));
+
+ /* Failure branch
+ * this is generally bad since e.g. failure to release the caps may result in other sessions not being able to use it
+ * so we are not trying to restore the caps back to their values before the VBoxGuestCommonGuestCapsAcquire call,
+ * but just pretend everithing is OK.
+ * @todo: better failure handling mechanism? */
+ }
+
+ /* success! */
+ uint32_t fGenFakeEvents = 0;
+
+ if (fSessionOrCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
+ {
+ /* generate the seamless change event so that the r3 app could synch with the seamless state
+ * although this introduces a false alarming of r3 client, it still solve the problem of
+ * client state inconsistency in multiuser environment */
+ fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
+ }
+
+ /* since the acquire filter mask has changed, we need to process events in any way to ensure they go from pending events field
+ * to the proper (un-filtered) entries */
+ VBoxGuestCommonCheckEvents(pDevExt, pSession, fGenFakeEvents);
+
+ return VINF_SUCCESS;
+}
+
+static int VBoxGuestCommonIOCTL_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestCapsAquire *pAcquire)
+{
+ int rc = VBoxGuestCommonGuestCapsAcquire(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags);
+ if (RT_FAILURE(rc))
+ LogRel(("VBoxGuestCommonGuestCapsAcquire: failed rc=%Rrc\n", rc));
+ pAcquire->rc = rc;
+ return VINF_SUCCESS;
+}
+
/**
* Common IOCtl for user to kernel and kernel to kernel communication.
@@ -2477,7 +2743,7 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES
if (cbData != (cb)) \
{ \
LogFunc((mnemonic ": cbData=%#zx (%zu) expected is %#zx (%zu)\n", \
- cbData, cbData, (size_t)(cb), (size_t)(cb))); \
+ cbData, cbData, (size_t)(cb), (size_t)(cb))); \
return VERR_BUFFER_OVERFLOW; \
} \
if ((cb) != 0 && !VALID_PTR(pvData)) \
@@ -2497,12 +2763,6 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES
CHECKRET_MIN_SIZE("VMMREQUEST", sizeof(VMMDevRequestHeader));
rc = VBoxGuestCommonIOCtl_VMMRequest(pDevExt, pSession, (VMMDevRequestHeader *)pvData, cbData, pcbDataReturned);
}
-#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
- else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_DPC))
- {
- rc = VBoxGuestCommonIOCtl_DPC(pDevExt, pSession, pvData, cbData, pcbDataReturned);
- }
-#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
#ifdef VBOX_WITH_HGCM
/*
* These ones are a bit tricky.
@@ -2640,10 +2900,23 @@ int VBoxGuestCommonIOCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUES
*(uint32_t *)pvData);
break;
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+ case VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER:
+ CHECKRET_SIZE("DPC_LATENCY_CHECKER", 0);
+ rc = VbgdNtIOCtl_DpcLatencyChecker();
+ break;
+#endif
+
+ case VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE:
+ CHECKRET_SIZE("GUEST_CAPS_ACQUIRE", sizeof(VBoxGuestCapsAquire));
+ rc = VBoxGuestCommonIOCTL_GuestCapsAcquire(pDevExt, pSession, (VBoxGuestCapsAquire*)pvData);
+ *pcbDataReturned = sizeof(VBoxGuestCapsAquire);
+ break;
+
default:
{
- LogRel(("VBoxGuestCommonIOCtl: Unknown request iFunction=%#x Stripped size=%#x\n", iFunction,
- VBOXGUEST_IOCTL_STRIP_SIZE(iFunction)));
+ LogRel(("VBoxGuestCommonIOCtl: Unknown request iFunction=%#x stripped size=%#x\n",
+ iFunction, VBOXGUEST_IOCTL_STRIP_SIZE(iFunction)));
rc = VERR_NOT_SUPPORTED;
break;
}
@@ -2704,7 +2977,7 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt)
PVBOXGUESTWAIT pWait;
PVBOXGUESTWAIT pSafe;
- Log(("VBoxGuestCommonISR: acknowledge events succeeded %#RX32\n", fEvents));
+ Log3(("VBoxGuestCommonISR: acknowledge events succeeded %#RX32\n", fEvents));
/*
* VMMDEV_EVENT_MOUSE_POSITION_CHANGED can only be polled for.
@@ -2748,10 +3021,11 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt)
fEvents |= pDevExt->f32PendingEvents;
RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
{
- if ( (pWait->fReqEvents & fEvents)
+ uint32_t fHandledEvents = VBoxGuestCommonGetHandledEventsLocked(pDevExt, pWait->pSession);
+ if ( (pWait->fReqEvents & fEvents & fHandledEvents)
&& !pWait->fResEvents)
{
- pWait->fResEvents = pWait->fReqEvents & fEvents;
+ pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
fEvents &= ~pWait->fResEvents;
RTListNodeRemove(&pWait->ListNode);
#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
@@ -2800,6 +3074,7 @@ bool VBoxGuestCommonISR(PVBOXGUESTDEVEXT pDevExt)
ASMAtomicDecU32(&pDevExt->cISR);
Assert(rc == 0);
+ NOREF(rc);
return fOurIrq;
}
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm b/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
index bb8757f1..008dd625 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
@@ -4,7 +4,7 @@
;
;
-; Copyright (C) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+; Copyright (C) 2007-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -20,7 +20,7 @@
;
; VBoxDrv - OS/2 assembly file, the first file in the link.
;
-; Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+; Copyright (c) 2007-2010 knut st. osmundsen <bird-src-spam@anduin.net>
;
; Permission is hereby granted, free of charge, to any person
; obtaining a copy of this software and associated documentation
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuestIDC-unix.c.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuestIDC-unix.c.h
index 87ad299b..de0a5125 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuestIDC-unix.c.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuestIDC-unix.c.h
@@ -1,4 +1,4 @@
-/* $Rev: 78530 $ */
+/* $Rev: 84795 $ */
/** @file
* VBoxGuest - Inter Driver Communication, unix implementation.
*
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,9 +28,12 @@
/** @todo Use some header that we have in common with VBoxGuestLib.h... */
-DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version);
-DECLVBGL(int) VBoxGuestIDCClose(void *pvSession);
-DECLVBGL(int) VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+/** @todo fix DECLVBGL usage. */
+RT_C_DECLS_BEGIN
+DECLEXPORT(void *) VBOXCALL VBoxGuestIDCOpen(uint32_t *pu32Version);
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCClose(void *pvSession);
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+RT_C_DECLS_END
/**
@@ -39,7 +42,7 @@ DECLVBGL(int) VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, siz
* @returns Opaque pointer to session object.
* @param pu32Version Where to store VMMDev version.
*/
-DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version)
+DECLEXPORT(void *) VBOXCALL VBoxGuestIDCOpen(uint32_t *pu32Version)
{
PVBOXGUESTSESSION pSession;
int rc;
@@ -96,7 +99,7 @@ DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version)
* @returns VBox error code.
* @param pvState Opaque pointer to the session object.
*/
-DECLVBGL(int) VBoxGuestIDCClose(void *pvSession)
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCClose(void *pvSession)
{
PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
LogFlow(("VBoxGuestIDCClose:\n"));
@@ -131,7 +134,7 @@ DECLVBGL(int) VBoxGuestIDCClose(void *pvSession)
* @param cbData Size of the data buffer.
* @param pcbDataReturned Where to store the amount of returned data.
*/
-DECLVBGL(int) VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
{
PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
LogFlow(("VBoxGuestIDCCall: %pvSession=%p Cmd=%u pvData=%p cbData=%d\n", pvSession, iCmd, pvData, cbData));
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
index 5a15aeee..e91b7678 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
@@ -107,7 +107,6 @@ typedef struct VBOXGUESTMEMBALLOON
/** Pointer to a memory balloon. */
typedef VBOXGUESTMEMBALLOON *PVBOXGUESTMEMBALLOON;
-
/**
* VBox guest device (data) extension.
*/
@@ -180,17 +179,12 @@ typedef struct VBOXGUESTDEVEXT
uint32_t volatile cISR;
/** Callback and user data for a kernel mouse handler. */
VBoxGuestMouseSetNotifyCallback MouseNotifyCallback;
-
- /** Windows part. */
- union
- {
-#ifdef ___VBoxGuest_win_h
- VBOXGUESTDEVEXTWIN s;
-#else
- uint32_t dummy;
-#endif
- } win;
-
+ /* list of caps used in acquire mode */
+ uint32_t u32AcquireModeGuestCaps;
+ /* list of caps used in set mode */
+ uint32_t u32SetModeGuestCaps;
+ /* currently acquired (and reported) guest caps */
+ uint32_t u32GuestCaps;
} VBOXGUESTDEVEXT;
/** Pointer to the VBoxGuest driver data. */
typedef VBOXGUESTDEVEXT *PVBOXGUESTDEVEXT;
@@ -205,7 +199,7 @@ typedef VBOXGUESTDEVEXT *PVBOXGUESTDEVEXT;
*/
typedef struct VBOXGUESTSESSION
{
-#if defined(RT_OS_OS2) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS)
/** Pointer to the next session with the same hash. */
PVBOXGUESTSESSION pNextHash;
#endif
@@ -234,7 +228,14 @@ typedef struct VBOXGUESTSESSION
/** Mouse features supported. A feature enabled in any guest session will
* be enabled for the host. */
uint32_t volatile fMouseStatus;
-
+#ifdef RT_OS_DARWIN
+ /** Pointer to the associated org_virtualbox_VBoxGuestClient object. */
+ void *pvVBoxGuestClient;
+ /** Whether this session has been opened or not. */
+ bool fOpened;
+#endif
+ /* Guest Caps Acquired & Reported by this session */
+ uint32_t u32AquiredGuestCaps;
} VBOXGUESTSESSION;
RT_C_DECLS_BEGIN
@@ -274,6 +275,11 @@ DECLVBGL(int) VBoxGuestNativeServiceCall(void *pvOpaque, unsigned int iCmd, v
*/
void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt);
+
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+int VbgdNtIOCtl_DpcLatencyChecker(void);
+#endif
+
RT_C_DECLS_END
#endif
diff --git a/src/VBox/Additions/common/VBoxGuest/darwin/Info.plist b/src/VBox/Additions/common/VBoxGuest/darwin/Info.plist
new file mode 100644
index 00000000..30cd22b9
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/darwin/Info.plist
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleExecutable</key> <string>VBoxGuest</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxGuest</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>VBoxGuest</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>NSHumanReadableCopyright</key> <string>Copyright © 2007-@VBOX_C_YEAR@ @VBOX_VENDOR@</string>
+ <key>CFBundleGetInfoString</key> <string>@VBOX_PRODUCT@ @VBOX_VERSION_STRING@, © 2007-@VBOX_C_YEAR@ @VBOX_VENDOR@</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>OSBundleCompatibleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ <key>VBoxGuest</key>
+ <dict>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxGuest</string>
+ <key>IOClass</key> <string>org_virtualbox_VBoxGuest</string>
+ <key>IOMatchCategory</key> <string>org_virtualbox_VBoxGuest</string>
+ <key>IOUserClientClass</key> <string>org_virtualbox_VBoxGuestClient</string>
+ <key>IOKitDebug</key> <integer>65535</integer>
+ <key>IOProviderClass</key> <string>IOPCIDevice</string>
+ <key>IONameMatch</key> <string>pci80ee,cafe</string>
+ </dict>
+ </dict>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.iokit.IOPCIFamily</key> <string>2.5</string> <!-- TODO: Figure the version in mac os x 10.4. -->
+ <key>com.apple.kpi.bsd</key> <string>8.0.0</string>
+ <key>com.apple.kpi.mach</key> <string>8.0.0</string>
+ <key>com.apple.kpi.libkern</key> <string>8.0.0</string>
+ <key>com.apple.kpi.unsupported</key> <string>8.0.0</string>
+ <key>com.apple.kpi.iokit</key> <string>8.0.0</string>
+ </dict>
+ <key>OSBundleLibraries_x86_64</key>
+ <dict>
+ <key>com.apple.iokit.IOPCIFamily</key> <string>2.6</string>
+ <key>com.apple.kpi.bsd</key> <string>10.0.0d4</string>
+ <key>com.apple.kpi.mach</key> <string>10.0.0d3</string>
+ <key>com.apple.kpi.libkern</key> <string>10.0.0d3</string>
+ <key>com.apple.kpi.iokit</key> <string>10.0.0d3</string>
+ <key>com.apple.kpi.unsupported</key> <string>10.0.0d3</string>
+ </dict>
+</dict>
+</plist>
+
diff --git a/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile b/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile
index c0326547..a25cc9f2 100644
--- a/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile
+++ b/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2006-2009 Oracle Corporation
+# Copyright (C) 2006-2012 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/linux/Makefile b/src/VBox/Additions/common/VBoxGuest/linux/Makefile
index 5b03a9a1..09f8bbc1 100644
--- a/src/VBox/Additions/common/VBoxGuest/linux/Makefile
+++ b/src/VBox/Additions/common/VBoxGuest/linux/Makefile
@@ -1,10 +1,10 @@
-# $Revision: 79403 $
+# $Revision: 83575 $
## @file
# VirtualBox Guest Additions Module Makefile.
#
#
-# Copyright (C) 2006-2011 Oracle Corporation
+# Copyright (C) 2006-2012 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/linux/files_vboxguest b/src/VBox/Additions/common/VBoxGuest/linux/files_vboxguest
index f733baa0..f9f8a9d7 100755
--- a/src/VBox/Additions/common/VBoxGuest/linux/files_vboxguest
+++ b/src/VBox/Additions/common/VBoxGuest/linux/files_vboxguest
@@ -5,7 +5,7 @@
#
#
-# Copyright (C) 2007-2010 Oracle Corporation
+# Copyright (C) 2007-2012 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuest.inf b/src/VBox/Additions/common/VBoxGuest/win/VBoxGuest.inf
index 09b56d39..04932fca 100644
--- a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuest.inf
+++ b/src/VBox/Additions/common/VBoxGuest/win/VBoxGuest.inf
@@ -1,7 +1,10 @@
+; $Id: VBoxGuest.inf $
+;; @file
+; INF file for installing the VirtualBox Windows guest driver.
;
-; INF file for installing the VirtualBox Windows guest driver
+
;
-; Copyright (C) 2006-2011 Oracle Corporation
+; Copyright (C) 2006-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestInst.cpp b/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestInst.cpp
index eb9a7b69..3f76ef9d 100644
--- a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestInst.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestInst.cpp
@@ -1,8 +1,10 @@
+/* $Id: VBoxGuestInst.cpp $ */
/** @file
- *
- * Small tool to (un)install the VBoxGuest device driver
- *
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Small tool to (un)install the VBoxGuest device driver.
+ */
+
+/*
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,7 +32,7 @@
-int installDriver(void)
+static int installDriver(void)
{
/*
* Assume it didn't exist, so we'll create the service.
@@ -57,17 +59,14 @@ int installDriver(void)
"System",
NULL, NULL, NULL, NULL);
if (!hService)
- {
printf("CreateService failed! lasterr=%d\n", GetLastError());
- } else
- {
+ else
CloseServiceHandle(hService);
- }
CloseServiceHandle(hSMgrCreate);
return hService ? 0 : -1;
}
-int uninstallDriver(void)
+static int uninstallDriver(void)
{
int rc = -1;
SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
@@ -96,8 +95,9 @@ int uninstallDriver(void)
return rc;
}
+#ifdef TESTMODE
-HANDLE openDriver(void)
+static HANDLE openDriver(void)
{
HANDLE hDevice;
@@ -115,43 +115,32 @@ HANDLE openDriver(void)
return hDevice;
}
-int closeDriver(HANDLE hDevice)
+static int closeDriver(HANDLE hDevice)
{
CloseHandle(hDevice);
return 0;
}
-#ifdef TESTMODE
-typedef struct TESTFOO
-{
- int values[16];
-} TESTFOO, *PTESTFOO;
-
-int performTest(void)
+static int performTest(void)
{
int rc = 0;
HANDLE hDevice = openDriver();
if (hDevice != INVALID_HANDLE_VALUE)
- {
- DWORD cbReturned;
-
closeDriver(hDevice);
- } else
- {
+ else
printf("openDriver failed!\n");
- }
-
return rc;
}
-#endif
-void displayHelpAndExit(char *programName)
+#endif /* TESTMODE */
+
+static int usage(char *programName)
{
printf("error, syntax: %s [install|uninstall]\n", programName);
- exit(1);
+ return 1;
}
int main(int argc, char **argv)
@@ -162,50 +151,36 @@ int main(int argc, char **argv)
#endif
if (argc != 2)
- {
- displayHelpAndExit(argv[0]);
- }
+ return usage(argv[0]);
+
if (strcmp(argv[1], "install") == 0)
- {
installMode = true;
- } else
- if (strcmp(argv[1], "uninstall") == 0)
- {
+ else if (strcmp(argv[1], "uninstall") == 0)
installMode = false;
- } else
#ifdef TESTMODE
- if (strcmp(argv[1], "test") == 0)
- {
+ else if (strcmp(argv[1], "test") == 0)
testMode = true;
- } else
#endif
- {
- displayHelpAndExit(argv[0]);
- }
+ else
+ return usage(argv[0]);
- int rc;
+ int rc;
#ifdef TESTMODE
if (testMode)
- {
rc = performTest();
- } else
+ else
#endif
if (installMode)
- {
rc = installDriver();
- } else
- {
+ else
rc = uninstallDriver();
- }
if (rc == 0)
- {
printf("operation completed successfully!\n");
- } else
- {
+ else
printf("error: operation failed with status code %d\n", rc);
- }
return rc;
}
+
diff --git a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestMsg.mc b/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestMsg.mc
deleted file mode 100644
index 65a14b5f..00000000
--- a/src/VBox/Additions/common/VBoxGuest/win/VBoxGuestMsg.mc
+++ /dev/null
@@ -1,60 +0,0 @@
-;
-; VBoxGuest Device Driver Messages
-;
-; Copyright (C) 2006-2007 Oracle Corporation
-;
-; This file is part of VirtualBox Open Source Edition (OSE), as
-; available from http://www.virtualbox.org. This file is free software;
-; you can redistribute it and/or modify it under the terms of the GNU
-; General Public License (GPL) as published by the Free Software
-; Foundation, in version 2 as it comes in the "COPYING" file of the
-; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
-; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
-;
-
-
-;//
-;// Status values are 32 bit values arranged as follows:
-;//
-;// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
-;// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-;// +---+-+-------------------------+-------------------------------+
-;// |Sev|C| Facility | Code |
-;// +---+-+-------------------------+-------------------------------+
-;//
-;// where
-;//
-;// Sev - is the severity code
-;//
-;// 00 - Success
-;// 01 - Informational
-;// 10 - Warning
-;// 11 - Error
-;//
-;// C - is the Customer code flag
-;//
-;// Facility - is the facility code
-;//
-;// Code - is the facility's status code
-;//
-;
-MessageIdTypedef=NTSTATUS
-
-SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
- Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
- Warning=0x2:STATUS_SEVERITY_WARNING
- Error=0x3:STATUS_SEVERITY_ERROR
- )
-
-FacilityNames=(System=0x0
- RpcRuntime=0x2:FACILITY_RPC_RUNTIME
- RpcStubs=0x3:FACILITY_RPC_STUBS
- Io=0x4:FACILITY_IO_ERROR_CODE
- VBoxGuestClass=0xee:FACILITY_VBOXGUESTCLASS_ERROR_CODE
- )
-
-
-MessageId=0x0001 Facility=VBoxGuestClass Severity=Informational SymbolicName=VBOXGUESTCLASS_FOO
-Language=English
-VBoxGuest has something to say %1.
-.
diff --git a/src/VBox/Additions/common/VBoxGuestLib/GenericRequest.cpp b/src/VBox/Additions/common/VBoxGuestLib/GenericRequest.cpp
index ea1fe187..cae7a8f3 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/GenericRequest.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/GenericRequest.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 71271 $ */
+/* $Revision: 87431 $ */
/** @file
* VBoxGuestLibR0 - Generic VMMDev request management.
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -69,20 +69,24 @@ DECLVBGL(int) VbglGRVerify (const VMMDevRequestHeader *pReq, size_t cbReq)
return VINF_SUCCESS;
}
- /* This can be a variable size request. Check the request type and limit the size
+ /*
+ * This can be a variable size request. Check the request type and limit the size
* to VMMDEV_MAX_VMMDEVREQ_SIZE, which is max size supported by the host.
+ *
+ * Note: Keep this list sorted for easier human lookup!
*/
- if ( pReq->requestType == VMMDevReq_LogString
- || pReq->requestType == VMMDevReq_VideoSetVisibleRegion
- || pReq->requestType == VMMDevReq_SetPointerShape
+ if ( pReq->requestType == VMMDevReq_ChangeMemBalloon
#ifdef VBOX_WITH_64_BITS_GUESTS
|| pReq->requestType == VMMDevReq_HGCMCall32
|| pReq->requestType == VMMDevReq_HGCMCall64
#else
|| pReq->requestType == VMMDevReq_HGCMCall
#endif /* VBOX_WITH_64_BITS_GUESTS */
- || pReq->requestType == VMMDevReq_ChangeMemBalloon
- || pReq->requestType == VMMDevReq_RegisterSharedModule)
+ || pReq->requestType == VMMDevReq_RegisterSharedModule
+ || pReq->requestType == VMMDevReq_ReportGuestUserState
+ || pReq->requestType == VMMDevReq_LogString
+ || pReq->requestType == VMMDevReq_SetPointerShape
+ || pReq->requestType == VMMDevReq_VideoSetVisibleRegion)
{
if (cbReq > VMMDEV_MAX_VMMDEVREQ_SIZE)
{
diff --git a/src/VBox/Additions/common/VBoxGuestLib/HGCM.cpp b/src/VBox/Additions/common/VBoxGuestLib/HGCM.cpp
index f6aa77b4..5521c142 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/HGCM.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/HGCM.cpp
@@ -1,4 +1,4 @@
-/* $Revision: 76853 $ */
+/* $Revision: 83575 $ */
/** @file
* VBoxGuestLib - Host-Guest Communication Manager.
*
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp b/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp
index fa2703aa..efd8d76b 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 77449 $ */
+/* $Revision: 88366 $ */
/** @file
* VBoxGuestLib - Host-Guest Communication Manager internal functions, implemented by VBoxGuest
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,9 +49,10 @@
#define VBGLR0_MAX_HGCM_USER_PARM (24*_1M)
/** The max parameter buffer size for a kernel request. */
#define VBGLR0_MAX_HGCM_KERNEL_PARM (16*_1M)
-#ifdef RT_OS_LINUX
+#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
/** Linux needs to use bounce buffers since RTR0MemObjLockUser has unwanted
- * side effects. */
+ * side effects.
+ * Darwin 32bit & 64bit also needs this because of 4GB/4GB user/kernel space. */
# define USE_BOUNCE_BUFFERS
#endif
diff --git a/src/VBox/Additions/common/VBoxGuestLib/Init.cpp b/src/VBox/Additions/common/VBoxGuestLib/Init.cpp
index c21ce6cd..5298ffe7 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/Init.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/Init.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 79609 $ */
+/* $Revision: 89635 $ */
/** @file
* VBoxGuestLibR0 - Library initialization.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -83,7 +83,7 @@ static void vbglQueryDriverInfo (void)
int rc = VINF_SUCCESS;
rc = RTSemMutexRequest(g_vbgldata.mutexDriverInit, RT_INDEFINITE_WAIT);
-
+
if (RT_FAILURE(rc))
return;
@@ -266,7 +266,7 @@ DECLVBGL(int) VbglInit (void)
{
vbglTerminateCommon ();
}
-
+
}
return rc;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk b/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk
index ed8c689e..244fc2b4 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2006-2012 Oracle Corporation
+# Copyright (C) 2006-2013 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -105,6 +105,7 @@ VBoxGuestR3Lib_SOURCES = \
VBoxGuestR3LibCpuHotPlug.cpp \
VBoxGuestR3LibCredentials.cpp \
VBoxGuestR3LibEvent.cpp \
+ VBoxGuestR3LibGuestUser.cpp \
VBoxGuestR3LibGR.cpp \
VBoxGuestR3LibHostChannel.cpp \
VBoxGuestR3LibLog.cpp \
diff --git a/src/VBox/Additions/common/VBoxGuestLib/PhysHeap.cpp b/src/VBox/Additions/common/VBoxGuestLib/PhysHeap.cpp
index 51f1281d..1f1d24f5 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/PhysHeap.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/PhysHeap.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 67140 $ */
+/* $Revision: 85891 $ */
/** @file
* VBoxGuestLibR0 - Physical memory heap.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -100,7 +100,7 @@ struct _VBGLPHYSHEAPCHUNK
uint32_t cbSize;
/* Physical address of the chunk */
- RTCCPHYS physAddr;
+ uint32_t physAddr;
/* Number of allocated blocks in the chunk */
int32_t cAllocatedBlocks;
@@ -318,9 +318,11 @@ static VBGLPHYSHEAPBLOCK *vbglPhysHeapChunkAlloc (uint32_t cbSize)
return NULL;
}
+ AssertRelease(physAddr < _4G && physAddr + cbSize <= _4G);
+
pChunk->u32Signature = VBGL_PH_CHUNKSIGNATURE;
pChunk->cbSize = cbSize;
- pChunk->physAddr = physAddr;
+ pChunk->physAddr = (uint32_t)physAddr;
pChunk->cAllocatedBlocks = 0;
pChunk->pNext = g_vbgldata.pChunkHead;
pChunk->pPrev = NULL;
@@ -493,9 +495,9 @@ DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize)
return vbglPhysHeapBlock2Data (pBlock);
}
-DECLVBGL(RTCCPHYS) VbglPhysHeapGetPhysAddr (void *p)
+DECLVBGL(uint32_t) VbglPhysHeapGetPhysAddr (void *p)
{
- RTCCPHYS physAddr = 0;
+ uint32_t physAddr = 0;
VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapData2Block (p);
if (pBlock)
@@ -504,7 +506,7 @@ DECLVBGL(RTCCPHYS) VbglPhysHeapGetPhysAddr (void *p)
("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
- physAddr = pBlock->pChunk->physAddr + ((char *)p - (char *)pBlock->pChunk);
+ physAddr = pBlock->pChunk->physAddr + (uint32_t)((uintptr_t)p - (uintptr_t)pBlock->pChunk);
}
return physAddr;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp b/src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp
index c50f287c..008c5e14 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 78886 $ */
+/* $Revision: 83575 $ */
/** @file
* VBoxGuestLibR0 - IDC with VBoxGuest and HGCM helpers.
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -309,7 +309,13 @@ int vbglDriverIOCtl (VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, ui
if (rc != STATUS_SUCCESS)
Log(("vbglDriverIOCtl: ntstatus=%x\n", rc));
- return NT_SUCCESS(rc)? VINF_SUCCESS: VERR_VBGL_IOCTL_FAILED;
+ if (NT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ if (rc == STATUS_INVALID_PARAMETER)
+ return VERR_INVALID_PARAMETER;
+ if (rc == STATUS_INVALID_BUFFER_SIZE)
+ return VERR_OUT_OF_RANGE;
+ return VERR_VBGL_IOCTL_FAILED;
# elif defined (RT_OS_OS2)
if ( pDriver->u32Session
diff --git a/src/VBox/Additions/common/VBoxGuestLib/SysHlp.h b/src/VBox/Additions/common/VBoxGuestLib/SysHlp.h
index 9e78e404..68603647 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/SysHlp.h
+++ b/src/VBox/Additions/common/VBoxGuestLib/SysHlp.h
@@ -1,10 +1,10 @@
-/* $Revision: 78884 $ */
+/* $Revision: 83575 $ */
/** @file
* VBoxGuestLibR0 - System dependent helpers internal header.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBGLInternal.h b/src/VBox/Additions/common/VBoxGuestLib/VBGLInternal.h
index 98cf339c..6fe015da 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBGLInternal.h
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBGLInternal.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -138,20 +138,13 @@ extern VBGLDATA g_vbgldata;
*
* @param a_fLocked For the windows shared folders workarounds.
*
- * @remarks Disable the PageList feature for 64-bit Windows, because shared
- * folders do not work, if this is enabled. This should be reenabled
- * again when the problem is fixed.
- * @remarks Disabled the PageList feature for 32-bit Windows, see xTracker
- * ticket 6096 and public ticket 10290. Hopefully this is the same
- * issue as on Windows/AMD64.
+ * @remarks Disabled the PageList feature for locked memory on Windows,
+ * because a new MDL is created by VBGL to get the page addresses
+ * and the pages from the MDL are marked as dirty when they should not.
*/
#if defined(RT_OS_WINDOWS)
-# ifdef RT_ARCH_AMD64
-# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) ( 0 )
-# else
-# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
- ( !(a_fLocked) && (g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
-# endif
+# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
+ ( !(a_fLocked) && (g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
#else
# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
( !!(g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBGLR3Internal.h b/src/VBox/Additions/common/VBoxGuestLib/VBGLR3Internal.h
index a36e8129..463c13dc 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBGLR3Internal.h
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBGLR3Internal.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestLog.h b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestLog.h
index 0046f8ea..fccd343e 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestLog.h
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestLog.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibCrOgl.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibCrOgl.cpp
index 3fa03d20..893b4718 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibCrOgl.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibCrOgl.cpp
@@ -91,9 +91,18 @@ DECLVBGL(int) vboxCrCtlConConnect(HVBOXCRCTL hCtl, uint32_t *pu32ClientID)
RTStrCopy(info.Loc.u.host.achName, sizeof (info.Loc.u.host.achName), "VBoxSharedCrOpenGL");
rc = vbglDriverIOCtl (&hCtl->driver, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info));
if (RT_SUCCESS(rc))
- *pu32ClientID = info.u32ClientID;
- else
- *pu32ClientID = 0;
+ {
+ rc = info.result;
+ if (RT_SUCCESS(rc))
+ {
+ Assert(info.u32ClientID);
+ *pu32ClientID = info.u32ClientID;
+ return rc;
+ }
+ }
+
+ Assert(RT_FAILURE(rc));
+ *pu32ClientID = 0;
return rc;
}
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c
index a792acaf..3ecb4388 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c
@@ -1,10 +1,10 @@
-/* $Revision: 76380 $ */
+/* $Revision: 84251 $ */
/** @file
* VBoxGuestR0LibSharedFolders - Ring 0 Shared Folders calls.
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,11 +27,12 @@
/* Entire file is ifdef'ed with !VBGL_VBOXGUEST */
#ifndef VBGL_VBOXGUEST
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SHARED_FOLDERS
-
#ifdef RT_OS_LINUX
# include "VBoxGuestR0LibSharedFolders.h"
-# define DbgPrint RTAssertMsg2Weak
#else
# include "VBoxGuestR0LibSharedFolders.h"
#endif
@@ -41,6 +42,10 @@
#include <iprt/path.h>
#include <iprt/string.h>
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
#define SHFL_CPARMS_SET_UTF8 0
#define SHFL_CPARMS_SET_SYMLINKS 0
@@ -52,9 +57,6 @@
(a)->u32Function = SHFL_FN_##b; \
(a)->cParms = SHFL_CPARMS_##b
-#ifndef RT_OS_WINDOWS
-# define RtlZeroMemory(a, b) memset (a, 0, b)
-#endif
DECLVBGL(int) vboxInit (void)
@@ -72,14 +74,12 @@ DECLVBGL(void) vboxUninit (void)
DECLVBGL(int) vboxConnect (PVBSFCLIENT pClient)
{
- int rc = VINF_SUCCESS;
-
+ int rc;
VBoxGuestHGCMConnectInfo data;
- RtlZeroMemory (&data, sizeof (VBoxGuestHGCMConnectInfo));
-
pClient->handle = NULL;
+ RT_ZERO(data);
data.result = VINF_SUCCESS;
data.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
strcpy (data.Loc.u.host.achName, "VBoxSharedFolders");
@@ -111,8 +111,7 @@ DECLVBGL(void) vboxDisconnect (PVBSFCLIENT pClient)
if (pClient->handle == NULL)
return; /* not connected */
- RtlZeroMemory (&data, sizeof (VBoxGuestHGCMDisconnectInfo));
-
+ RT_ZERO(data);
data.result = VINF_SUCCESS;
data.u32ClientID = pClient->ulClientID;
@@ -125,7 +124,7 @@ DECLVBGL(void) vboxDisconnect (PVBSFCLIENT pClient)
}
DECLVBGL(int) vboxCallQueryMappings (PVBSFCLIENT pClient, SHFLMAPPING paMappings[],
- uint32_t *pcMappings)
+ uint32_t *pcMappings)
{
int rc = VINF_SUCCESS;
@@ -442,6 +441,52 @@ DECLVBGL(int) vboxCallRead(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
return rc;
}
+DECLVBGL(int) VbglR0SharedFolderReadPageList(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ uint32_t cbToRead = *pcbBuffer;
+ uint32_t cbData = sizeof(VBoxSFRead) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]);
+ VBoxSFRead *pData = (VBoxSFRead *)RTMemTmpAlloc(cbData);
+ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1);
+ uint16_t iPage;
+ int rc;
+
+ if (RT_UNLIKELY(!pData))
+ return VERR_NO_TMP_MEMORY;
+
+ VBOX_INIT_CALL(&pData->callInfo, READ, pClient);
+
+ pData->root.type = VMMDevHGCMParmType_32bit;
+ pData->root.u.value32 = pMap->root;
+
+ pData->handle.type = VMMDevHGCMParmType_64bit;
+ pData->handle.u.value64 = hFile;
+ pData->offset.type = VMMDevHGCMParmType_64bit;
+ pData->offset.u.value64 = offset;
+ pData->cb.type = VMMDevHGCMParmType_32bit;
+ pData->cb.u.value32 = cbToRead;
+ pData->buffer.type = VMMDevHGCMParmType_PageList;
+ pData->buffer.u.PageList.size = cbToRead;
+ pData->buffer.u.PageList.offset = sizeof(VBoxSFRead);
+
+ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
+ pPgLst->offFirstPage = offFirstPage;
+ pPgLst->cPages = cPages;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pPgLst->aPages[iPage] = paPages[iPage];
+
+ rc = VbglHGCMCall(pClient->handle, &pData->callInfo, cbData);
+ if (RT_SUCCESS (rc))
+ {
+ rc = pData->callInfo.result;
+ *pcbBuffer = pData->cb.u.value32;
+ }
+
+ RTMemTmpFree(pData);
+ return rc;
+}
+
DECLVBGL(int) vboxCallWrite(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked)
{
@@ -524,6 +569,52 @@ DECLVBGL(int) VbglR0SfWritePhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHAND
}
+DECLVBGL(int) VbglR0SharedFolderWritePageList(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ uint32_t cbToWrite = *pcbBuffer;
+ uint32_t cbData = sizeof(VBoxSFWrite) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]);
+ VBoxSFWrite *pData = (VBoxSFWrite *)RTMemTmpAlloc(cbData);
+ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1);
+ uint16_t iPage;
+ int rc;
+
+ if (RT_UNLIKELY(!pData))
+ return VERR_NO_TMP_MEMORY;
+
+ VBOX_INIT_CALL(&pData->callInfo, WRITE, pClient);
+
+ pData->root.type = VMMDevHGCMParmType_32bit;
+ pData->root.u.value32 = pMap->root;
+
+ pData->handle.type = VMMDevHGCMParmType_64bit;
+ pData->handle.u.value64 = hFile;
+ pData->offset.type = VMMDevHGCMParmType_64bit;
+ pData->offset.u.value64 = offset;
+ pData->cb.type = VMMDevHGCMParmType_32bit;
+ pData->cb.u.value32 = cbToWrite;
+ pData->buffer.type = VMMDevHGCMParmType_PageList;
+ pData->buffer.u.PageList.size = cbToWrite;
+ pData->buffer.u.PageList.offset = sizeof(VBoxSFWrite);
+
+ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
+ pPgLst->offFirstPage = offFirstPage;
+ pPgLst->cPages = cPages;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pPgLst->aPages[iPage] = paPages[iPage];
+
+ rc = VbglHGCMCall (pClient->handle, &pData->callInfo, cbData);
+ if (RT_SUCCESS (rc))
+ {
+ rc = pData->callInfo.result;
+ *pcbBuffer = pData->cb.u.value32;
+ }
+
+ RTMemTmpFree(pData);
+ return rc;
+}
+
DECLVBGL(int) vboxCallFlush(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile)
{
int rc = VINF_SUCCESS;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h
index 3947a13d..5e5c9576 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -172,8 +172,14 @@ DECLVBGL(int) vboxCallRename (PVBSFCLIENT pClient, PVBSFMAP pMap, PSHFLSTRING pS
DECLVBGL(int) vboxCallFlush (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile);
DECLVBGL(int) vboxCallRead (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked);
+DECLVBGL(int) VbglR0SharedFolderReadPageList(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages);
DECLVBGL(int) vboxCallWrite (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked);
DECLVBGL(int) VbglR0SfWritePhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, RTCCPHYS PhysBuffer);
+DECLVBGL(int) VbglR0SharedFolderWritePageList(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages);
DECLVBGL(int) vboxCallLock (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint64_t cbSize, uint32_t fLock);
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3Lib.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3Lib.cpp
index 32ccf4c4..80e5b877 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3Lib.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3Lib.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,14 +36,20 @@
# define INCL_ERRORS
# include <os2.h>
-#elif defined(RT_OS_FREEBSD) \
+#elif defined(RT_OS_DARWIN) \
+ || defined(RT_OS_FREEBSD) \
+ || defined(RT_OS_HAIKU) \
|| defined(RT_OS_LINUX) \
|| defined(RT_OS_SOLARIS)
# include <sys/types.h>
# include <sys/stat.h>
-# if defined(RT_OS_LINUX) /** @todo check this on solaris+freebsd as well. */
+# if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) /** @todo check this on solaris+freebsd as well. */
# include <sys/ioctl.h>
# endif
+# if defined(RT_OS_DARWIN)
+# include <mach/mach_port.h>
+# include <IOKit/IOKitLib.h>
+# endif
# include <errno.h>
# include <unistd.h>
#endif
@@ -85,6 +91,10 @@ static RTFILE g_File = NIL_RTFILE;
* inside a single process space.
*/
static uint32_t volatile g_cInits = 0;
+#ifdef RT_OS_DARWIN
+/** I/O Kit connection handle. */
+static io_connect_t g_uConnection = 0;
+#endif
@@ -189,6 +199,40 @@ static int vbglR3Init(const char *pszDeviceName)
}
g_File = (RTFILE)hf;
+#elif defined(RT_OS_DARWIN)
+ /*
+ * Darwin is kind of special we need to engage the device via I/O first
+ * before we open it via the BSD device node.
+ */
+ mach_port_t MasterPort;
+ kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
+ if (kr != kIOReturnSuccess)
+ return VERR_GENERAL_FAILURE;
+
+ CFDictionaryRef ClassToMatch = IOServiceMatching("org_virtualbox_VBoxGuest");
+ if (!ClassToMatch)
+ return VERR_GENERAL_FAILURE;
+
+ io_service_t ServiceObject = IOServiceGetMatchingService(kIOMasterPortDefault, ClassToMatch);
+ if (!ServiceObject)
+ return VERR_NOT_FOUND;
+
+ io_connect_t uConnection;
+ kr = IOServiceOpen(ServiceObject, mach_task_self(), 0, &uConnection);
+ IOObjectRelease(ServiceObject);
+ if (kr != kIOReturnSuccess)
+ return VERR_OPEN_FAILED;
+
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+ if (RT_FAILURE(rc))
+ {
+ IOServiceClose(uConnection);
+ return rc;
+ }
+ g_File = hFile;
+ g_uConnection = uConnection;
+
#elif defined(VBOX_VBGLR3_XFREE86)
int File = xf86open(pszDeviceName, XF86_O_RDWR);
if (File == -1)
@@ -197,7 +241,7 @@ static int vbglR3Init(const char *pszDeviceName)
#else
- /* The default implementation. (linux, solaris, freebsd) */
+ /* The default implementation. (linux, solaris, freebsd, haiku) */
RTFILE File;
int rc = RTFileOpen(&File, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
if (RT_FAILURE(rc))
@@ -262,13 +306,22 @@ VBGLR3DECL(void) VbglR3Term(void)
Assert(fRc); NOREF(fRc);
# elif defined(RT_OS_OS2)
-
RTFILE File = g_File;
g_File = NIL_RTFILE;
AssertReturnVoid(File != NIL_RTFILE);
APIRET rc = DosClose((uintptr_t)File);
AssertMsg(!rc, ("%ld\n", rc));
+#elif defined(RT_OS_DARWIN)
+ io_connect_t uConnection = g_uConnection;
+ RTFILE hFile = g_File;
+ g_uConnection = 0;
+ g_File = NIL_RTFILE;
+ kern_return_t kr = IOServiceClose(uConnection);
+ AssertMsg(kr == kIOReturnSuccess, ("%#x (%d)\n", kr, kr));
+ int rc = RTFileClose(hFile);
+ AssertRC(rc);
+
# else /* The IPRT case. */
RTFILE File = g_File;
g_File = NIL_RTFILE;
@@ -357,7 +410,7 @@ int vbglR3DoIOCtl(unsigned iFunction, void *pvData, size_t cbData)
}
return VINF_SUCCESS;
-#elif defined(RT_OS_LINUX)
+#elif defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
# ifdef VBOX_VBGLR3_XFREE86
int rc = xf86ioctl((int)g_File, iFunction, pvData);
# else
@@ -380,6 +433,20 @@ int vbglR3DoIOCtl(unsigned iFunction, void *pvData, size_t cbData)
NOREF(cbData);
return rc;
+#elif defined(RT_OS_HAIKU)
+ /* The ioctl hook in Haiku does take the len parameter when specified,
+ * so just use it. */
+ int rc = ioctl((int)g_File, iFunction, pvData, cbData);
+ if (RT_LIKELY(rc == 0))
+ return VINF_SUCCESS;
+
+ /* Positive values are negated VBox error status codes. */
+ if (rc > 0)
+ rc = -rc;
+ else
+ rc = RTErrConvertFromErrno(errno);
+ return rc;
+
#elif defined(VBOX_VBGLR3_XFREE86)
/* PORTME - This is preferred over the RTFileIOCtl variant below, just be careful with the (int). */
/** @todo test status code passing! */
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibClipboard.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibClipboard.cpp
index 2c13b0aa..045d4670 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibClipboard.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibClipboard.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibCredentials.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibCredentials.cpp
index a25515e1..7809a420 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibCredentials.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibCredentials.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp
index a314e522..c6ab6545 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDaemonize.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2009 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,10 +28,7 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
-#if defined(RT_OS_DARWIN)
-# error "PORTME"
-
-#elif defined(RT_OS_OS2)
+#if defined(RT_OS_OS2)
# define INCL_BASE
# define INCL_ERRORS
# include <os2.h>
@@ -73,10 +70,7 @@
*/
VBGLR3DECL(int) VbglR3Daemonize(bool fNoChDir, bool fNoClose)
{
-#if defined(RT_OS_DARWIN)
-# error "PORTME"
-
-#elif defined(RT_OS_OS2)
+#if defined(RT_OS_OS2)
PPIB pPib;
PTIB pTib;
DosGetInfoBlocks(&pTib, &pPib);
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGR.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGR.cpp
index b8a3fa7f..a5e16501 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGR.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGR.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
index 514d60c9..2bd554c4 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2011 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,10 +49,10 @@ using namespace guestControl;
* Connects to the guest control service.
*
* @returns VBox status code
- * @param pu32ClientId Where to put the client id on success. The client id
- * must be passed to all the other calls to the service.
+ * @param puClientId Where to put The client ID on success. The client ID
+ * must be passed to all the other calls to the service.
*/
-VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pu32ClientId)
+VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *puClientId)
{
VBoxGuestHGCMConnectInfo Info;
Info.result = VERR_WRONG_ORDER;
@@ -66,7 +66,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pu32ClientId)
{
rc = Info.result;
if (RT_SUCCESS(rc))
- *pu32ClientId = Info.u32ClientID;
+ *puClientId = Info.u32ClientID;
}
return rc;
}
@@ -76,13 +76,13 @@ VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pu32ClientId)
* Disconnect from the guest control service.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
*/
-VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t u32ClientId)
+VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t uClientId)
{
VBoxGuestHGCMDisconnectInfo Info;
Info.result = VERR_WRONG_ORDER;
- Info.u32ClientID = u32ClientId;
+ Info.u32ClientID = uClientId;
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
if (RT_SUCCESS(rc))
@@ -96,22 +96,22 @@ VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t u32ClientId)
* This will block until a message becomes available.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
* @param puMsg Where to store the message id.
* @param puNumParms Where to store the number of parameters which will be received
* in a second call to the host.
*/
-VBGLR3DECL(int) VbglR3GuestCtrlWaitForHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms)
+VBGLR3DECL(int) VbglR3GuestCtrlMsgWaitFor(uint32_t uClientId, uint32_t *puMsg, uint32_t *puNumParms)
{
AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
AssertPtrReturn(puNumParms, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgType Msg;
+ HGCMMsgCmdWaitFor Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG; /* Tell the host we want our next command. */
- Msg.hdr.cParms = 2; /* Just peek for the next message! */
+ Msg.hdr.u32ClientID = uClientId;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT; /* Tell the host we want our next command. */
+ Msg.hdr.cParms = 2; /* Just peek for the next message! */
VbglHGCMParmUInt32Set(&Msg.msg, 0);
VbglHGCMParmUInt32Set(&Msg.num_parms, 0);
@@ -131,17 +131,139 @@ VBGLR3DECL(int) VbglR3GuestCtrlWaitForHostMsg(uint32_t u32ClientId, uint32_t *pu
/**
+ * Asks the host guest control service to set a command filter to this
+ * client so that it only will receive certain commands in the future.
+ * The filter(s) are a bitmask for the context IDs, served from the host.
+ *
+ * @return IPRT status code.
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
+ * @param uValue The value to filter messages for.
+ * @param uMaskAdd Filter mask to add.
+ * @param uMaskRemove Filter mask to remove.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue,
+ uint32_t uMaskAdd, uint32_t uMaskRemove)
+{
+ HGCMMsgCmdFilterSet Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = uClientId;
+ Msg.hdr.u32Function = GUEST_MSG_FILTER_SET; /* Tell the host we want to set a filter. */
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.value, uValue);
+ VbglHGCMParmUInt32Set(&Msg.mask_add, uMaskAdd);
+ VbglHGCMParmUInt32Set(&Msg.mask_remove, uMaskRemove);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ rc = Msg.hdr.result;
+ return rc;
+}
+
+
+/**
+ * Disables a previously set message filter.
+ *
+ * @return IPRT status code.
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterUnset(uint32_t uClientId)
+{
+ HGCMMsgCmdFilterUnset Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = uClientId;
+ Msg.hdr.u32Function = GUEST_MSG_FILTER_UNSET; /* Tell the host we want to unset the filter. */
+ Msg.hdr.cParms = 1;
+
+ VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ rc = Msg.hdr.result;
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ int rc)
+{
+ return VbglR3GuestCtrlMsgReplyEx(pCtx, rc, 0 /* uType */,
+ NULL /* pvPayload */, 0 /* cbPayload */);
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ int rc, uint32_t uType,
+ void *pvPayload, uint32_t cbPayload)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ /* Everything else is optional. */
+
+ HGCMMsgCmdReply Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_REPLY;
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.rc, (uint32_t)rc); /* int vs. uint32_t */
+ VbglHGCMParmUInt32Set(&Msg.type, uType);
+ VbglHGCMParmPtrSet(&Msg.payload, pvPayload, cbPayload);
+
+ int rc2 = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc3 = Msg.hdr.result;
+ if (RT_FAILURE(rc3))
+ rc2 = rc3;
+ }
+ return rc2;
+}
+
+
+/**
+ * Tells the host service to skip the current message returned by
+ * VbglR3GuestCtrlMsgWaitFor().
+ *
+ * @return IPRT status code.
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId)
+{
+ HGCMMsgCmdSkip Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = uClientId;
+ Msg.hdr.u32Function = GUEST_MSG_SKIP; /* Tell the host we want to skip
+ the current assigned command. */
+ Msg.hdr.cParms = 1;
+
+ VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ rc = Msg.hdr.result;
+
+ return rc;
+}
+
+
+/**
* Asks the host to cancel (release) all pending waits which were deferred.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
+ * @param uClientId The client ID returned by VbglR3GuestCtrlConnect().
*/
-VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId)
+VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t uClientId)
{
- VBoxGuestCtrlHGCMMsgCancelPendingWaits Msg;
+ HGCMMsgCancelPendingWaits Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
+ Msg.hdr.u32ClientID = uClientId;
Msg.hdr.u32Function = GUEST_CANCEL_PENDING_WAITS;
Msg.hdr.cParms = 0;
@@ -157,28 +279,238 @@ VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId)
/**
+ * Asks a specific guest session to close.
+ *
+ * @return IPRT status code.
+ * @param pCtx Host context.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+
+ HGCMMsgSessionClose Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_SESSION_CLOSE;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.flags, uFlags);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uType, uint32_t uResult)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMMsgSessionNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_SESSION_NOTIFY;
+ Msg.hdr.cParms = 3;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, uType);
+ VbglHGCMParmUInt32Set(&Msg.result, uResult);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+/**
+ * Retrieves the request to create a new guest session.
+ *
+ * @return IPRT status code.
+ * @param pCtx Host context.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puProtocol,
+ char *pszUser, uint32_t cbUser,
+ char *pszPassword, uint32_t cbPassword,
+ char *pszDomain, uint32_t cbDomain,
+ uint32_t *puFlags, uint32_t *puSessionID)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 6, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(puProtocol, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszDomain, VERR_INVALID_POINTER);
+ AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
+
+ HGCMMsgSessionOpen Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmUInt32Set(&Msg.protocol, 0);
+ VbglHGCMParmPtrSet(&Msg.username, pszUser, cbUser);
+ VbglHGCMParmPtrSet(&Msg.password, pszPassword, cbPassword);
+ VbglHGCMParmPtrSet(&Msg.domain, pszDomain, cbDomain);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.protocol.GetUInt32(puProtocol);
+ Msg.flags.GetUInt32(puFlags);
+
+ if (puSessionID)
+ *puSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtx->uContextID);
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * Retrieves the request to terminate an existing guest session.
+ *
+ * @return IPRT status code.
+ * @param pCtx Host context.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puFlags, uint32_t *puSessionID)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
+
+ HGCMMsgSessionClose Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(puFlags);
+
+ if (puSessionID)
+ *puSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtx->uContextID);
+ }
+ }
+
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlPathGetRename(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszSource, uint32_t cbSource,
+ char *pszDest, uint32_t cbDest,
+ uint32_t *puFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
+ AssertReturn(cbSource, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
+ AssertReturn(cbDest, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
+
+ HGCMMsgPathRename Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmPtrSet(&Msg.source, pszSource, cbSource);
+ VbglHGCMParmPtrSet(&Msg.dest, pszDest, cbDest);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(puFlags);
+ }
+ }
+ return rc;
+}
+
+
+/**
* Allocates and gets host data, based on the message id.
*
* This will block until data becomes available.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
- * @param uNumParms
** @todo Docs!
+ ** @todo Move the parameters in an own struct!
*/
-VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdExec(uint32_t u32ClientId, uint32_t cParms,
- uint32_t *puContext,
- char *pszCmd, uint32_t cbCmd,
- uint32_t *puFlags,
- char *pszArgs, uint32_t cbArgs, uint32_t *pcArgs,
- char *pszEnv, uint32_t *pcbEnv, uint32_t *pcEnvVars,
- char *pszUser, uint32_t cbUser,
- char *pszPassword, uint32_t cbPassword,
- uint32_t *pcMsTimeLimit)
-{
- AssertReturn(cParms == 11, VERR_INVALID_PARAMETER);
-
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetStart(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszCmd, uint32_t cbCmd,
+ uint32_t *puFlags,
+ char *pszArgs, uint32_t cbArgs, uint32_t *pcArgs,
+ char *pszEnv, uint32_t *pcbEnv, uint32_t *pcEnvVars,
+ char *pszUser, uint32_t cbUser,
+ char *pszPassword, uint32_t cbPassword,
+ uint32_t *puTimeoutMS,
+ uint32_t *puPriority,
+ uint64_t *puAffinity, uint32_t cbAffinity, uint32_t *pcAffinity)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
AssertPtrReturn(pszCmd, VERR_INVALID_POINTER);
AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
AssertPtrReturn(pszArgs, VERR_INVALID_POINTER);
@@ -186,16 +518,14 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdExec(uint32_t u32ClientId, uint
AssertPtrReturn(pszEnv, VERR_INVALID_POINTER);
AssertPtrReturn(pcbEnv, VERR_INVALID_POINTER);
AssertPtrReturn(pcEnvVars, VERR_INVALID_POINTER);
- AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
- AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
- AssertPtrReturn(pcMsTimeLimit, VERR_INVALID_POINTER);
+ AssertPtrReturn(puTimeoutMS, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgExecCmd Msg;
+ HGCMMsgProcExec Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 11;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmPtrSet(&Msg.cmd, pszCmd, cbCmd);
@@ -205,9 +535,27 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdExec(uint32_t u32ClientId, uint
VbglHGCMParmUInt32Set(&Msg.num_env, 0);
VbglHGCMParmUInt32Set(&Msg.cb_env, 0);
VbglHGCMParmPtrSet(&Msg.env, pszEnv, *pcbEnv);
- VbglHGCMParmPtrSet(&Msg.username, pszUser, cbUser);
- VbglHGCMParmPtrSet(&Msg.password, pszPassword, cbPassword);
- VbglHGCMParmUInt32Set(&Msg.timeout, 0);
+ if (pCtx->uProtocol < 2)
+ {
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ AssertReturn(cbUser, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
+ AssertReturn(pszPassword, VERR_INVALID_PARAMETER);
+
+ VbglHGCMParmPtrSet(&Msg.u.v1.username, pszUser, cbUser);
+ VbglHGCMParmPtrSet(&Msg.u.v1.password, pszPassword, cbPassword);
+ VbglHGCMParmUInt32Set(&Msg.u.v1.timeout, 0);
+ }
+ else
+ {
+ AssertPtrReturn(puAffinity, VERR_INVALID_POINTER);
+ AssertReturn(cbAffinity, VERR_INVALID_PARAMETER);
+
+ VbglHGCMParmUInt32Set(&Msg.u.v2.timeout, 0);
+ VbglHGCMParmUInt32Set(&Msg.u.v2.priority, 0);
+ VbglHGCMParmUInt32Set(&Msg.u.v2.num_affinity, 0);
+ VbglHGCMParmPtrSet(&Msg.u.v2.affinity, puAffinity, cbAffinity);
+ }
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
@@ -219,12 +567,21 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdExec(uint32_t u32ClientId, uint
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.flags.GetUInt32(puFlags);
Msg.num_args.GetUInt32(pcArgs);
Msg.num_env.GetUInt32(pcEnvVars);
Msg.cb_env.GetUInt32(pcbEnv);
- Msg.timeout.GetUInt32(pcMsTimeLimit);
+ if (pCtx->uProtocol < 2)
+ {
+ Msg.u.v1.timeout.GetUInt32(puTimeoutMS);
+ }
+ else
+ {
+ Msg.u.v2.timeout.GetUInt32(puTimeoutMS);
+ Msg.u.v2.priority.GetUInt32(puPriority);
+ Msg.u.v2.num_affinity.GetUInt32(pcAffinity);
+ }
}
}
return rc;
@@ -237,27 +594,24 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdExec(uint32_t u32ClientId, uint
* This will block until data becomes available.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
- * @param cParms
** @todo Docs!
*/
-VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t u32ClientId, uint32_t cParms,
- uint32_t *puContext, uint32_t *puPID,
- uint32_t *puHandle, uint32_t *puFlags)
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetOutput(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puPID, uint32_t *puHandle, uint32_t *puFlags)
{
- AssertReturn(cParms == 4, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
AssertPtrReturn(puPID, VERR_INVALID_POINTER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgExecOut Msg;
+ HGCMMsgProcOutput Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 4;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.pid, 0);
@@ -274,7 +628,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t u32ClientId, ui
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.pid.GetUInt32(puPID);
Msg.handle.GetUInt32(puHandle);
Msg.flags.GetUInt32(puFlags);
@@ -291,30 +645,27 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t u32ClientId, ui
* This will block until data becomes available.
*
* @returns VBox status code.
- * @param u32ClientId The client id returned by VbglR3GuestCtrlConnect().
- * @param cParms
** @todo Docs!
*/
-VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdInput(uint32_t u32ClientId, uint32_t cParms,
- uint32_t *puContext, uint32_t *puPID,
- uint32_t *puFlags,
- void *pvData, uint32_t cbData,
- uint32_t *pcbSize)
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetInput(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puPID, uint32_t *puFlags,
+ void *pvData, uint32_t cbData,
+ uint32_t *pcbSize)
{
- AssertReturn(cParms == 5, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
AssertPtrReturn(puPID, VERR_INVALID_POINTER);
AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
AssertPtrReturn(pvData, VERR_INVALID_POINTER);
AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgExecIn Msg;
+ HGCMMsgProcInput Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 5;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.pid, 0);
@@ -332,7 +683,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdInput(uint32_t u32ClientId, uin
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.pid.GetUInt32(puPID);
Msg.flags.GetUInt32(puFlags);
Msg.size.GetUInt32(pcbSize);
@@ -342,151 +693,156 @@ VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdInput(uint32_t u32ClientId, uin
}
-/**
- * Reports the process status (along with some other stuff) to the host.
- *
- * @returns VBox status code.
- ** @todo Docs!
- */
-VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatus(uint32_t u32ClientId,
- uint32_t u32Context,
- uint32_t u32PID,
- uint32_t u32Status,
- uint32_t u32Flags,
- void *pvData,
- uint32_t cbData)
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszPath, uint32_t cbPath,
+ uint32_t *puFlags)
{
- VBoxGuestCtrlHGCMMsgExecStatus Msg;
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 3, VERR_INVALID_PARAMETER);
- Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_EXEC_SEND_STATUS;
- Msg.hdr.cParms = 5;
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cbPath, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
- VbglHGCMParmUInt32Set(&Msg.context, u32Context);
- VbglHGCMParmUInt32Set(&Msg.pid, u32PID);
- VbglHGCMParmUInt32Set(&Msg.status, u32Status);
- VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);
- VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
+ HGCMMsgDirRemove Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmPtrSet(&Msg.path, pszPath, cbPath);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
{
int rc2 = Msg.hdr.result;
if (RT_FAILURE(rc2))
+ {
rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(puFlags);
+ }
}
return rc;
}
-/**
- * Sends output (from stdout/stderr) from a running process.
- *
- * @returns VBox status code.
- ** @todo Docs!
- */
-VBGLR3DECL(int) VbglR3GuestCtrlExecSendOut(uint32_t u32ClientId,
- uint32_t u32Context,
- uint32_t u32PID,
- uint32_t u32Handle,
- uint32_t u32Flags,
- void *pvData,
- uint32_t cbData)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszFileName, uint32_t cbFileName,
+ char *pszAccess, uint32_t cbAccess,
+ char *pszDisposition, uint32_t cbDisposition,
+ char *pszSharing, uint32_t cbSharing,
+ uint32_t *puCreationMode,
+ uint64_t *puOffset)
{
- VBoxGuestCtrlHGCMMsgExecOut Msg;
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 7, VERR_INVALID_PARAMETER);
- Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_EXEC_SEND_OUTPUT;
- Msg.hdr.cParms = 5;
+ AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
+ AssertReturn(cbFileName, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszAccess, VERR_INVALID_POINTER);
+ AssertReturn(cbAccess, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszDisposition, VERR_INVALID_POINTER);
+ AssertReturn(cbDisposition, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszSharing, VERR_INVALID_POINTER);
+ AssertReturn(cbSharing, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puCreationMode, VERR_INVALID_POINTER);
+ AssertPtrReturn(puOffset, VERR_INVALID_POINTER);
- VbglHGCMParmUInt32Set(&Msg.context, u32Context);
- VbglHGCMParmUInt32Set(&Msg.pid, u32PID);
- VbglHGCMParmUInt32Set(&Msg.handle, u32Handle);
- VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);
- VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
+ HGCMMsgFileOpen Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmPtrSet(&Msg.filename, pszFileName, cbFileName);
+ VbglHGCMParmPtrSet(&Msg.openmode, pszAccess, cbAccess);
+ VbglHGCMParmPtrSet(&Msg.disposition, pszDisposition, cbDisposition);
+ VbglHGCMParmPtrSet(&Msg.sharing, pszSharing, cbSharing);
+ VbglHGCMParmUInt32Set(&Msg.creationmode, 0);
+ VbglHGCMParmUInt64Set(&Msg.offset, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
{
int rc2 = Msg.hdr.result;
if (RT_FAILURE(rc2))
+ {
rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.creationmode.GetUInt32(puCreationMode);
+ Msg.offset.GetUInt64(puOffset);
+ }
}
return rc;
}
-/**
- * Reports back the input status to the host.
- *
- * @returns VBox status code.
- ** @todo Docs!
- */
-VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatusIn(uint32_t u32ClientId,
- uint32_t u32Context,
- uint32_t u32PID,
- uint32_t u32Status,
- uint32_t u32Flags,
- uint32_t cbWritten)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle)
{
- VBoxGuestCtrlHGCMMsgExecStatusIn Msg;
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
- Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = u32ClientId;
- Msg.hdr.u32Function = GUEST_EXEC_SEND_INPUT_STATUS;
- Msg.hdr.cParms = 5;
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
- VbglHGCMParmUInt32Set(&Msg.context, u32Context);
- VbglHGCMParmUInt32Set(&Msg.pid, u32PID);
- VbglHGCMParmUInt32Set(&Msg.status, u32Status);
- VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);
- VbglHGCMParmUInt32Set(&Msg.written, cbWritten);
+ HGCMMsgFileClose Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmUInt32Set(&Msg.handle, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
{
int rc2 = Msg.hdr.result;
if (RT_FAILURE(rc2))
+ {
rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.handle.GetUInt32(puHandle);
+ }
}
return rc;
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdOpen(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- char *pszFileName, uint32_t cbFileName,
- char *pszOpenMode, uint32_t cbOpenMode,
- char *pszDisposition, uint32_t cbDisposition,
- uint32_t *puCreationMode,
- uint64_t *puOffset)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puHandle, uint32_t *puToRead)
{
- AssertReturn(cParms == 6, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
- AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
- AssertReturn(cbFileName, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pszOpenMode, VERR_INVALID_POINTER);
- AssertReturn(cbOpenMode, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pszDisposition, VERR_INVALID_POINTER);
- AssertReturn(cbDisposition, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puCreationMode, VERR_INVALID_POINTER);
- AssertPtrReturn(puOffset, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 3, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+ AssertPtrReturn(puToRead, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileOpen Msg;
+ HGCMMsgFileRead Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 6;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
- VbglHGCMParmPtrSet(&Msg.filename, pszFileName, cbFileName);
- VbglHGCMParmPtrSet(&Msg.openmode, pszOpenMode, cbOpenMode);
- VbglHGCMParmPtrSet(&Msg.disposition, pszDisposition, cbDisposition);
- VbglHGCMParmUInt32Set(&Msg.creationmode, 0);
- VbglHGCMParmUInt64Set(&Msg.offset, 0);
+ VbglHGCMParmUInt32Set(&Msg.handle, 0);
+ VbglHGCMParmUInt32Set(&Msg.size, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
@@ -498,32 +854,35 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdOpen(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
- Msg.creationmode.GetUInt32(puCreationMode);
- Msg.offset.GetUInt64(puOffset);
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.handle.GetUInt32(puHandle);
+ Msg.size.GetUInt32(puToRead);
}
}
return rc;
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdClose(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- uint32_t *puHandle)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetReadAt(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puHandle, uint32_t *puToRead, uint64_t *puOffset)
{
- AssertReturn(cParms == 2, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+ AssertPtrReturn(puToRead, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileClose Msg;
+ HGCMMsgFileReadAt Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 2;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.handle, 0);
+ VbglHGCMParmUInt32Set(&Msg.offset, 0);
+ VbglHGCMParmUInt32Set(&Msg.size, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
@@ -535,32 +894,37 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdClose(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.handle.GetUInt32(puHandle);
+ Msg.offset.GetUInt64(puOffset);
+ Msg.size.GetUInt32(puToRead);
}
}
return rc;
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdRead(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- uint32_t *puHandle, uint32_t *puToRead)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle,
+ void *pvData, uint32_t cbData, uint32_t *pcbSize)
{
- AssertReturn(cParms == 4, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(puToRead, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+ AssertReturn(cbData, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileRead Msg;
+ HGCMMsgFileWrite Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 4;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.handle, 0);
+ VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
VbglHGCMParmUInt32Set(&Msg.size, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -573,38 +937,38 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdRead(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.handle.GetUInt32(puHandle);
- Msg.size.GetUInt32(puToRead);
+ Msg.size.GetUInt32(pcbSize);
}
}
return rc;
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdWrite(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- uint32_t *puHandle,
- void *pvData, uint32_t cbData,
- uint32_t *pcbSize)
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetWriteAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle,
+ void *pvData, uint32_t cbData, uint32_t *pcbSize, uint64_t *puOffset)
{
- AssertReturn(cParms == 4, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
AssertPtrReturn(pvData, VERR_INVALID_POINTER);
AssertReturn(cbData, VERR_INVALID_PARAMETER);
AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileWrite Msg;
+ HGCMMsgFileWriteAt Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 4;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.handle, 0);
VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
VbglHGCMParmUInt32Set(&Msg.size, 0);
+ VbglHGCMParmUInt32Set(&Msg.offset, 0);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
@@ -616,7 +980,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdWrite(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.handle.GetUInt32(puHandle);
Msg.size.GetUInt32(pcbSize);
}
@@ -625,23 +989,22 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdWrite(uint32_t uClientId,
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdSeek(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- uint32_t *puHandle,
- uint32_t *puSeekMethod, uint64_t *puOffset)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetSeek(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puHandle, uint32_t *puSeekMethod, uint64_t *puOffset)
{
- AssertReturn(cParms == 4, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
AssertPtrReturn(puSeekMethod, VERR_INVALID_POINTER);
AssertPtrReturn(puOffset, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileSeek Msg;
+ HGCMMsgFileSeek Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 4;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.handle, 0);
@@ -658,7 +1021,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdSeek(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.handle.GetUInt32(puHandle);
Msg.method.GetUInt32(puSeekMethod);
Msg.offset.GetUInt64(puOffset);
@@ -668,20 +1031,19 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdSeek(uint32_t uClientId,
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdTell(uint32_t uClientId, uint32_t cParms,
- uint32_t *puContext,
- uint32_t *puHandle)
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle)
{
- AssertReturn(cParms == 2, VERR_INVALID_PARAMETER);
- AssertPtrReturn(puContext, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileTell Msg;
+ HGCMMsgFileTell Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
- Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
- Msg.hdr.cParms = 2;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
VbglHGCMParmUInt32Set(&Msg.context, 0);
VbglHGCMParmUInt32Set(&Msg.handle, 0);
@@ -696,7 +1058,7 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdTell(uint32_t uClientId,
}
else
{
- Msg.context.GetUInt32(puContext);
+ Msg.context.GetUInt32(&pCtx->uContextID);
Msg.handle.GetUInt32(puHandle);
}
}
@@ -704,27 +1066,376 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetHostCmdTell(uint32_t uClientId,
}
-VBGLR3DECL(int) VbglR3GuestCtrlFileNotify(uint32_t uClientId,
- uint32_t uContext, uint32_t uHandle,
- uint32_t uType,
- void *pvPayload, uint32_t cbPayload)
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetTerminate(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID)
{
- AssertPtrReturn(uContext, VERR_INVALID_POINTER);
- AssertPtrReturn(uHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(pvPayload, VERR_INVALID_POINTER);
- AssertReturn(cbPayload, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
- VBoxGuestCtrlHGCMMsgFileNotify Msg;
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puPID, VERR_INVALID_POINTER);
+
+ HGCMMsgProcTerminate Msg;
Msg.hdr.result = VERR_WRONG_ORDER;
- Msg.hdr.u32ClientID = uClientId;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmUInt32Set(&Msg.pid, 0);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.pid.GetUInt32(puPID);
+ }
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t *puPID, uint32_t *puWaitFlags, uint32_t *puTimeoutMS)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(puPID, VERR_INVALID_POINTER);
+
+ HGCMMsgProcWaitFor Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_MSG_WAIT;
+ Msg.hdr.cParms = pCtx->uNumParms;
+
+ VbglHGCMParmUInt32Set(&Msg.context, 0);
+ VbglHGCMParmUInt32Set(&Msg.pid, 0);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+ VbglHGCMParmUInt32Set(&Msg.timeout, 0);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ }
+ else
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.pid.GetUInt32(puPID);
+ Msg.flags.GetUInt32(puWaitFlags);
+ Msg.timeout.GetUInt32(puTimeoutMS);
+ }
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc, uint32_t uFileHandle)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_OPEN);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ VbglHGCMParmUInt32Set(&Msg.u.open.handle, uFileHandle);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 3;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_CLOSE);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbError(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 3;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_ERROR);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc,
+ void *pvData, uint32_t cbData)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
Msg.hdr.cParms = 4;
- VbglHGCMParmUInt32Set(&Msg.context, uContext);
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_READ);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ VbglHGCMParmPtrSet(&Msg.u.read.data, pvData, cbData);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc, uint32_t uWritten)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_WRITE);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ VbglHGCMParmUInt32Set(&Msg.u.write.written, uWritten);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc, uint64_t uOffActual)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_SEEK);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ VbglHGCMParmUInt64Set(&Msg.u.seek.offset, uOffActual);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uRc, uint64_t uOffActual)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyFileNotify Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_FILE_NOTIFY;
+ Msg.hdr.cParms = 4;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_TELL);
+ VbglHGCMParmUInt32Set(&Msg.rc, uRc);
+
+ VbglHGCMParmUInt64Set(&Msg.u.tell.offset, uOffActual);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+/**
+ * Callback for reporting a guest process status (along with some other stuff) to the host.
+ *
+ * @returns VBox status code.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uPID, uint32_t uStatus, uint32_t uFlags,
+ void *pvData, uint32_t cbData)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMMsgProcStatus Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_EXEC_STATUS;
+ Msg.hdr.cParms = 5;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.pid, uPID);
+ VbglHGCMParmUInt32Set(&Msg.status, uStatus);
+ VbglHGCMParmUInt32Set(&Msg.flags, uFlags);
+ VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+/**
+ * Sends output (from stdout/stderr) from a running process.
+ *
+ * @returns VBox status code.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uPID,uint32_t uHandle, uint32_t uFlags,
+ void *pvData, uint32_t cbData)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMMsgProcOutput Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_EXEC_OUTPUT;
+ Msg.hdr.cParms = 5;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.pid, uPID);
VbglHGCMParmUInt32Set(&Msg.handle, uHandle);
- VbglHGCMParmUInt32Set(&Msg.type, uType);
- VbglHGCMParmPtrSet(&Msg.payload, pvPayload, cbPayload);
+ VbglHGCMParmUInt32Set(&Msg.flags, uFlags);
+ VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
+
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = Msg.hdr.result;
+ if (RT_FAILURE(rc2))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+/**
+ * Callback for reporting back the input status of a guest process to the host.
+ *
+ * @returns VBox status code.
+ ** @todo Docs!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ uint32_t uPID, uint32_t uStatus,
+ uint32_t uFlags, uint32_t cbWritten)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMMsgProcStatusInput Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = pCtx->uClientID;
+ Msg.hdr.u32Function = GUEST_EXEC_INPUT_STATUS;
+ Msg.hdr.cParms = 5;
+
+ VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.pid, uPID);
+ VbglHGCMParmUInt32Set(&Msg.status, uStatus);
+ VbglHGCMParmUInt32Set(&Msg.flags, uFlags);
+ VbglHGCMParmUInt32Set(&Msg.written, cbWritten);
int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
if (RT_SUCCESS(rc))
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp
index 32c7d796..48539199 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -783,6 +783,32 @@ VBGLR3DECL(void) VbglR3GuestPropEnumFree(PVBGLR3GUESTPROPENUM pHandle)
/**
+ * Deletes a guest property.
+ *
+ * @returns VBox status code.
+ * @param u32ClientId The client id returned by VbglR3InvsSvcConnect().
+ * @param pszName The property to delete. Utf8
+ */
+VBGLR3DECL(int) VbglR3GuestPropDelete(uint32_t u32ClientId, const char *pszName)
+{
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+
+ DelProperty Msg;
+
+ Msg.hdr.result = VERR_WRONG_ORDER;
+ Msg.hdr.u32ClientID = u32ClientId;
+ Msg.hdr.u32Function = DEL_PROP;
+ Msg.hdr.cParms = 1;
+ VbglHGCMParmPtrSetString(&Msg.name, pszName);
+ int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ rc = Msg.hdr.result;
+
+ return rc;
+}
+
+
+/**
* Deletes a set of keys.
*
* The set is specified in the same way as for VbglR3GuestPropEnum.
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestUser.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestUser.cpp
new file mode 100644
index 00000000..56b95785
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestUser.cpp
@@ -0,0 +1,114 @@
+/* $Id: VBoxGuestR3LibGuestUser.cpp $ */
+/** @file
+ * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions,
+ * guest user reporting / utility functions.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/assert.h>
+#include <VBox/log.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+#include "VBGLR3Internal.h"
+
+
+/**
+ * Reports a state change of a specific guest user.
+ *
+ * @returns IPRT status value
+ * @param pszUser Guest user name to report state for.
+ * @param pszDomain Domain the guest user's account is bound to.
+ * @param enmState Guest user state to report.
+ * @param puDetails Pointer to state details. Optional.
+ * @param cbDetails Size (in bytes) of state details. Pass 0
+ * if puDetails is NULL.
+ */
+VBGLR3DECL(int) VbglR3GuestUserReportState(const char *pszUser,
+ const char *pszDomain,
+ VBoxGuestUserState enmState,
+ uint8_t *puDetails,
+ uint32_t cbDetails)
+{
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ /* pszDomain is optional. */
+ /* puDetails is optional. */
+
+ uint32_t cbBase = sizeof(VMMDevReportGuestUserState);
+ uint32_t cbUser = strlen(pszUser) + 1; /* Include terminating zero */
+ uint32_t cbDomain = pszDomain ? strlen(pszDomain) + 1 /* Dito */ : 0;
+
+ /* Allocate enough space for all fields. */
+ unsigned long cbSize =
+ cbBase
+ + cbUser
+ + cbDomain
+ + cbDetails;
+
+ AssertReturn(cbSize, VERR_BUFFER_UNDERFLOW);
+ VMMDevReportGuestUserState *pReport =
+ (VMMDevReportGuestUserState *)RTMemAllocZ(cbSize);
+ if (!pReport)
+ return VERR_NO_MEMORY;
+
+ int rc = vmmdevInitRequest(&pReport->header, VMMDevReq_ReportGuestUserState);
+ if (RT_SUCCESS(rc))
+ {
+ pReport->header.size = cbSize;
+
+ pReport->status.state = enmState;
+ pReport->status.cbUser = cbUser;
+ pReport->status.cbDomain = cbDomain;
+ pReport->status.cbDetails = cbDetails;
+
+ /*
+ * Note: cbOffDynamic contains the first dynamic array entry within
+ * VBoxGuestUserStatus.
+ * Therefore it's vital to *not* change the order of the struct members
+ * without altering this code. Don't try this at home.
+ */
+ uint32_t cbOffDynamic =
+ RT_OFFSETOF(VBoxGuestUserStatus, szUser);
+
+ /* pDynamic marks the beginning for the dynamically allocated areas. */
+ uint8_t *pDynamic = (uint8_t *)&pReport->status;
+ pDynamic += cbOffDynamic;
+ AssertPtr(pDynamic);
+
+ memcpy(pDynamic, pszUser, cbUser);
+ if (cbDomain)
+ memcpy(pDynamic + cbUser, pszDomain, cbDomain);
+ if (cbDetails)
+ memcpy(pDynamic + cbUser + cbDomain, puDetails, cbDetails);
+
+ rc = vbglR3GRPerform(&pReport->header);
+ }
+
+ RTMemFree(pReport);
+ return rc;
+}
+
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostChannel.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostChannel.cpp
index 7051ae62..35ee6b5c 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostChannel.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostChannel.cpp
@@ -24,7 +24,7 @@
* terms and conditions of either the GPL or the CDDL or both.
*/
-
+
#include <iprt/mem.h>
#include <VBox/HostServices/VBoxHostChannel.h>
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostVersion.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostVersion.cpp
index 03cfce8f..e253838b 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostVersion.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibHostVersion.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMouse.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMouse.cpp
index 25fc44ee..52e39ab2 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMouse.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMouse.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSeamless.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSeamless.cpp
index aa146281..60b47a08 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSeamless.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSeamless.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSharedFolders.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSharedFolders.cpp
index 0d6be8ed..1ebec9cd 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSharedFolders.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibSharedFolders.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -199,6 +199,11 @@ VBGLR3DECL(int) VbglR3SharedFolderGetMappings(uint32_t u32ClientId, bool fAutoMo
ppaMappingsTemp = NULL;
}
+ /* In this case, just return success with 0 mappings */
+ if ( rc == VERR_INVALID_PARAMETER
+ && fAutoMountOnly)
+ rc = VINF_SUCCESS;
+
*ppaMappings = ppaMappingsTemp;
return rc;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibTime.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibTime.cpp
index c03b2c22..13830afe 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibTime.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibTime.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibVideo.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibVideo.cpp
index 3298d85d..fa972a3e 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibVideo.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibVideo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2009 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -139,6 +139,69 @@ VBGLR3DECL(int) VbglR3SetPointerShapeReq(VMMDevReqMousePointer *pReq)
rc = pReq->header.rc;
return rc;
}
+/**
+ * Query the last display change request sent from the host to the guest.
+ *
+ * @returns iprt status value
+ * @param pcx Where to store the horizontal pixel resolution
+ * requested (a value of zero means do not change).
+ * @param pcy Where to store the vertical pixel resolution
+ * requested (a value of zero means do not change).
+ * @param pcBits Where to store the bits per pixel requested (a value
+ * of zero means do not change).
+ * @param iDisplay Where to store the display number the request was for
+ * - 0 for the primary display, 1 for the first
+ * secondary display, etc.
+ * @param fAck whether or not to acknowledge the newest request sent by
+ * the host. If this is set, the function will return the
+ * most recent host request, otherwise it will return the
+ * last request to be acknowledged.
+ *
+ * @param pcOriginX New horizontal position of the secondary monitor.
+ * @param pcOriginY New vertical position of the secondary monitor.
+ * param pfEnabled Secondary monitor is enabled or not.
+ *
+ */
+VBGLR3DECL(int) VbglR3GetDisplayChangeRequestEx(uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits,
+ uint32_t *piDisplay, uint32_t *pcOriginX, uint32_t *pcOriginY,
+ bool *pfEnabled, bool fAck)
+{
+ VMMDevDisplayChangeRequestEx Req;
+ int rc = VINF_SUCCESS;
+ AssertPtrReturn(pcx, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcy, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcBits, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcOriginX, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcOriginY, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(piDisplay, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pfEnabled, VERR_INVALID_PARAMETER);
+ RT_ZERO(Req);
+ rc = vmmdevInitRequest(&Req.header, VMMDevReq_GetDisplayChangeRequestEx);
+ if (RT_FAILURE(rc))
+ {
+ LogRelFlowFunc(("DisplayChangeRequest Extended not supported. Can't Init the Req.\n"));
+ return rc;
+ }
+
+ if (fAck)
+ Req.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
+ rc = vbglR3GRPerform(&Req.header);
+ if (RT_SUCCESS(rc))
+ rc = Req.header.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *pcx = Req.xres;
+ *pcy = Req.yres;
+ *pcBits = Req.bpp;
+ *piDisplay = Req.display;
+ *pcOriginX = Req.cxOrigin;
+ *pcOriginY = Req.cyOrigin;
+ *pfEnabled = Req.fEnabled;
+ LogRel(("VbglR3GetDisplayChangeRequestEx: pcx=%d pcy=%d display=%d orgX=%d orgY=%d and Enabled=%d\n",
+ *pcx, *pcy, *piDisplay, *pcOriginX, *pcOriginY, *pfEnabled));
+ }
+ return rc;
+}
/**
@@ -146,7 +209,6 @@ VBGLR3DECL(int) VbglR3SetPointerShapeReq(VMMDevReqMousePointer *pReq)
*
* @returns iprt status value
* @param pcx Where to store the horizontal pixel resolution
- * requested (a value of zero means do not change).
* @param pcy Where to store the vertical pixel resolution
* requested (a value of zero means do not change).
* @param pcBits Where to store the bits per pixel requested (a value
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VMMDev.cpp b/src/VBox/Additions/common/VBoxGuestLib/VMMDev.cpp
index 00779237..beda4bb2 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VMMDev.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VMMDev.cpp
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VbglR0CanUsePhysPageList.cpp b/src/VBox/Additions/common/VBoxGuestLib/VbglR0CanUsePhysPageList.cpp
index a8764556..e8ecf07f 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VbglR0CanUsePhysPageList.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VbglR0CanUsePhysPageList.cpp
@@ -1,10 +1,10 @@
-/* $Revision: 77449 $ */
+/* $Revision: 83618 $ */
/** @file
* VBoxGuestLibR0 - Physical memory heap.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -34,6 +34,9 @@
*/
DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void)
{
+ /* a_fLocked is false, because the actual capability of the host is requested.
+ * See VBGLR0_CAN_USE_PHYS_PAGE_LIST definition.
+ */
int rc = vbglR0Enter();
return RT_SUCCESS(rc)
&& VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ false);
diff --git a/src/VBox/Additions/common/VBoxService/Makefile.kmk b/src/VBox/Additions/common/VBoxService/Makefile.kmk
index e00f66c6..8a42bab1 100644
--- a/src/VBox/Additions/common/VBoxService/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxService/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2007-2012 Oracle Corporation
+# Copyright (C) 2007-2013 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -38,6 +38,9 @@ VBoxService_DEFS += \
VBOX_BUILD_TARGET=\"$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)\"
VBoxService_DEFS.win += _WIN32_WINNT=0x0501
VBoxService_DEFS.os2 = VBOX_WITH_HGCM VBOXSERVICE_CLIPBOARD
+ifdef VBOX_WITH_DBUS
+ VBoxService_DEFS += VBOX_WITH_DBUS
+endif
ifdef VBOX_WITH_GUEST_PROPS
VBoxService_DEFS += VBOX_WITH_GUEST_PROPS VBOXSERVICE_VMINFO
endif
@@ -48,7 +51,10 @@ ifdef VBOX_WITH_MEMBALLOON
VBoxService_DEFS += VBOX_WITH_MEMBALLOON
endif
if1of ($(KBUILD_TARGET), win)
- VBoxService_DEFS += VBOX_WITH_PAGE_SHARING
+ VBoxService_DEFS += VBOXSERVICE_PAGE_SHARING
+ ifdef VBOX_WITH_MMR
+ VBoxService_DEFS += VBOX_WITH_MMR
+ endif
endif
if1of ($(KBUILD_TARGET), linux)
VBoxService_DEFS += VBOXSERVICE_CPUHOTPLUG
@@ -70,7 +76,8 @@ VBoxService_SOURCES = \
ifdef VBOX_WITH_GUEST_CONTROL
VBoxService_SOURCES += \
VBoxServiceControl.cpp \
- VBoxServiceControlThread.cpp
+ VBoxServiceControlProcess.cpp \
+ VBoxServiceControlSession.cpp
endif
ifdef VBOX_WITH_MEMBALLOON
@@ -112,6 +119,8 @@ VBoxService_SOURCES.os2 = \
VBoxService-os2.def \
VBoxServiceClipboard-os2.cpp
+VBoxService_LDFLAGS.darwin = -framework IOKit
+
VBoxService_LIBS += \
$(VBOX_LIB_IPRT_GUEST_R3) \
$(VBOX_LIB_VBGL_R3) \
@@ -120,6 +129,12 @@ if1of ($(KBUILD_TARGET), linux)
VBoxService_LIBS += \
crypt
endif
+ifdef VBOX_WITH_DBUS
+ if1of ($(KBUILD_TARGET), linux solaris) # FreeBSD?
+ VBoxService_LIBS += \
+ dl
+ endif
+endif
ifdef VBOX_WITH_GUEST_PROPS
VBoxService_LIBS.win += \
Secur32.lib \
diff --git a/src/VBox/Additions/common/VBoxService/VBoxService-os2.def b/src/VBox/Additions/common/VBoxService/VBoxService-os2.def
index 2c14ceed..aed84c68 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxService-os2.def
+++ b/src/VBox/Additions/common/VBoxService/VBoxService-os2.def
@@ -3,7 +3,7 @@
;
;
-; Copyright (C) 2007 Oracle Corporation
+; Copyright (C) 2007-2010 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp b/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp
index e09173c1..eb970fa8 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,6 +21,7 @@
*******************************************************************************/
#include <iprt/assert.h>
#include <iprt/err.h>
+#include <iprt/system.h> /* For querying OS version. */
#include <VBox/VBoxGuestLib.h>
#include "VBoxServiceInternal.h"
@@ -132,18 +133,40 @@ static BOOL vboxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
g_dwWinServiceLastStatus = dwStatus;
SERVICE_STATUS ss;
+ RT_ZERO(ss);
+
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState = dwStatus;
- ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ /* Don't accept controls when in start pending state. */
+ if (ss.dwCurrentState != SERVICE_START_PENDING)
+ {
+ ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
#ifndef TARGET_NT4
- ss.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE;
+ /* Don't use SERVICE_ACCEPT_SESSIONCHANGE on Windows 2000.
+ * This makes SCM angry. */
+ char szOSVersion[32];
+ int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE,
+ szOSVersion, sizeof(szOSVersion));
+ if (RT_SUCCESS(rc))
+ {
+ if (RTStrVersionCompare(szOSVersion, "5.1") >= 0)
+ ss.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE;
+ }
+ else
+ VBoxServiceError("Error determining OS version, rc=%Rrc\n", rc);
#endif
+ }
+
ss.dwWin32ExitCode = NO_ERROR;
ss.dwServiceSpecificExitCode = 0; /* Not used */
ss.dwCheckPoint = dwCheckPoint;
ss.dwWaitHint = 3000;
- return SetServiceStatus(g_hWinServiceStatus, &ss);
+ BOOL fStatusSet = SetServiceStatus(g_hWinServiceStatus, &ss);
+ if (!fStatusSet)
+ VBoxServiceError("Error reporting service status=%ld (controls=%x, checkpoint=%ld) to SCM: %ld\n",
+ dwStatus, ss.dwControlsAccepted, dwCheckPoint, GetLastError());
+ return fStatusSet;
}
@@ -339,6 +362,8 @@ static int vboxServiceWinStart(void)
if (RT_SUCCESS(rc))
{
+ vboxServiceWinSetStatus(SERVICE_START_PENDING, 0);
+
rc = VBoxServiceStartServices();
if (RT_SUCCESS(rc))
{
diff --git a/src/VBox/Additions/common/VBoxService/VBoxService.cpp b/src/VBox/Additions/common/VBoxService/VBoxService.cpp
index 639b97f7..8ce44dae 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxService.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxService.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,6 +56,9 @@
#include <VBox/log.h>
#include "VBoxServiceInternal.h"
+#ifdef VBOX_WITH_GUEST_CONTROL
+# include "VBoxServiceControl.h"
+#endif
/*******************************************************************************
@@ -65,6 +68,7 @@
char *g_pszProgName = (char *)"";
/** The current verbosity level. */
int g_cVerbosity = 0;
+char g_szLogFile[RTPATH_MAX + 128] = "";
/** Logging parameters. */
/** @todo Make this configurable later. */
static PRTLOGGER g_pLoggerRelease = NULL;
@@ -126,7 +130,7 @@ static struct
# endif
{ &g_VMStatistics, NIL_RTTHREAD, false, false, false, false, true },
#endif
-#if defined(VBOX_WITH_PAGE_SHARING) && defined(RT_OS_WINDOWS)
+#if defined(VBOXSERVICE_PAGE_SHARING)
{ &g_PageSharing, NIL_RTTHREAD, false, false, false, false, true },
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
@@ -211,11 +215,12 @@ static void VBoxServiceLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmP
/**
* Creates the default release logger outputting to the specified file.
+ * Pass NULL for disabled logging.
*
* @return IPRT status code.
* @param pszLogFile Filename for log output. Optional.
*/
-static int VBoxServiceLogCreate(const char *pszLogFile)
+int VBoxServiceLogCreate(const char *pszLogFile)
{
/* Create release logger (stdout + file). */
static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
@@ -241,7 +246,8 @@ static int VBoxServiceLogCreate(const char *pszLogFile)
return rc;
}
-static void VBoxServiceLogDestroy(void)
+
+void VBoxServiceLogDestroy(void)
{
RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
}
@@ -633,6 +639,8 @@ int VBoxServiceStopServices(void)
g_aServices[j].pDesc->pfnStop();
}
+ VBoxServiceVerbose(3, "All stop functions for services called\n");
+
/*
* Wait for all the service threads to complete.
*/
@@ -745,6 +753,7 @@ void VBoxServiceMainWait(void)
int main(int argc, char **argv)
{
RTEXITCODE rcExit;
+ bool fUserSession = false;
/*
* Init globals and such.
@@ -769,14 +778,32 @@ int main(int argc, char **argv)
return rcExit;
#endif
+#ifdef VBOX_WITH_GUEST_CONTROL
+ /*
+ * Check if we're the specially spawned VBoxService.exe process that
+ * handles a guest control session.
+ */
+ if ( argc >= 2
+ && !RTStrICmp(argv[1], "guestsession"))
+ fUserSession = true;
+#endif
+
/*
* Connect to the kernel part before daemonizing so we can fail and
* complain if there is some kind of problem. We need to initialize the
* guest lib *before* we do the pre-init just in case one of services needs
* do to some initial stuff with it.
*/
- VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
- rc = VbglR3Init();
+ if (fUserSession)
+ {
+ VBoxServiceVerbose(2, "Calling VbgR3InitUser()\n");
+ rc = VbglR3InitUser();
+ }
+ else
+ {
+ VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
+ rc = VbglR3Init();
+ }
if (RT_FAILURE(rc))
{
if (rc == VERR_ACCESS_DENIED)
@@ -790,12 +817,19 @@ int main(int argc, char **argv)
* Check if we're the specially spawned VBoxService.exe process that
* handles page fusion. This saves an extra executable.
*/
- if ( argc == 2
- && !strcmp(argv[1], "--pagefusionfork"))
+ if ( argc == 2
+ && !RTStrICmp(argv[1], "pagefusion"))
return VBoxServicePageSharingInitFork();
#endif
- char szLogFile[RTPATH_MAX + 128] = "";
+#ifdef VBOX_WITH_GUEST_CONTROL
+ /*
+ * Check if we're the specially spawned VBoxService.exe process that
+ * handles a guest control session.
+ */
+ if (fUserSession)
+ return VBoxServiceControlSessionForkInit(argc, argv);
+#endif
/*
* Parse the arguments.
@@ -845,17 +879,17 @@ int main(int argc, char **argv)
{
bool fFound = false;
- if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
+ if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-")))
for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
g_aServices[j].fEnabled = true;
- if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
+ if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-")))
for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
g_aServices[j].fEnabled = false;
- if (cch > sizeof("only-") && !memcmp(psz, "only-", sizeof("only-") - 1))
+ if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-")))
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
{
g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
@@ -925,7 +959,7 @@ int main(int argc, char **argv)
case 'l':
{
rc = VBoxServiceArgString(argc, argv, psz + 1, &i,
- szLogFile, sizeof(szLogFile));
+ g_szLogFile, sizeof(g_szLogFile));
if (rc)
return rc;
psz = NULL;
@@ -960,10 +994,10 @@ int main(int argc, char **argv)
if (vboxServiceCountEnabledServices() == 0)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");
- rc = VBoxServiceLogCreate(strlen(szLogFile) ? szLogFile : NULL);
+ rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
- strlen(szLogFile) ? szLogFile : "<None>", rc);
+ strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);
/* Call pre-init if we didn't do it already. */
rcExit = vboxServiceLazyPreInit();
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp
index 06d172e4..190418b4 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2011 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -243,22 +243,32 @@ static int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char
int rc = VINF_SUCCESS;
char szAlreadyMountedTo[RTPATH_MAX];
- /* If a Shared Folder already is mounted but not to our desired mount point,
- * do an unmount first! */
- if ( VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo))
- && RTStrICmp(pszMountPoint, szAlreadyMountedTo))
+ bool fSkip = false;
+
+ /* Already mounted? */
+ if (VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo)))
{
- VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
- pszShareName, szAlreadyMountedTo);
- rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
- if (RT_FAILURE(rc))
- VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
- szAlreadyMountedTo, strerror(errno), errno);
+ fSkip = true;
+ /* Do if it not mounted to our desired mount point */
+ if (RTStrICmp(pszMountPoint, szAlreadyMountedTo))
+ {
+ VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
+ pszShareName, szAlreadyMountedTo);
+ rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
+ szAlreadyMountedTo, strerror(errno), errno);
+ else
+ fSkip = false;
+ }
+ if (fSkip)
+ VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", skipping\n",
+ pszShareName, szAlreadyMountedTo);
}
- if (RT_SUCCESS(rc))
+ if (!fSkip && RT_SUCCESS(rc))
rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
- if (RT_SUCCESS(rc))
+ if (!fSkip && RT_SUCCESS(rc))
{
#ifdef RT_OS_SOLARIS
char achOptBuf[MAX_MNTOPT_STR] = { '\0', };
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp
index ecfd743c..3d5d0a86 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp
index 60b96671..3f88642a 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp
@@ -957,8 +957,8 @@ static DECLCALLBACK(int) VBoxServiceClipboardOS2Worker(bool volatile *pfShutdown
while (WinGetMsg(g_habWorker, &qmsg, NULLHANDLE, NULLHANDLE, 0))
{
if (qmsg.msg != WM_TIMER)
- VBoxServiceVerbose(6, "WinGetMsg -> hwnd=%p msg=%#x mp1=%p mp2=%p time=%#x ptl=%d,%d rsrv=%#x\n",
- qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2, qmsg.time, qmsg.ptl.x, qmsg.ptl.y, qmsg.reserved);
+ VBoxServiceVerbose(6, "WinGetMsg -> hwnd=%p msg=%#x mp1=%p mp2=%p time=%#x ptl=%d,%d rsrv=%#x\n",
+ qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2, qmsg.time, qmsg.ptl.x, qmsg.ptl.y, qmsg.reserved);
WinDispatchMsg(g_habWorker, &qmsg);
}
VBoxServiceVerbose(2, "clipboard: Exited PM message loop. *pfShutdown=%RTbool\n", *pfShutdown);
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
index 07778cd7..cd6d5ee6 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,15 +21,18 @@
*******************************************************************************/
#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/env.h>
#include <iprt/file.h>
#include <iprt/getopt.h>
#include <iprt/mem.h>
#include <iprt/path.h>
+#include <iprt/process.h>
#include <iprt/semaphore.h>
#include <iprt/thread.h>
#include <VBox/VBoxGuestLib.h>
#include <VBox/HostServices/GuestControlSvc.h>
#include "VBoxServiceInternal.h"
+#include "VBoxServiceControl.h"
#include "VBoxServiceUtils.h"
using namespace guestControl;
@@ -41,89 +44,45 @@ using namespace guestControl;
static uint32_t g_uControlIntervalMS = 0;
/** The semaphore we're blocking our main control thread on. */
static RTSEMEVENTMULTI g_hControlEvent = NIL_RTSEMEVENTMULTI;
+/** The VM session ID. Changes whenever the VM is restored or reset. */
+static uint64_t g_idControlSession;
/** The guest control service client ID. */
static uint32_t g_uControlSvcClientID = 0;
/** How many started guest processes are kept into memory for supplying
* information to the host. Default is 256 processes. If 0 is specified,
* the maximum number of processes is unlimited. */
static uint32_t g_uControlProcsMaxKept = 256;
-#ifdef DEBUG
- static bool g_fControlDumpStdErr = false;
- static bool g_fControlDumpStdOut = false;
-#endif
-/** List of active guest control threads (VBOXSERVICECTRLTHREAD). */
-static RTLISTANCHOR g_lstControlThreadsActive;
-/** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */
-static RTLISTANCHOR g_lstControlThreadsInactive;
-/** Critical section protecting g_GuestControlExecThreads. */
-static RTCRITSECT g_csControlThreads;
-/** List of guest control files (VBOXSERVICECTRLFILE).
- **@todo Use a map (later). */
-static RTLISTANCHOR g_lstControlFiles;
-/** The internal file count for building our internal file handles.
- * Should be enough for now. */
-static uint32_t g_uControlFileCount = 0;
-
+/** List of guest control session threads (VBOXSERVICECTRLSESSIONTHREAD).
+ * A guest session thread represents a forked guest session process
+ * of VBoxService. */
+RTLISTANCHOR g_lstControlSessionThreads;
+/** The local session object used for handling all session-related stuff.
+ * When using the legacy guest control protocol (< 2), this session runs
+ * under behalf of the VBoxService main process. On newer protocol versions
+ * each session is a forked version of VBoxService using the appropriate
+ * user credentials for opening a guest session. These forked sessions then
+ * are kept in VBOXSERVICECTRLSESSIONTHREAD structures. */
+VBOXSERVICECTRLSESSION g_Session;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
-/** @todo Shorten "VBoxServiceControl" to "gstsvcCntl". */
-static int VBoxServiceControlReapThreads(void);
-static int VBoxServiceControlStartAllowed(bool *pbAllowed);
-static int VBoxServiceControlHandleCmdStartProc(uint32_t u32ClientId, uint32_t uNumParms);
-static int VBoxServiceControlHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms, void *pvScratchBuf, size_t cbScratchBuf);
-static int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
-static int VBoxServiceControlHandleFileOpen(uint32_t idClient, uint32_t cParms);
-static int VBoxServiceControlHandleFileClose(uint32_t idClient, uint32_t cParms);
-static int VBoxServiceControlHandleFileRead(uint32_t idClient, uint32_t cParms);
-static int VBoxServiceControlHandleFileWrite(uint32_t idClient, uint32_t cParms, void *pvScratchBuf, size_t cbScratchBuf);
-static int VBoxServiceControlHandleFileSeek(uint32_t idClient, uint32_t cParms);
-static int VBoxServiceControlHandleFileTell(uint32_t idClient, uint32_t cParms);
-
-#ifdef DEBUG
-static int vboxServiceControlDump(const char *pszFileName, void *pvBuf, size_t cbBuf)
-{
- AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
-
- if (!cbBuf)
- return VINF_SUCCESS;
-
- char szFile[RTPATH_MAX];
-
- int rc = RTPathTemp(szFile, sizeof(szFile));
- if (RT_SUCCESS(rc))
- rc = RTPathAppend(szFile, sizeof(szFile), pszFileName);
-
- if (RT_SUCCESS(rc))
- {
- VBoxServiceVerbose(4, "Dumping %ld bytes to \"%s\"\n", cbBuf, szFile);
-
- RTFILE fh;
- rc = RTFileOpen(&fh, szFile, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
- if (RT_SUCCESS(rc))
- {
- rc = RTFileWrite(fh, pvBuf, cbBuf, NULL /* pcbWritten */);
- RTFileClose(fh);
- }
- }
-
- return rc;
-}
-#endif
+static int gstcntlHandleSessionOpen(PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlHandleSessionClose(PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static void VBoxServiceControlShutdown(void);
/** @copydoc VBOXSERVICE::pfnPreInit */
static DECLCALLBACK(int) VBoxServiceControlPreInit(void)
{
+ int rc;
#ifdef VBOX_WITH_GUEST_PROPS
/*
* Read the service options from the VM's guest properties.
* Note that these options can be overridden by the command line options later.
*/
uint32_t uGuestPropSvcClientID;
- int rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
+ rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
if (RT_FAILURE(rc))
{
if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
@@ -132,23 +91,27 @@ static DECLCALLBACK(int) VBoxServiceControlPreInit(void)
rc = VINF_SUCCESS;
}
else
- VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
+ VBoxServiceError("Failed to connect to the guest property service, rc=%Rrc\n", rc);
}
else
{
- rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--control-procs-max-kept",
- &g_uControlProcsMaxKept, 0, UINT32_MAX - 1);
-
VbglR3GuestPropDisconnect(uGuestPropSvcClientID);
}
if (rc == VERR_NOT_FOUND) /* If a value is not found, don't be sad! */
rc = VINF_SUCCESS;
- return rc;
#else
/* Nothing to do here yet. */
- return VINF_SUCCESS;
+ rc = VINF_SUCCESS;
#endif
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Init session object. */
+ rc = GstCntlSessionInit(&g_Session, 0 /* Flags */);
+ }
+
+ return rc;
}
@@ -161,18 +124,15 @@ static DECLCALLBACK(int) VBoxServiceControlOption(const char **ppszShort, int ar
else if (!strcmp(argv[*pi], "--control-interval"))
rc = VBoxServiceArgUInt32(argc, argv, "", pi,
&g_uControlIntervalMS, 1, UINT32_MAX - 1);
- else if (!strcmp(argv[*pi], "--control-procs-max-kept"))
- rc = VBoxServiceArgUInt32(argc, argv, "", pi,
- &g_uControlProcsMaxKept, 0, UINT32_MAX - 1);
#ifdef DEBUG
- else if (!strcmp(argv[*pi], "--control-dump-stderr"))
+ else if (!strcmp(argv[*pi], "--control-dump-stdout"))
{
- g_fControlDumpStdErr = true;
+ g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT;
rc = 0; /* Flag this command as parsed. */
}
- else if (!strcmp(argv[*pi], "--control-dump-stdout"))
+ else if (!strcmp(argv[*pi], "--control-dump-stderr"))
{
- g_fControlDumpStdOut = true;
+ g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR;
rc = 0; /* Flag this command as parsed. */
}
#endif
@@ -193,19 +153,18 @@ static DECLCALLBACK(int) VBoxServiceControlInit(void)
int rc = RTSemEventMultiCreate(&g_hControlEvent);
AssertRCReturn(rc, rc);
- rc = VbglR3GuestCtrlConnect(&g_uControlSvcClientID);
+ VbglR3GetSessionId(&g_idControlSession);
+ /* The status code is ignored as this information is not available with VBox < 3.2.10. */
+
+ if (RT_SUCCESS(rc))
+ rc = VbglR3GuestCtrlConnect(&g_uControlSvcClientID);
if (RT_SUCCESS(rc))
{
- VBoxServiceVerbose(3, "Service client ID: %#x\n", g_uControlSvcClientID);
-
- /* Init lists. */
- RTListInit(&g_lstControlThreadsActive);
- RTListInit(&g_lstControlThreadsInactive);
- RTListInit(&g_lstControlFiles);
+ VBoxServiceVerbose(3, "Guest control service client ID=%RU32\n",
+ g_uControlSvcClientID);
- /* Init critical section for protecting the thread lists. */
- rc = RTCritSectInit(&g_csControlThreads);
- AssertRC(rc);
+ /* Init session thread list. */
+ RTListInit(&g_lstControlSessionThreads);
}
else
{
@@ -244,75 +203,91 @@ DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
uint8_t *pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
AssertPtrReturn(pvScratchBuf, VERR_NO_MEMORY);
- /*
- * Execution loop.
- *
- * @todo
- */
+ VBGLR3GUESTCTRLCMDCTX ctxHost = { g_uControlSvcClientID };
+ /* Set default protocol version to 1. */
+ ctxHost.uProtocol = 1;
+
for (;;)
{
VBoxServiceVerbose(3, "Waiting for host msg ...\n");
uint32_t uMsg = 0;
uint32_t cParms = 0;
- rc = VbglR3GuestCtrlWaitForHostMsg(g_uControlSvcClientID, &uMsg, &cParms);
+ rc = VbglR3GuestCtrlMsgWaitFor(g_uControlSvcClientID, &uMsg, &cParms);
if (rc == VERR_TOO_MUCH_DATA)
{
+#ifdef DEBUG
VBoxServiceVerbose(4, "Message requires %ld parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms);
+#endif
rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */
}
else if (RT_FAILURE(rc))
VBoxServiceVerbose(3, "Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
if (RT_SUCCESS(rc))
{
- VBoxServiceVerbose(3, "Msg=%u (%u parms) retrieved\n", uMsg, cParms);
- switch (uMsg)
- {
- case HOST_CANCEL_PENDING_WAITS:
- VBoxServiceVerbose(3, "Host asked us to quit ...\n");
- break;
-
- case HOST_EXEC_CMD:
- rc = VBoxServiceControlHandleCmdStartProc(g_uControlSvcClientID, cParms);
- break;
-
- case HOST_EXEC_SET_INPUT:
- rc = VBoxServiceControlHandleCmdSetInput(g_uControlSvcClientID, cParms,
- pvScratchBuf, cbScratchBuf);
- break;
-
- case HOST_EXEC_GET_OUTPUT:
- rc = VBoxServiceControlHandleCmdGetOutput(g_uControlSvcClientID, cParms);
- break;
+ VBoxServiceVerbose(4, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
- case HOST_FILE_OPEN:
- rc = VBoxServiceControlHandleFileOpen(g_uControlSvcClientID, cParms);
- break;
+ /* Set number of parameters for current host context. */
+ ctxHost.uNumParms = cParms;
- case HOST_FILE_CLOSE:
- rc = VBoxServiceControlHandleFileClose(g_uControlSvcClientID, cParms);
- break;
+ /* Check for VM session change. */
+ uint64_t idNewSession = g_idControlSession;
+ int rc2 = VbglR3GetSessionId(&idNewSession);
+ if ( RT_SUCCESS(rc2)
+ && (idNewSession != g_idControlSession))
+ {
+ VBoxServiceVerbose(1, "The VM session ID changed\n");
+ g_idControlSession = idNewSession;
- case HOST_FILE_READ:
- rc = VBoxServiceControlHandleFileRead(g_uControlSvcClientID, cParms);
- break;
+ /* Close all opened guest sessions -- all context IDs, sessions etc.
+ * are now invalid. */
+ rc2 = GstCntlSessionClose(&g_Session);
+ AssertRC(rc2);
+ }
- case HOST_FILE_WRITE:
- rc = VBoxServiceControlHandleFileWrite(g_uControlSvcClientID, cParms,
- pvScratchBuf, cbScratchBuf);
+ switch (uMsg)
+ {
+ case HOST_CANCEL_PENDING_WAITS:
+ VBoxServiceVerbose(1, "We were asked to quit ...\n");
break;
- case HOST_FILE_SEEK:
- rc = VBoxServiceControlHandleFileSeek(g_uControlSvcClientID, cParms);
+ case HOST_SESSION_CREATE:
+ rc = gstcntlHandleSessionOpen(&ctxHost);
break;
- case HOST_FILE_TELL:
- rc = VBoxServiceControlHandleFileTell(g_uControlSvcClientID, cParms);
+ case HOST_SESSION_CLOSE:
+ rc = gstcntlHandleSessionClose(&ctxHost);
break;
default:
- VBoxServiceVerbose(3, "Unsupported message from host! Msg=%u\n", uMsg);
- /* Don't terminate here; just wait for the next message. */
+ {
+ /*
+ * Protocol v1 did not have support for (dedicated)
+ * guest sessions, so all actions need to be performed
+ * under behalf of VBoxService's main executable.
+ *
+ * The global session object then acts as a host for all
+ * started guest processes which bring all their
+ * credentials with them with the actual guest process
+ * execution call.
+ */
+ if (ctxHost.uProtocol == 1)
+ {
+ rc = GstCntlSessionHandler(&g_Session, uMsg, &ctxHost,
+ pvScratchBuf, cbScratchBuf, pfShutdown);
+ }
+ else
+ {
+ /*
+ * ... on newer protocols handling all other commands is
+ * up to the guest session fork of VBoxService, so just
+ * skip all not wanted messages here.
+ */
+ rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID);
+ VBoxServiceVerbose(3, "Skipping uMsg=%RU32, cParms=%RU32, rc=%Rrc\n",
+ uMsg, cParms, rc);
+ }
break;
+ }
}
}
@@ -320,7 +295,6 @@ DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
if ( *pfShutdown
|| (RT_SUCCESS(rc) && uMsg == HOST_CANCEL_PENDING_WAITS))
{
- rc = VINF_SUCCESS;
break;
}
@@ -328,630 +302,96 @@ DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
RTThreadYield();
}
+ VBoxServiceVerbose(0, "Guest control service stopped\n");
+
/* Delete scratch buffer. */
if (pvScratchBuf)
RTMemFree(pvScratchBuf);
+ VBoxServiceVerbose(0, "Guest control worker returned with rc=%Rrc\n", rc);
return rc;
}
-/**
- * Handles starting processes on the guest.
- *
- * @returns IPRT status code.
- * @param uClientID The HGCM client session ID.
- * @param cParms The number of parameters the host is offering.
- */
-static int VBoxServiceControlHandleCmdStartProc(uint32_t uClientID, uint32_t cParms)
-{
- uint32_t uContextID = 0;
-
- int rc;
- bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */
- if (cParms == 11)
- {
- VBOXSERVICECTRLPROCESS proc;
- RT_ZERO(proc);
-
- /* Initialize maximum environment block size -- needed as input
- * parameter to retrieve the stuff from the host. On output this then
- * will contain the actual block size. */
- proc.cbEnv = sizeof(proc.szEnv);
-
- rc = VbglR3GuestCtrlExecGetHostCmdExec(uClientID,
- cParms,
- &uContextID,
- /* Command */
- proc.szCmd, sizeof(proc.szCmd),
- /* Flags */
- &proc.uFlags,
- /* Arguments */
- proc.szArgs, sizeof(proc.szArgs), &proc.uNumArgs,
- /* Environment */
- proc.szEnv, &proc.cbEnv, &proc.uNumEnvVars,
- /* Credentials */
- proc.szUser, sizeof(proc.szUser),
- proc.szPassword, sizeof(proc.szPassword),
- /* Timelimit */
- &proc.uTimeLimitMS);
- if (RT_SUCCESS(rc))
- {
- VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s, uTimeout=%u\n",
- proc.szCmd, proc.uFlags,
- proc.uNumArgs ? proc.szArgs : "<None>",
- proc.uNumEnvVars ? proc.szEnv : "<None>",
- proc.szUser,
-#ifdef DEBUG
- proc.szPassword,
-#else
- "XXX", /* Never show passwords in release mode. */
-#endif
- proc.uTimeLimitMS);
-
- rc = VBoxServiceControlReapThreads();
- if (RT_FAILURE(rc))
- VBoxServiceError("Reaping stopped processes failed with rc=%Rrc\n", rc);
- /* Keep going. */
-
- rc = VBoxServiceControlStartAllowed(&fStartAllowed);
- if (RT_SUCCESS(rc))
- {
- if (fStartAllowed)
- {
- rc = VBoxServiceControlThreadStart(uContextID, &proc);
- }
- else
- rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */
- }
- }
- }
- else
- rc = VERR_INVALID_PARAMETER; /* Incorrect number of parameters. */
-
- /* In case of an error we need to notify the host to not wait forever for our response. */
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("Starting process failed with rc=%Rrc\n", rc);
-
- /*
- * Note: The context ID can be 0 because we mabye weren't able to fetch the command
- * from the host. The host in case has to deal with that!
- */
- int rc2 = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID /* Might be 0 */, 0 /* PID, invalid */,
- PROC_STS_ERROR, rc,
- NULL /* pvData */, 0 /* cbData */);
- if (RT_FAILURE(rc2))
- {
- VBoxServiceError("Error sending start process status to host, rc=%Rrc\n", rc2);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- }
-
- return rc;
-}
-
-
-/**
- * Gets output from stdout/stderr of a specified guest process.
- *
- * @return IPRT status code.
- * @param uPID PID of process to retrieve the output from.
- * @param uHandleId Stream ID (stdout = 0, stderr = 2) to get the output from.
- * @param uTimeout Timeout (in ms) to wait for output becoming available.
- * @param pvBuf Pointer to a pre-allocated buffer to store the output.
- * @param cbBuf Size (in bytes) of the pre-allocated buffer.
- * @param pcbRead Pointer to number of bytes read. Optional.
- */
-int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uCID,
- uint32_t uHandleId, uint32_t uTimeout,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static int gstcntlHandleSessionOpen(PVBGLR3GUESTCTRLCMDCTX pHostCtx)
{
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbRead is optional. */
-
- int rc = VINF_SUCCESS;
- VBOXSERVICECTRLREQUESTTYPE reqType;
- switch (uHandleId)
- {
- case OUTPUT_HANDLE_ID_STDERR:
- reqType = VBOXSERVICECTRLREQUEST_STDERR_READ;
- break;
-
- case OUTPUT_HANDLE_ID_STDOUT:
- case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED:
- reqType = VBOXSERVICECTRLREQUEST_STDOUT_READ;
- break;
-
- default:
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- PVBOXSERVICECTRLREQUEST pRequest;
- if (RT_SUCCESS(rc))
- {
- rc = VBoxServiceControlThreadRequestAllocEx(&pRequest, reqType,
- pvBuf, cbBuf, uCID);
- if (RT_SUCCESS(rc))
- rc = VBoxServiceControlThreadPerform(uPID, pRequest);
-
- if (RT_SUCCESS(rc))
- {
- if (pcbRead)
- *pcbRead = pRequest->cbData;
- }
-
- VBoxServiceControlThreadRequestFree(pRequest);
- }
-
- return rc;
-}
-
-
-/**
- * Sets the specified guest thread to a certain list.
- *
- * @return IPRT status code.
- * @param enmList List to move thread to.
- * @param pThread Thread to set inactive.
- */
-int VBoxServiceControlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList,
- PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&g_csControlThreads);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ VBOXSERVICECTRLSESSIONSTARTUPINFO ssInfo = { 0 };
+ int rc = VbglR3GuestCtrlSessionGetOpen(pHostCtx,
+ &ssInfo.uProtocol,
+ ssInfo.szUser, sizeof(ssInfo.szUser),
+ ssInfo.szPassword, sizeof(ssInfo.szPassword),
+ ssInfo.szDomain, sizeof(ssInfo.szDomain),
+ &ssInfo.uFlags, &ssInfo.uSessionID);
if (RT_SUCCESS(rc))
{
- VBoxServiceVerbose(3, "Setting thread (PID %u) to list %d\n",
- pThread->uPID, enmList);
-
- PRTLISTANCHOR pAnchor = NULL;
- switch (enmList)
- {
- case VBOXSERVICECTRLTHREADLIST_STOPPED:
- pAnchor = &g_lstControlThreadsInactive;
- break;
-
- case VBOXSERVICECTRLTHREADLIST_RUNNING:
- pAnchor = &g_lstControlThreadsActive;
- break;
-
- default:
- AssertMsgFailed(("Unknown list type: %u", enmList));
- break;
- }
-
- if (!pAnchor)
- rc = VERR_INVALID_PARAMETER;
-
- if (RT_SUCCESS(rc))
- {
- if (pThread->pAnchor != NULL)
- {
- /* If thread was assigned to a list before,
- * remove the thread from the old list first. */
- /* rc = */ RTListNodeRemove(&pThread->Node);
- }
+ /* The session open call has the protocol version the host
+ * wants to use. So update the current protocol version with the one the
+ * host wants to use in subsequent calls. */
+ pHostCtx->uProtocol = ssInfo.uProtocol;
+ VBoxServiceVerbose(3, "Client ID=%RU32 now is using protocol %RU32\n",
+ pHostCtx->uClientID, pHostCtx->uProtocol);
- /* Add thread to desired list. */
- /* rc = */ RTListAppend(pAnchor, &pThread->Node);
- pThread->pAnchor = pAnchor;
- }
-
- int rc2 = RTCritSectLeave(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- rc = rc2;
+ rc = GstCntlSessionThreadCreate(&g_lstControlSessionThreads,
+ &ssInfo, NULL /* ppSessionThread */);
}
- return VINF_SUCCESS;
-}
-
-
-/**
- * Injects input to a specified running process.
- *
- * @return IPRT status code.
- * @param uPID PID of process to set the input for.
- * @param fPendingClose Flag indicating whether this is the last input block sent to the process.
- * @param pvBuf Pointer to a buffer containing the actual input data.
- * @param cbBuf Size (in bytes) of the input buffer data.
- * @param pcbWritten Pointer to number of bytes written to the process. Optional.
- */
-int VBoxServiceControlSetInput(uint32_t uPID, uint32_t uCID,
- bool fPendingClose,
- void *pvBuf, uint32_t cbBuf,
- uint32_t *pcbWritten)
-{
- /* pvBuf is optional. */
- /* cbBuf is optional. */
- /* pcbWritten is optional. */
-
- PVBOXSERVICECTRLREQUEST pRequest;
- int rc = VBoxServiceControlThreadRequestAllocEx(&pRequest,
- fPendingClose
- ? VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF
- : VBOXSERVICECTRLREQUEST_STDIN_WRITE,
- pvBuf, cbBuf, uCID);
- if (RT_SUCCESS(rc))
- {
- rc = VBoxServiceControlThreadPerform(uPID, pRequest);
- if (RT_SUCCESS(rc))
- {
- if (pcbWritten)
- *pcbWritten = pRequest->cbData;
- }
-
- VBoxServiceControlThreadRequestFree(pRequest);
- }
-
- return rc;
-}
-
-
-/**
- * Handles input for a started process by copying the received data into its
- * stdin pipe.
- *
- * @returns IPRT status code.
- * @param idClient The HGCM client session ID.
- * @param cParms The number of parameters the host is
- * offering.
- * @param pvScratchBuf The scratch buffer.
- * @param cbScratchBuf The scratch buffer size for retrieving the input data.
- */
-static int VBoxServiceControlHandleCmdSetInput(uint32_t idClient, uint32_t cParms,
- void *pvScratchBuf, size_t cbScratchBuf)
-{
- AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
-
- uint32_t uContextID;
- uint32_t uPID;
- uint32_t uFlags;
- uint32_t cbSize;
-
- uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status sent back to the host. */
- uint32_t cbWritten = 0; /* Number of bytes written to the guest. */
-
- /*
- * Ask the host for the input data.
- */
- int rc = VbglR3GuestCtrlExecGetHostCmdInput(idClient, cParms,
- &uContextID, &uPID, &uFlags,
- pvScratchBuf, cbScratchBuf, &cbSize);
if (RT_FAILURE(rc))
{
- VBoxServiceError("[PID %u]: Failed to retrieve exec input command! Error: %Rrc\n",
- uPID, rc);
- }
- else if (cbSize > cbScratchBuf)
- {
- VBoxServiceError("[PID %u]: Too much input received! cbSize=%u, cbScratchBuf=%u\n",
- uPID, cbSize, cbScratchBuf);
- rc = VERR_INVALID_PARAMETER;
- }
- else
- {
- /*
- * Is this the last input block we need to deliver? Then let the pipe know ...
- */
- bool fPendingClose = false;
- if (uFlags & INPUT_FLAG_EOF)
- {
- fPendingClose = true;
- VBoxServiceVerbose(4, "[PID %u]: Got last input block of size %u ...\n",
- uPID, cbSize);
- }
-
- rc = VBoxServiceControlSetInput(uPID, uContextID, fPendingClose, pvScratchBuf,
- cbSize, &cbWritten);
- VBoxServiceVerbose(4, "[PID %u]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
- uPID, uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten);
- if (RT_SUCCESS(rc))
- {
- uStatus = INPUT_STS_WRITTEN;
- uFlags = 0; /* No flags at the moment. */
- }
- else
- {
- if (rc == VERR_BAD_PIPE)
- uStatus = INPUT_STS_TERMINATED;
- else if (rc == VERR_BUFFER_OVERFLOW)
- uStatus = INPUT_STS_OVERFLOW;
- }
- }
-
- /*
- * If there was an error and we did not set the host status
- * yet, then do it now.
- */
- if ( RT_FAILURE(rc)
- && uStatus == INPUT_STS_UNDEFINED)
- {
- uStatus = INPUT_STS_ERROR;
- uFlags = rc;
+ /* Report back on failure. On success this will be done
+ * by the forked session thread. */
+ int rc2 = VbglR3GuestCtrlSessionNotify(pHostCtx,
+ GUEST_SESSION_NOTIFYTYPE_ERROR, rc /* uint32_t vs. int */);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Reporting session error status on open failed with rc=%Rrc\n", rc2);
}
- Assert(uStatus > INPUT_STS_UNDEFINED);
-
- VBoxServiceVerbose(3, "[PID %u]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n",
- uPID, uContextID, uStatus, uFlags, cbWritten);
- /* Note: Since the context ID is unique the request *has* to be completed here,
- * regardless whether we got data or not! Otherwise the progress object
- * on the host never will get completed! */
- rc = VbglR3GuestCtrlExecReportStatusIn(idClient, uContextID, uPID,
- uStatus, uFlags, (uint32_t)cbWritten);
-
- if (RT_FAILURE(rc))
- VBoxServiceError("[PID %u]: Failed to report input status! Error: %Rrc\n",
- uPID, rc);
+ VBoxServiceVerbose(3, "Opening a new guest session returned rc=%Rrc\n", rc);
return rc;
}
-static PVBOXSERVICECTRLFILE VBoxControlGetFile(uint32_t uHandle)
+static int gstcntlHandleSessionClose(PVBGLR3GUESTCTRLCMDCTX pHostCtx)
{
- PVBOXSERVICECTRLFILE pFileCur = NULL;
- /** @todo Use a map later! */
- RTListForEach(&g_lstControlFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
- {
- if (pFileCur->uHandle == uHandle)
- return pFileCur;
- }
-
- return NULL;
-}
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
-
-static int VBoxServiceControlHandleFileOpen(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
-
- char szFile[RTPATH_MAX];
- char szOpenMode[64];
- char szDisposition[64];
- uint32_t uCreationMode;
- uint64_t uOffset;
-
- int rc = VbglR3GuestCtrlFileGetHostCmdOpen(idClient, cParms, &uContextID,
- /* File to open. */
- szFile, sizeof(szFile),
- /* Open mode. */
- szOpenMode, sizeof(szOpenMode),
- /* Disposition. */
- szDisposition, sizeof(szDisposition),
- /* Creation mode. */
- &uCreationMode,
- /* Offset. */
- &uOffset);
+ uint32_t uSessionID, uFlags;
+ int rc = VbglR3GuestCtrlSessionGetClose(pHostCtx, &uFlags, &uSessionID);
if (RT_SUCCESS(rc))
{
- PVBOXSERVICECTRLFILE pFile = (PVBOXSERVICECTRLFILE)RTMemAlloc(sizeof(VBOXSERVICECTRLFILE));
- if (!pFile)
- return VERR_NO_MEMORY;
-
- if (!RTStrPrintf(pFile->szName, sizeof(pFile->szName), "%s", szFile))
- rc = VERR_BUFFER_UNDERFLOW;
+ rc = VERR_NOT_FOUND;
- if (RT_SUCCESS(rc))
+ PVBOXSERVICECTRLSESSIONTHREAD pThread;
+ RTListForEach(&g_lstControlSessionThreads, pThread, VBOXSERVICECTRLSESSIONTHREAD, Node)
{
- uint64_t fFlags = RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; /** @todo Modes! */
- rc = RTFileOpen(&pFile->hFile, pFile->szName, fFlags);
- if ( RT_SUCCESS(rc)
- && uOffset)
+ if (pThread->StartupInfo.uSessionID == uSessionID)
{
- /* Seeking is optional. */
- int rc2 = RTFileSeek(pFile->hFile, (int64_t)uOffset, RTFILE_SEEK_BEGIN, NULL /* Current offset */);
- if (RT_FAILURE(rc2))
- VBoxServiceVerbose(3, "[File %s]: Seeking to offset %RU64 failed; rc=%Rrc\n",
- pFile->szName, uOffset, rc);
+ rc = GstCntlSessionThreadDestroy(pThread, uFlags);
+ break;
}
- else
- VBoxServiceVerbose(3, "[File %s]: Opening failed; rc=%Rrc\n",
- pFile->szName, rc);
- }
-
- uint32_t uHandle = 0;
- if (RT_SUCCESS(rc))
- {
- VBoxServiceVerbose(3, "[File %s]: Opened.\n", pFile->szName);
-
- uHandle = g_uControlFileCount++;
- pFile->uHandle = uHandle;
- /* rc = */ RTListAppend(&g_lstControlFiles, &pFile->Node);
}
-
+#if 0
if (RT_FAILURE(rc))
- RTMemFree(pFile);
-
- /* Report back in any case. */
- int rc2 = VbglR3GuestCtrlFileNotify(idClient, uContextID, uHandle,
- GUESTFILENOTIFYTYPE_OPEN, &rc, sizeof(rc));
- if (RT_FAILURE(rc2))
- VBoxServiceError("[File %s]: Failed to report open status, rc=%Rrc\n",
- szFile, rc2);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- return rc;
-}
-
-
-static int VBoxServiceControlHandleFileClose(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
- uint32_t uHandle;
-
- int rc = VbglR3GuestCtrlFileGetHostCmdClose(idClient, cParms, &uContextID,
- /* File handle to close. */
- &uHandle);
- if (RT_SUCCESS(rc))
- {
- PVBOXSERVICECTRLFILE pFile = VBoxControlGetFile(uHandle);
- if (pFile)
- {
- rc = RTFileClose(pFile->hFile);
- }
- else
- rc = VERR_NOT_FOUND;
-
- /* Report back in any case. */
- int rc2 = VbglR3GuestCtrlFileNotify(idClient, uContextID, uHandle,
- GUESTFILENOTIFYTYPE_CLOSE, &rc, sizeof(rc));
- if (RT_FAILURE(rc2))
- VBoxServiceError("Failed to report close status, rc=%Rrc\n", rc2);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- return rc;
-}
-
-
-static int VBoxServiceControlHandleFileRead(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
- uint32_t uHandle;
- uint32_t cbToRead;
-
- int rc = VbglR3GuestCtrlFileGetHostCmdRead(idClient, cParms, &uContextID,
- &uHandle, &cbToRead);
- if (RT_SUCCESS(rc))
- {
-
- }
- return rc;
-}
-
-
-static int VBoxServiceControlHandleFileWrite(uint32_t idClient, uint32_t cParms,
- void *pvScratchBuf, size_t cbScratchBuf)
-{
- AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
-
- uint32_t uContextID;
- uint32_t uHandle;
- uint32_t cbToWrite;
-
- int rc = VbglR3GuestCtrlFileGetHostCmdWrite(idClient, cParms, &uContextID,
- &uHandle, pvScratchBuf, cbScratchBuf,
- &cbToWrite);
- if (RT_SUCCESS(rc))
- {
-
- }
- return rc;
-}
-
-
-static int VBoxServiceControlHandleFileSeek(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
- uint32_t uHandle;
- uint32_t uSeekMethod;
- uint64_t uOffset; /* Will be converted to int64_t. */
-
- int rc = VbglR3GuestCtrlFileGetHostCmdSeek(idClient, cParms, &uContextID,
- &uHandle, &uSeekMethod, &uOffset);
- if (RT_SUCCESS(rc))
- {
-
- }
- return rc;
-}
-
-
-static int VBoxServiceControlHandleFileTell(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
- uint32_t uHandle;
-
- int rc = VbglR3GuestCtrlFileGetHostCmdTell(idClient, cParms, &uContextID,
- &uHandle);
- if (RT_SUCCESS(rc))
- {
-
- }
- return rc;
-}
-
-
-/**
- * Handles the guest control output command.
- *
- * @return IPRT status code.
- * @param idClient The HGCM client session ID.
- * @param cParms The number of parameters the host is offering.
- */
-static int VBoxServiceControlHandleCmdGetOutput(uint32_t idClient, uint32_t cParms)
-{
- uint32_t uContextID;
- uint32_t uPID;
- uint32_t uHandleID;
- uint32_t uFlags;
-
- int rc = VbglR3GuestCtrlExecGetHostCmdOutput(idClient, cParms,
- &uContextID, &uPID, &uHandleID, &uFlags);
- if (RT_SUCCESS(rc))
- {
- uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);
- if (pBuf)
{
- uint32_t cbRead = 0;
- rc = VBoxServiceControlExecGetOutput(uPID, uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
- pBuf, _64K /* cbSize */, &cbRead);
- VBoxServiceVerbose(3, "[PID %u]: Got output, rc=%Rrc, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
- uPID, rc, uContextID, cbRead, uHandleID, uFlags);
-
-#ifdef DEBUG
- if ( g_fControlDumpStdErr
- && uHandleID == OUTPUT_HANDLE_ID_STDERR)
+ /* Report back on failure. On success this will be done
+ * by the forked session thread. */
+ int rc2 = VbglR3GuestCtrlSessionNotify(pHostCtx,
+ GUEST_SESSION_NOTIFYTYPE_ERROR, rc);
+ if (RT_FAILURE(rc2))
{
- char szPID[RTPATH_MAX];
- if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))
- rc = VERR_BUFFER_UNDERFLOW;
+ VBoxServiceError("Reporting session error status on close failed with rc=%Rrc\n", rc2);
if (RT_SUCCESS(rc))
- rc = vboxServiceControlDump(szPID, pBuf, cbRead);
+ rc = rc2;
}
- else if ( g_fControlDumpStdOut
- && ( uHandleID == OUTPUT_HANDLE_ID_STDOUT
- || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED))
- {
- char szPID[RTPATH_MAX];
- if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))
- rc = VERR_BUFFER_UNDERFLOW;
- if (RT_SUCCESS(rc))
- rc = vboxServiceControlDump(szPID, pBuf, cbRead);
- AssertRC(rc);
- }
-#endif
- /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
- * data which the host needs to work with -- so just pass through all data unfiltered! */
-
- /* Note: Since the context ID is unique the request *has* to be completed here,
- * regardless whether we got data or not! Otherwise the progress object
- * on the host never will get completed! */
- int rc2 = VbglR3GuestCtrlExecSendOut(idClient, uContextID, uPID, uHandleID, uFlags,
- pBuf, cbRead);
- if (RT_SUCCESS(rc))
- rc = rc2;
- else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */
- rc = VINF_SUCCESS;
-
- RTMemFree(pBuf);
}
- else
- rc = VERR_NO_MEMORY;
+#endif
+ VBoxServiceVerbose(2, "Closing guest session %RU32 returned rc=%Rrc\n",
+ uSessionID, rc);
}
-
- if (RT_FAILURE(rc))
- VBoxServiceError("[PID %u]: Error handling output command! Error: %Rrc\n",
- uPID, rc);
+ else
+ VBoxServiceError("Closing guest session %RU32 failed with rc=%Rrc\n",
+ uSessionID, rc);
return rc;
}
@@ -967,8 +407,8 @@ static DECLCALLBACK(void) VBoxServiceControlStop(void)
RTSemEventMultiSignal(g_hControlEvent);
/*
- * Ask the host service to cancel all pending requests so that we can
- * shutdown properly here.
+ * Ask the host service to cancel all pending requests for the main
+ * control thread so that we can shutdown properly here.
*/
if (g_uControlSvcClientID)
{
@@ -983,124 +423,20 @@ static DECLCALLBACK(void) VBoxServiceControlStop(void)
/**
- * Reaps all inactive guest process threads.
- *
- * @return IPRT status code.
- */
-static int VBoxServiceControlReapThreads(void)
-{
- int rc = RTCritSectEnter(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- {
- PVBOXSERVICECTRLTHREAD pThread =
- RTListGetFirst(&g_lstControlThreadsInactive, VBOXSERVICECTRLTHREAD, Node);
- while (pThread)
- {
- PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);
- bool fLast = RTListNodeIsLast(&g_lstControlThreadsInactive, &pThread->Node);
- int rc2 = VBoxServiceControlThreadWait(pThread, 30 * 1000 /* 30 seconds max. */,
- NULL /* rc */);
- if (RT_SUCCESS(rc2))
- {
- RTListNodeRemove(&pThread->Node);
-
- rc2 = VBoxServiceControlThreadFree(pThread);
- if (RT_FAILURE(rc2))
- {
- VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);
- if (RT_SUCCESS(rc)) /* Keep original failure. */
- rc = rc2;
- }
- }
- else
- VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);
- /* Keep going. */
-
- if (fLast)
- break;
-
- pThread = pNext;
- }
-
- int rc2 = RTCritSectLeave(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
-
- VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc);
- return rc;
-}
-
-
-/**
* Destroys all guest process threads which are still active.
*/
static void VBoxServiceControlShutdown(void)
{
VBoxServiceVerbose(2, "Shutting down ...\n");
- /* Signal all threads in the active list that we want to shutdown. */
- PVBOXSERVICECTRLTHREAD pThread;
- RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)
- VBoxServiceControlThreadStop(pThread);
-
- /* Wait for all active threads to shutdown and destroy the active thread list. */
- pThread = RTListGetFirst(&g_lstControlThreadsActive, VBOXSERVICECTRLTHREAD, Node);
- while (pThread)
- {
- PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);
- bool fLast = RTListNodeIsLast(&g_lstControlThreadsActive, &pThread->Node);
-
- int rc2 = VBoxServiceControlThreadWait(pThread,
- 30 * 1000 /* Wait 30 seconds max. */,
- NULL /* rc */);
- if (RT_FAILURE(rc2))
- VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);
-
- if (fLast)
- break;
-
- pThread = pNext;
- }
-
- int rc2 = VBoxServiceControlReapThreads();
+ int rc2 = GstCntlSessionThreadDestroyAll(&g_lstControlSessionThreads,
+ 0 /* Flags */);
if (RT_FAILURE(rc2))
- VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc2);
-
- AssertMsg(RTListIsEmpty(&g_lstControlThreadsActive),
- ("Guest process active thread list still contains entries when it should not\n"));
- AssertMsg(RTListIsEmpty(&g_lstControlThreadsInactive),
- ("Guest process inactive thread list still contains entries when it should not\n"));
-
- /* Destroy critical section. */
- RTCritSectDelete(&g_csControlThreads);
-
- /* Close all left guest files. */
- PVBOXSERVICECTRLFILE pFile;
- pFile = RTListGetFirst(&g_lstControlFiles, VBOXSERVICECTRLFILE, Node);
- while (pFile)
- {
- PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
- bool fLast = RTListNodeIsLast(&g_lstControlFiles, &pFile->Node);
-
- rc2 = RTFileClose(pFile->hFile);
- if (RT_FAILURE(rc2))
- {
- VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n",
- pFile->szName, rc2);
- /* Keep going. */
- }
-
- RTListNodeRemove(&pFile->Node);
-
- if (fLast)
- break;
+ VBoxServiceError("Closing session threads failed with rc=%Rrc\n", rc2);
- pFile = pNext;
- }
-
- AssertMsg(RTListIsEmpty(&g_lstControlFiles),
- ("Guest file list still contains entries when it should not\n"));
+ rc2 = GstCntlSessionClose(&g_Session);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Closing session failed with rc=%Rrc\n", rc2);
VBoxServiceVerbose(2, "Shutting down complete\n");
}
@@ -1127,152 +463,6 @@ static DECLCALLBACK(void) VBoxServiceControlTerm(void)
/**
- * Determines whether starting a new guest process according to the
- * maximum number of concurrent guest processes defined is allowed or not.
- *
- * @return IPRT status code.
- * @param pbAllowed True if starting (another) guest process
- * is allowed, false if not.
- */
-static int VBoxServiceControlStartAllowed(bool *pbAllowed)
-{
- AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- {
- /*
- * Check if we're respecting our memory policy by checking
- * how many guest processes are started and served already.
- */
- bool fLimitReached = false;
- if (g_uControlProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */
- {
- uint32_t uProcsRunning = 0;
- PVBOXSERVICECTRLTHREAD pThread;
- RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)
- uProcsRunning++;
-
- VBoxServiceVerbose(3, "Maximum served guest processes set to %u, running=%u\n",
- g_uControlProcsMaxKept, uProcsRunning);
-
- int32_t iProcsLeft = (g_uControlProcsMaxKept - uProcsRunning - 1);
- if (iProcsLeft < 0)
- {
- VBoxServiceVerbose(3, "Maximum running guest processes reached (%u)\n",
- g_uControlProcsMaxKept);
- fLimitReached = true;
- }
- }
-
- *pbAllowed = !fLimitReached;
-
- int rc2 = RTCritSectLeave(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
-
- return rc;
-}
-
-
-/**
- * Finds a (formerly) started process given by its PID and locks it. Must be unlocked
- * by the caller with VBoxServiceControlThreadUnlock().
- *
- * @return PVBOXSERVICECTRLTHREAD Process structure if found, otherwise NULL.
- * @param uPID PID to search for.
- */
-PVBOXSERVICECTRLTHREAD VBoxServiceControlLockThread(uint32_t uPID)
-{
- PVBOXSERVICECTRLTHREAD pThread = NULL;
- int rc = RTCritSectEnter(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- {
- PVBOXSERVICECTRLTHREAD pThreadCur;
- RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
- {
- if (pThreadCur->uPID == uPID)
- {
- rc = RTCritSectEnter(&pThreadCur->CritSect);
- if (RT_SUCCESS(rc))
- pThread = pThreadCur;
- break;
- }
- }
-
- int rc2 = RTCritSectLeave(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
-
- return pThread;
-}
-
-
-/**
- * Unlocks a previously locked guest process thread.
- *
- * @param pThread Thread to unlock.
- */
-void VBoxServiceControlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertPtr(pThread);
-
- int rc = RTCritSectLeave(&pThread->CritSect);
- AssertRC(rc);
-}
-
-
-/**
- * Assigns a valid PID to a guest control thread and also checks if there already was
- * another (stale) guest process which was using that PID before and destroys it.
- *
- * @return IPRT status code.
- * @param pThread Thread to assign PID to.
- * @param uPID PID to assign to the specified guest control execution thread.
- */
-int VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- AssertReturn(uPID, VERR_INVALID_PARAMETER);
-
- int rc = RTCritSectEnter(&g_csControlThreads);
- if (RT_SUCCESS(rc))
- {
- /* Search old threads using the desired PID and shut them down completely -- it's
- * not used anymore. */
- PVBOXSERVICECTRLTHREAD pThreadCur;
- bool fTryAgain = false;
- do
- {
- RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
- {
- if (pThreadCur->uPID == uPID)
- {
- Assert(pThreadCur != pThread); /* can't happen */
- uint32_t uTriedPID = uPID;
- uPID += 391939;
- VBoxServiceVerbose(2, "PID %u was used before, trying again with %u ...\n",
- uTriedPID, uPID);
- fTryAgain = true;
- break;
- }
- }
- } while (fTryAgain);
-
- /* Assign PID to current thread. */
- pThread->uPID = uPID;
-
- rc = RTCritSectLeave(&g_csControlThreads);
- AssertRC(rc);
- }
-
- return rc;
-}
-
-
-/**
* The 'vminfo' service description.
*/
VBOXSERVICE g_Control =
@@ -1285,8 +475,7 @@ VBOXSERVICE g_Control =
#ifdef DEBUG
" [--control-dump-stderr] [--control-dump-stdout]\n"
#endif
- " [--control-interval <ms>] [--control-procs-max-kept <x>]\n"
- " [--control-procs-mem-std[in|out|err] <KB>]"
+ " [--control-interval <ms>]"
,
/* pszOptions. */
#ifdef DEBUG
@@ -1297,9 +486,6 @@ VBOXSERVICE g_Control =
#endif
" --control-interval Specifies the interval at which to check for\n"
" new control commands. The default is 1000 ms.\n"
- " --control-procs-max-kept\n"
- " Specifies how many started guest processes are\n"
- " kept into memory to work with. Default is 256.\n"
,
/* methods */
VBoxServiceControlPreInit,
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
new file mode 100644
index 00000000..7afe7cb4
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
@@ -0,0 +1,325 @@
+/* $Id: VBoxServiceControl.h $ */
+/** @file
+ * VBoxServiceControl.h - Internal guest control definitions.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___VBoxServiceControl_h
+#define ___VBoxServiceControl_h
+
+#include <iprt/critsect.h>
+#include <iprt/list.h>
+#include <iprt/req.h>
+
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/HostServices/GuestControlSvc.h>
+
+
+/**
+ * Pipe IDs for handling the guest process poll set.
+ */
+typedef enum VBOXSERVICECTRLPIPEID
+{
+ VBOXSERVICECTRLPIPEID_UNKNOWN = 0,
+ VBOXSERVICECTRLPIPEID_STDIN = 10,
+ VBOXSERVICECTRLPIPEID_STDIN_WRITABLE = 11,
+ /** Pipe for reading from guest process' stdout. */
+ VBOXSERVICECTRLPIPEID_STDOUT = 40,
+ /** Pipe for reading from guest process' stderr. */
+ VBOXSERVICECTRLPIPEID_STDERR = 50,
+ /** Notification pipe for waking up the guest process
+ * control thread. */
+ VBOXSERVICECTRLPIPEID_IPC_NOTIFY = 100
+} VBOXSERVICECTRLPIPEID;
+
+/**
+ * Structure for one (opened) guest file.
+ */
+typedef struct VBOXSERVICECTRLFILE
+{
+ /** Pointer to list archor of following
+ * list node.
+ * @todo Would be nice to have a RTListGetAnchor(). */
+ PRTLISTANCHOR pAnchor;
+ /** Node to global guest control file list. */
+ /** @todo Use a map later? */
+ RTLISTNODE Node;
+ /** The file name. */
+ char szName[RTPATH_MAX];
+ /** The file handle on the guest. */
+ RTFILE hFile;
+ /** File handle to identify this file. */
+ uint32_t uHandle;
+ /** Context ID. */
+ uint32_t uContextID;
+} VBOXSERVICECTRLFILE;
+/** Pointer to thread data. */
+typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE;
+
+typedef struct VBOXSERVICECTRLSESSIONSTARTUPINFO
+{
+ /** The session's protocol version to use. */
+ uint32_t uProtocol;
+ /** The session's ID. */
+ uint32_t uSessionID;
+ /** User name (account) to start the guest session under. */
+ char szUser[GUESTPROCESS_MAX_USER_LEN];
+ /** Password of specified user name (account). */
+ char szPassword[GUESTPROCESS_MAX_PASSWORD_LEN];
+ /** Domain of the user account. */
+ char szDomain[GUESTPROCESS_MAX_DOMAIN_LEN];
+ /** Session creation flags.
+ * @sa VBOXSERVICECTRLSESSIONSTARTUPFLAG_* flags. */
+ uint32_t uFlags;
+} VBOXSERVICECTRLSESSIONSTARTUPINFO;
+/** Pointer to thread data. */
+typedef VBOXSERVICECTRLSESSIONSTARTUPINFO *PVBOXSERVICECTRLSESSIONSTARTUPINFO;
+
+/**
+ * Structure for a guest session thread to
+ * observe/control the forked session instance from
+ * the VBoxService main executable.
+ */
+typedef struct VBOXSERVICECTRLSESSIONTHREAD
+{
+ /** Node to global guest control session list. */
+ /** @todo Use a map later? */
+ RTLISTNODE Node;
+ /** The sessions's startup info. */
+ VBOXSERVICECTRLSESSIONSTARTUPINFO
+ StartupInfo;
+ /** The worker thread. */
+ RTTHREAD Thread;
+ /** Critical section for thread-safe use. */
+ RTCRITSECT CritSect;
+ /** Process handle for forked child. */
+ RTPROCESS hProcess;
+ /** Shutdown indicator; will be set when the thread
+ * needs (or is asked) to shutdown. */
+ bool volatile fShutdown;
+ /** Indicator set by the service thread exiting. */
+ bool volatile fStopped;
+ /** Whether the thread was started or not. */
+ bool fStarted;
+#if 0 /* Pipe IPC not used yet. */
+ /** Pollset containing all the pipes. */
+ RTPOLLSET hPollSet;
+ RTPIPE hStdInW;
+ RTPIPE hStdOutR;
+ RTPIPE hStdErrR;
+ struct StdPipe
+ {
+ RTHANDLE hChild;
+ PRTHANDLE phChild;
+ } StdIn,
+ StdOut,
+ StdErr;
+ /** The notification pipe associated with this guest session.
+ * This is NIL_RTPIPE for output pipes. */
+ RTPIPE hNotificationPipeW;
+ /** The other end of hNotificationPipeW. */
+ RTPIPE hNotificationPipeR;
+#endif
+} VBOXSERVICECTRLSESSIONTHREAD;
+/** Pointer to thread data. */
+typedef VBOXSERVICECTRLSESSIONTHREAD *PVBOXSERVICECTRLSESSIONTHREAD;
+
+/** Flag indicating that this session has been forked from
+ * the main executable. */
+#define VBOXSERVICECTRLSESSION_FLAG_FORK RT_BIT(0)
+/** Flag indicating that this session is anonymous, that is,
+ * it will run start guest processes with the same credentials
+ * as the main executable. */
+#define VBOXSERVICECTRLSESSION_FLAG_ANONYMOUS RT_BIT(1)
+/** Flag indicating that started guest processes will dump their
+ * stdout output to a separate file on disk. For debugging. */
+#define VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT RT_BIT(2)
+/** Flag indicating that started guest processes will dump their
+ * stderr output to a separate file on disk. For debugging. */
+#define VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR RT_BIT(3)
+
+/**
+ * Structure for maintaining a guest session. This also
+ * contains all started threads (e.g. for guest processes).
+ *
+ * This structure can act in two different ways:
+ * - For legacy guest control handling (protocol version < 2)
+ * this acts as a per-guest process structure containing all
+ * the information needed to get a guest process up and running.
+ * - For newer guest control protocols (>= 2) this structure is
+ * part of the forked session child, maintaining all guest
+ * control objects under it.
+ */
+typedef struct VBOXSERVICECTRLSESSION
+{
+ /* The session's startup information. */
+ VBOXSERVICECTRLSESSIONSTARTUPINFO
+ StartupInfo;
+ /** List of active guest process threads
+ * (VBOXSERVICECTRLPROCESS). */
+ RTLISTANCHOR lstProcesses;
+ /** List of guest control files (VBOXSERVICECTRLFILE). */
+ RTLISTANCHOR lstFiles;
+ /** The session's critical section. */
+ RTCRITSECT CritSect;
+ /** Internal session flags, not related
+ * to StartupInfo stuff.
+ * @sa VBOXSERVICECTRLSESSION_FLAG_* flags. */
+ uint32_t uFlags;
+ /** How many processes do we allow keeping around at a time? */
+ uint32_t uProcsMaxKept;
+} VBOXSERVICECTRLSESSION;
+/** Pointer to guest session. */
+typedef VBOXSERVICECTRLSESSION *PVBOXSERVICECTRLSESSION;
+
+/**
+ * Structure holding information for starting a guest
+ * process.
+ */
+typedef struct VBOXSERVICECTRLPROCSTARTUPINFO
+{
+ /** Full qualified path of process to start (without arguments). */
+ char szCmd[GUESTPROCESS_MAX_CMD_LEN];
+ /** Process execution flags. @sa */
+ uint32_t uFlags;
+ /** Command line arguments. */
+ char szArgs[GUESTPROCESS_MAX_ARGS_LEN];
+ /** Number of arguments specified in pszArgs. */
+ uint32_t uNumArgs;
+ /** String of environment variables ("FOO=BAR") to pass to the process
+ * to start. */
+ char szEnv[GUESTPROCESS_MAX_ENV_LEN];
+ /** Size (in bytes) of environment variables block. */
+ uint32_t cbEnv;
+ /** Number of environment variables specified in pszEnv. */
+ uint32_t uNumEnvVars;
+ /** User name (account) to start the process under. */
+ char szUser[GUESTPROCESS_MAX_USER_LEN];
+ /** Password of specified user name (account). */
+ char szPassword[GUESTPROCESS_MAX_PASSWORD_LEN];
+ /** Time limit (in ms) of the process' life time. */
+ uint32_t uTimeLimitMS;
+ /** Process priority. */
+ uint32_t uPriority;
+ /** Process affinity. At the moment we support
+ * up to 4 * 64 = 256 CPUs. */
+ uint64_t uAffinity[4];
+ /** Number of used process affinity blocks. */
+ uint32_t uNumAffinity;
+} VBOXSERVICECTRLPROCSTARTUPINFO;
+/** Pointer to a guest process block. */
+typedef VBOXSERVICECTRLPROCSTARTUPINFO *PVBOXSERVICECTRLPROCSTARTUPINFO;
+
+/**
+ * Structure for holding data for one (started) guest process.
+ */
+typedef struct VBOXSERVICECTRLPROCESS
+{
+ /** Node. */
+ RTLISTNODE Node;
+ /** Process handle. */
+ RTPROCESS hProcess;
+ /** Number of references using this struct. */
+ uint32_t cRefs;
+ /** The worker thread. */
+ RTTHREAD Thread;
+ /** The session this guest process
+ * is bound to. */
+ PVBOXSERVICECTRLSESSION pSession;
+ /** Shutdown indicator; will be set when the thread
+ * needs (or is asked) to shutdown. */
+ bool volatile fShutdown;
+ /** Whether the guest process thread was stopped
+ * or not. */
+ bool volatile fStopped;
+ /** Whether the guest process thread was started
+ * or not. */
+ bool fStarted;
+ /** Client ID. */
+ uint32_t uClientID;
+ /** Context ID. */
+ uint32_t uContextID;
+ /** Critical section for thread-safe use. */
+ RTCRITSECT CritSect;
+ /** Process startup information. */
+ VBOXSERVICECTRLPROCSTARTUPINFO
+ StartupInfo;
+ /** The process' PID assigned by the guest OS. */
+ uint32_t uPID;
+ /** The process' request queue to handle requests
+ * from the outside, e.g. the session. */
+ RTREQQUEUE hReqQueue;
+ /** Our pollset, used for accessing the process'
+ * std* pipes + the notification pipe. */
+ RTPOLLSET hPollSet;
+ /** StdIn pipe for addressing writes to the
+ * guest process' stdin.*/
+ RTPIPE hPipeStdInW;
+ /** StdOut pipe for addressing reads from
+ * guest process' stdout.*/
+ RTPIPE hPipeStdOutR;
+ /** StdOut pipe for addressing reads from
+ * guest process' stdout.*/
+ RTPIPE hPipeStdErrR;
+ /** The notification pipe associated with this guest process.
+ * This is NIL_RTPIPE for output pipes. */
+ RTPIPE hNotificationPipeW;
+ /** The other end of hNotificationPipeW. */
+ RTPIPE hNotificationPipeR;
+} VBOXSERVICECTRLPROCESS;
+/** Pointer to thread data. */
+typedef VBOXSERVICECTRLPROCESS *PVBOXSERVICECTRLPROCESS;
+
+RT_C_DECLS_BEGIN
+
+/**
+ * Note on naming conventions:
+ * - VBoxServiceControl* is named everything sub service module related, e.g.
+ * everything which is callable by main() and/or the service dispatcher(s).
+ * - GstCntl* is named everything which declared extern and thus can be called
+ * by different guest control modules as needed.
+ * - gstcntl (all lowercase) is a purely static function to split up functionality
+ * inside a module.
+ */
+
+/* Guest session thread handling. */
+extern int GstCntlSessionThreadCreate(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread);
+extern int GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags);
+extern int GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags);
+extern int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession);
+extern RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv);
+/* Per-session functions. */
+extern PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID);
+extern int GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession);
+extern int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession);
+extern int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags);
+extern int GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf, volatile bool *pfShutdown);
+extern int GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
+extern int GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
+extern int GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed);
+extern int GstCntlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession);
+/* Per-guest process functions. */
+extern int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess);
+extern int GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf);
+extern int GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags);
+extern int GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess);
+extern void GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess);
+extern int GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession, const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo, uint32_t uContext);
+extern int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess);
+extern int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, RTMSINTERVAL msTimeout, int *pRc);
+
+RT_C_DECLS_END
+
+#endif /* ___VBoxServiceControl_h */
+
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
new file mode 100644
index 00000000..c355b581
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
@@ -0,0 +1,2141 @@
+/* $Id: VBoxServiceControlProcess.cpp $ */
+/** @file
+ * VBoxServiceControlThread - Guest process handling.
+ */
+
+/*
+ * Copyright (C) 2012-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/handle.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/pipe.h>
+#include <iprt/poll.h>
+#include <iprt/process.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/HostServices/GuestControlSvc.h>
+
+#include "VBoxServiceInternal.h"
+#include "VBoxServiceControl.h"
+
+using namespace guestControl;
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int gstcntlProcessAssignPID(PVBOXSERVICECTRLPROCESS pThread, uint32_t uPID);
+static int gstcntlProcessLock(PVBOXSERVICECTRLPROCESS pProcess);
+static int gstcntlProcessRequest(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, PFNRT pfnFunction, unsigned cArgs, ...);
+static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);
+static int gstcntlProcessUnlock(PVBOXSERVICECTRLPROCESS pProcess);
+/* Request handlers. */
+static DECLCALLBACK(int) gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf);
+static DECLCALLBACK(int) gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags);
+static DECLCALLBACK(int) gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis);
+
+/**
+ * Initialies the passed in thread data structure with the parameters given.
+ *
+ * @return IPRT status code.
+ * @param pProcess Process to initialize.
+ * @param pSession Guest session the process is bound to.
+ * @param pStartupInfo Startup information.
+ * @param u32ContextID The context ID bound to this request / command.
+ */
+static int gstcntlProcessInit(PVBOXSERVICECTRLPROCESS pProcess,
+ const PVBOXSERVICECTRLSESSION pSession,
+ const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo,
+ uint32_t u32ContextID)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStartupInfo, VERR_INVALID_POINTER);
+
+ /* General stuff. */
+ pProcess->hProcess = NIL_RTPROCESS;
+ pProcess->pSession = pSession;
+ pProcess->Node.pPrev = NULL;
+ pProcess->Node.pNext = NULL;
+
+ pProcess->fShutdown = false;
+ pProcess->fStarted = false;
+ pProcess->fStopped = false;
+
+ pProcess->uPID = 0; /* Don't have a PID yet. */
+ pProcess->cRefs = 0;
+ /*
+ * Use the initial context ID we got for starting
+ * the process to report back its status with the
+ * same context ID.
+ */
+ pProcess->uContextID = u32ContextID;
+ /*
+ * Note: pProcess->ClientID will be assigned when thread is started;
+ * every guest process has its own client ID to detect crashes on
+ * a per-guest-process level.
+ */
+
+ int rc = RTCritSectInit(&pProcess->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ pProcess->hPollSet = NIL_RTPOLLSET;
+ pProcess->hPipeStdInW = NIL_RTPIPE;
+ pProcess->hPipeStdOutR = NIL_RTPIPE;
+ pProcess->hPipeStdErrR = NIL_RTPIPE;
+ pProcess->hNotificationPipeW = NIL_RTPIPE;
+ pProcess->hNotificationPipeR = NIL_RTPIPE;
+
+ rc = RTReqQueueCreate(&pProcess->hReqQueue);
+ AssertReleaseRC(rc);
+
+ /* Copy over startup info. */
+ memcpy(&pProcess->StartupInfo, pStartupInfo, sizeof(VBOXSERVICECTRLPROCSTARTUPINFO));
+
+ /* Adjust timeout value. */
+ if ( pProcess->StartupInfo.uTimeLimitMS == UINT32_MAX
+ || pProcess->StartupInfo.uTimeLimitMS == 0)
+ pProcess->StartupInfo.uTimeLimitMS = RT_INDEFINITE_WAIT;
+
+ if (RT_FAILURE(rc)) /* Clean up on failure. */
+ GstCntlProcessFree(pProcess);
+ return rc;
+}
+
+
+/**
+ * Frees a guest process. On success, pProcess will be
+ * free'd and thus won't be available anymore.
+ *
+ * @return IPRT status code.
+ * @param pProcess Guest process to free.
+ */
+int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Freeing (cRefs=%RU32)...\n",
+ pProcess->uPID, pProcess->cRefs);
+ Assert(pProcess->cRefs == 0);
+
+ /*
+ * Destroy other thread data.
+ */
+ if (RTCritSectIsInitialized(&pProcess->CritSect))
+ RTCritSectDelete(&pProcess->CritSect);
+
+ int rc = RTReqQueueDestroy(pProcess->hReqQueue);
+ AssertRC(rc);
+
+ /*
+ * Remove from list.
+ */
+ AssertPtr(pProcess->pSession);
+ rc = GstCntlSessionProcessRemove(pProcess->pSession, pProcess);
+ AssertRC(rc);
+
+ /*
+ * Destroy thread structure as final step.
+ */
+ RTMemFree(pProcess);
+ pProcess = NULL;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Signals a guest process thread that we want it to shut down in
+ * a gentle way.
+ *
+ * @return IPRT status code.
+ * @param pProcess Process to stop.
+ */
+int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Stopping ...\n",
+ pProcess->uPID);
+
+ /* Do *not* set pThread->fShutdown or other stuff here!
+ * The guest thread loop will clean up itself. */
+
+ return GstCntlProcessHandleTerm(pProcess);
+}
+
+
+/**
+ * Releases a previously acquired guest process (decreases the refcount).
+ *
+ * @param pProcess Process to unlock.
+ */
+void GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturnVoid(pProcess);
+
+ bool fShutdown = false;
+
+ int rc = RTCritSectEnter(&pProcess->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(pProcess->cRefs);
+ pProcess->cRefs--;
+ fShutdown = pProcess->fStopped; /* Has the process' thread been stopped? */
+
+ rc = RTCritSectLeave(&pProcess->CritSect);
+ AssertRC(rc);
+ }
+
+ if (fShutdown)
+ GstCntlProcessFree(pProcess);
+}
+
+
+/**
+ * Wait for a guest process thread to shut down.
+ *
+ * @return IPRT status code.
+ * @param pProcess Process to wait shutting down for.
+ * @param RTMSINTERVAL Timeout in ms to wait for shutdown.
+ * @param pRc Where to store the thread's return code. Optional.
+ */
+int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess,
+ RTMSINTERVAL msTimeout, int *pRc)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ /* pRc is optional. */
+
+ int rc = gstcntlProcessLock(pProcess);
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n",
+ pProcess->uPID, msTimeout);
+
+ AssertMsgReturn(pProcess->fStarted,
+ ("Tried to wait on guest process=%p (PID %RU32) which has not been started yet\n",
+ pProcess, pProcess->uPID), VERR_INVALID_PARAMETER);
+
+ /* Guest process already has been stopped, no need to wait. */
+ if (!pProcess->fStopped)
+ {
+ /* Unlock process before waiting. */
+ rc = gstcntlProcessUnlock(pProcess);
+ AssertRC(rc);
+
+ /* Do the actual waiting. */
+ int rcThread;
+ Assert(pProcess->Thread != NIL_RTTHREAD);
+ rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n",
+ pProcess->uPID, rc);
+ }
+ else
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Thread shutdown complete, thread rc=%Rrc\n",
+ pProcess->uPID, rcThread);
+ if (pRc)
+ *pRc = rcThread;
+ }
+ }
+ else
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Thread already shut down, no waiting needed\n",
+ pProcess->uPID);
+
+ int rc2 = gstcntlProcessUnlock(pProcess);
+ AssertRC(rc2);
+ }
+ }
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Waiting resulted in rc=%Rrc\n",
+ pProcess->uPID, rc);
+ return rc;
+}
+
+
+/**
+ * Closes the stdin pipe of a guest process.
+ *
+ * @return IPRT status code.
+ * @param hPollSet The polling set.
+ * @param phStdInW The standard input pipe handle.
+ */
+static int gstcntlProcessPollsetCloseInput(PVBOXSERVICECTRLPROCESS pProcess,
+ PRTPIPE phStdInW)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
+
+ int rc = RTPollSetRemove(pProcess->hPollSet, VBOXSERVICECTRLPIPEID_STDIN);
+ if (rc != VERR_POLL_HANDLE_ID_NOT_FOUND)
+ AssertRC(rc);
+
+ if (*phStdInW != NIL_RTPIPE)
+ {
+ rc = RTPipeClose(*phStdInW);
+ AssertRC(rc);
+ *phStdInW = NIL_RTPIPE;
+ }
+
+ return rc;
+}
+
+
+static const char* gstcntlProcessPollHandleToString(uint32_t idPollHnd)
+{
+ switch (idPollHnd)
+ {
+ case VBOXSERVICECTRLPIPEID_UNKNOWN:
+ return "unknown";
+ case VBOXSERVICECTRLPIPEID_STDIN:
+ return "stdin";
+ case VBOXSERVICECTRLPIPEID_STDIN_WRITABLE:
+ return "stdin_writable";
+ case VBOXSERVICECTRLPIPEID_STDOUT:
+ return "stdout";
+ case VBOXSERVICECTRLPIPEID_STDERR:
+ return "stderr";
+ case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
+ return "ipc_notify";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+
+/**
+ * Handle an error event on standard input.
+ *
+ * @return IPRT status code.
+ * @param pProcess Process to handle pollset for.
+ * @param fPollEvt The event mask returned by RTPollNoResume.
+ * @param phStdInW The standard input pipe handle.
+ */
+static int gstcntlProcessPollsetOnInput(PVBOXSERVICECTRLPROCESS pProcess,
+ uint32_t fPollEvt, PRTPIPE phStdInW)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ NOREF(fPollEvt);
+
+ return gstcntlProcessPollsetCloseInput(pProcess, phStdInW);
+}
+
+
+/**
+ * Handle pending output data or error on standard out or standard error.
+ *
+ * @returns IPRT status code from client send.
+ * @param pProcess Process to handle pollset for.
+ * @param fPollEvt The event mask returned by RTPollNoResume.
+ * @param phPipeR The pipe handle.
+ * @param idPollHnd The pipe ID to handle.
+ *
+ */
+static int gstcntlProcessHandleOutputError(PVBOXSERVICECTRLPROCESS pProcess,
+ uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ if (!phPipeR)
+ return VINF_SUCCESS;
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[PID %RU32]: Output error: idPollHnd=%s, fPollEvt=0x%x\n",
+ pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt);
+#endif
+
+ /* Remove pipe from poll set. */
+ int rc2 = RTPollSetRemove(pProcess->hPollSet, idPollHnd);
+ AssertMsg(RT_SUCCESS(rc2) || rc2 == VERR_POLL_HANDLE_ID_NOT_FOUND, ("%Rrc\n", rc2));
+
+ bool fClosePipe = true; /* By default close the pipe. */
+
+ /* Check if there's remaining data to read from the pipe. */
+ if (*phPipeR != NIL_RTPIPE)
+ {
+ size_t cbReadable;
+ rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable);
+ if ( RT_SUCCESS(rc2)
+ && cbReadable)
+ {
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s has %zu bytes left, vetoing close\n",
+ pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), cbReadable);
+#endif
+ /* Veto closing the pipe yet because there's still stuff to read
+ * from the pipe. This can happen on UNIX-y systems where on
+ * error/hangup there still can be data to be read out. */
+ fClosePipe = false;
+ }
+ }
+#ifdef DEBUG
+ else
+ VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s will be closed\n",
+ pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd));
+#endif
+
+ if ( *phPipeR != NIL_RTPIPE
+ && fClosePipe)
+ {
+ rc2 = RTPipeClose(*phPipeR);
+ AssertRC(rc2);
+ *phPipeR = NIL_RTPIPE;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Handle pending output data or error on standard out or standard error.
+ *
+ * @returns IPRT status code from client send.
+ * @param pProcess Process to handle pollset for.
+ * @param fPollEvt The event mask returned by RTPollNoResume.
+ * @param phPipeR The pipe handle.
+ * @param idPollHnd The pipe ID to handle.
+ *
+ */
+static int gstcntlProcessPollsetOnOutput(PVBOXSERVICECTRLPROCESS pProcess,
+ uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[PID %RU32]: Output event phPipeR=%p, idPollHnd=%s, fPollEvt=0x%x\n",
+ pProcess->uPID, phPipeR, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt);
+#endif
+
+ if (!phPipeR)
+ return VINF_SUCCESS;
+
+ int rc = VINF_SUCCESS;
+
+#ifdef DEBUG
+ if (*phPipeR != NIL_RTPIPE)
+ {
+ size_t cbReadable;
+ rc = RTPipeQueryReadable(*phPipeR, &cbReadable);
+ if ( RT_SUCCESS(rc)
+ && cbReadable)
+ {
+ VBoxServiceVerbose(4, "[PID %RU32]: Output event cbReadable=%zu\n",
+ pProcess->uPID, cbReadable);
+ }
+ }
+#endif
+
+#if 0
+ /* Push output to the host. */
+ if (fPollEvt & RTPOLL_EVT_READ)
+ {
+ size_t cbRead = 0;
+ uint8_t byData[_64K];
+ rc = RTPipeRead(*phPipeR,
+ byData, sizeof(byData), &cbRead);
+ VBoxServiceVerbose(4, "GstCntlProcessHandleOutputEvent cbRead=%u, rc=%Rrc\n",
+ cbRead, rc);
+
+ /* Make sure we go another poll round in case there was too much data
+ for the buffer to hold. */
+ fPollEvt &= RTPOLL_EVT_ERROR;
+ }
+#endif
+
+ if (fPollEvt & RTPOLL_EVT_ERROR)
+ rc = gstcntlProcessHandleOutputError(pProcess,
+ fPollEvt, phPipeR, idPollHnd);
+ return rc;
+}
+
+
+/**
+ * Execution loop which runs in a dedicated per-started-process thread and
+ * handles all pipe input/output and signalling stuff.
+ *
+ * @return IPRT status code.
+ * @param pProcess The guest process to handle.
+ */
+static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ int rc;
+ int rc2;
+ uint64_t const uMsStart = RTTimeMilliTS();
+ RTPROCSTATUS ProcessStatus = { 254, RTPROCEXITREASON_ABEND };
+ bool fProcessAlive = true;
+ bool fProcessTimedOut = false;
+ uint64_t MsProcessKilled = UINT64_MAX;
+ RTMSINTERVAL const cMsPollBase = pProcess->hPipeStdInW != NIL_RTPIPE
+ ? 100 /* Need to poll for input. */
+ : 1000; /* Need only poll for process exit and aborts. */
+ RTMSINTERVAL cMsPollCur = 0;
+
+ /*
+ * Assign PID to thread data.
+ * Also check if there already was a thread with the same PID and shut it down -- otherwise
+ * the first (stale) entry will be found and we get really weird results!
+ */
+ rc = gstcntlProcessAssignPID(pProcess, pProcess->hProcess /* Opaque PID handle */);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Unable to assign PID=%u, to new thread, rc=%Rrc\n",
+ pProcess->hProcess, rc);
+ return rc;
+ }
+
+ /*
+ * Before entering the loop, tell the host that we've started the guest
+ * and that it's now OK to send input to the process.
+ */
+ VBoxServiceVerbose(2, "[PID %RU32]: Process \"%s\" started, CID=%u, User=%s, cMsTimeout=%RU32\n",
+ pProcess->uPID, pProcess->StartupInfo.szCmd, pProcess->uContextID,
+ pProcess->StartupInfo.szUser, pProcess->StartupInfo.uTimeLimitMS);
+ VBGLR3GUESTCTRLCMDCTX ctxStart = { pProcess->uClientID, pProcess->uContextID };
+ rc = VbglR3GuestCtrlProcCbStatus(&ctxStart,
+ pProcess->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
+ NULL /* pvData */, 0 /* cbData */);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("[PID %RU32]: Error reporting starting status to host, rc=%Rrc\n",
+ pProcess->uPID, rc);
+
+ /*
+ * Process input, output, the test pipe and client requests.
+ */
+ while ( RT_SUCCESS(rc)
+ && RT_UNLIKELY(!pProcess->fShutdown))
+ {
+ /*
+ * Wait/Process all pending events.
+ */
+ uint32_t idPollHnd;
+ uint32_t fPollEvt;
+ rc2 = RTPollNoResume(pProcess->hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
+ if (pProcess->fShutdown)
+ continue;
+
+ cMsPollCur = 0; /* No rest until we've checked everything. */
+
+ if (RT_SUCCESS(rc2))
+ {
+ switch (idPollHnd)
+ {
+ case VBOXSERVICECTRLPIPEID_STDIN:
+ rc = gstcntlProcessPollsetOnInput(pProcess, fPollEvt,
+ &pProcess->hPipeStdInW);
+ break;
+
+ case VBOXSERVICECTRLPIPEID_STDOUT:
+ rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt,
+ &pProcess->hPipeStdOutR, idPollHnd);
+ break;
+
+ case VBOXSERVICECTRLPIPEID_STDERR:
+ rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt,
+ &pProcess->hPipeStdOutR, idPollHnd);
+ break;
+
+ case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
+#ifdef DEBUG_andy
+ VBoxServiceVerbose(4, "[PID %RU32]: IPC notify\n", pProcess->uPID);
+#endif
+ rc2 = gstcntlProcessLock(pProcess);
+ if (RT_SUCCESS(rc2))
+ {
+ /* Drain the notification pipe. */
+ uint8_t abBuf[8];
+ size_t cbIgnore;
+ rc2 = RTPipeRead(pProcess->hNotificationPipeR,
+ abBuf, sizeof(abBuf), &cbIgnore);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc2);
+
+ /* Process all pending requests. */
+ VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests ...\n",
+ pProcess->uPID);
+ Assert(pProcess->hReqQueue != NIL_RTREQQUEUE);
+ rc2 = RTReqQueueProcess(pProcess->hReqQueue,
+ 0 /* Only process all pending requests, don't wait for new ones */);
+ if ( RT_FAILURE(rc2)
+ && rc2 != VERR_TIMEOUT)
+ VBoxServiceError("Processing requests failed with with rc=%Rrc\n", rc2);
+
+ int rc3 = gstcntlProcessUnlock(pProcess);
+ AssertRC(rc3);
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests done, rc=%Rrc\n",
+ pProcess->uPID, rc2);
+#endif
+ }
+
+ break;
+
+ default:
+ AssertMsgFailed(("Unknown idPollHnd=%RU32\n", idPollHnd));
+ break;
+ }
+
+ if (RT_FAILURE(rc) || rc == VINF_EOF)
+ break; /* Abort command, or client dead or something. */
+ }
+#if 0
+ VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%RU32, idPollHnd=%s, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n",
+ pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), gstcntlProcessPollHandleToString(idPollHnd), rc, fProcessAlive, pProcess->fShutdown);
+ VBoxServiceVerbose(4, "[PID %RU32]: stdOut=%s, stdErrR=%s\n",
+ pProcess->uPID,
+ *phStdOutR == NIL_RTPIPE ? "closed" : "open",
+ *phStdErrR == NIL_RTPIPE ? "closed" : "open");
+#endif
+ if (RT_UNLIKELY(pProcess->fShutdown))
+ break; /* We were asked to shutdown. */
+
+ /*
+ * Check for process death.
+ */
+ if (fProcessAlive)
+ {
+ rc2 = RTProcWaitNoResume(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
+#if 0
+ VBoxServiceVerbose(4, "[PID %RU32]: RTProcWaitNoResume=%Rrc\n",
+ pProcess->uPID, rc2);
+#endif
+ if (RT_SUCCESS_NP(rc2))
+ {
+ fProcessAlive = false;
+ /* Note: Don't bail out here yet. First check in the next block below
+ * if all needed pipe outputs have been consumed. */
+ }
+ else
+ {
+ if (RT_UNLIKELY(rc2 == VERR_INTERRUPTED))
+ continue;
+ if (RT_UNLIKELY(rc2 == VERR_PROCESS_NOT_FOUND))
+ {
+ fProcessAlive = false;
+ ProcessStatus.enmReason = RTPROCEXITREASON_ABEND;
+ ProcessStatus.iStatus = 255;
+ AssertFailed();
+ }
+ else
+ AssertMsg(rc2 == VERR_PROCESS_RUNNING, ("%Rrc\n", rc2));
+ }
+ }
+
+ /*
+ * If the process has terminated and all output has been consumed,
+ * we should be heading out.
+ */
+ if (!fProcessAlive)
+ {
+ if ( fProcessTimedOut
+ || ( pProcess->hPipeStdOutR == NIL_RTPIPE
+ && pProcess->hPipeStdErrR == NIL_RTPIPE)
+ )
+ {
+ break;
+ }
+ }
+
+ /*
+ * Check for timed out, killing the process.
+ */
+ uint32_t cMilliesLeft = RT_INDEFINITE_WAIT;
+ if ( pProcess->StartupInfo.uTimeLimitMS != RT_INDEFINITE_WAIT
+ && pProcess->StartupInfo.uTimeLimitMS != 0)
+ {
+ uint64_t u64Now = RTTimeMilliTS();
+ uint64_t cMsElapsed = u64Now - uMsStart;
+ if (cMsElapsed >= pProcess->StartupInfo.uTimeLimitMS)
+ {
+ fProcessTimedOut = true;
+ if ( MsProcessKilled == UINT64_MAX
+ || u64Now - MsProcessKilled > 1000)
+ {
+ if (u64Now - MsProcessKilled > 20*60*1000)
+ break; /* Give up after 20 mins. */
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU64ms elapsed > %RU32ms timeout), killing ...\n",
+ pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS);
+
+ rc2 = RTProcTerminate(pProcess->hProcess);
+ VBoxServiceVerbose(3, "[PID %RU32]: Killing process resulted in rc=%Rrc\n",
+ pProcess->uPID, rc2);
+ MsProcessKilled = u64Now;
+ continue;
+ }
+ cMilliesLeft = 10000;
+ }
+ else
+ cMilliesLeft = pProcess->StartupInfo.uTimeLimitMS - (uint32_t)cMsElapsed;
+ }
+
+ /* Reset the polling interval since we've done all pending work. */
+ cMsPollCur = fProcessAlive
+ ? cMsPollBase
+ : RT_MS_1MIN;
+ if (cMilliesLeft < cMsPollCur)
+ cMsPollCur = cMilliesLeft;
+ }
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Loop ended: rc=%Rrc, fShutdown=%RTbool, fProcessAlive=%RTbool, fProcessTimedOut=%RTbool, MsProcessKilled=%RU64\n",
+ pProcess->uPID, rc, pProcess->fShutdown, fProcessAlive, fProcessTimedOut, MsProcessKilled, MsProcessKilled);
+ VBoxServiceVerbose(3, "[PID %RU32]: *phStdOutR=%s, *phStdErrR=%s\n",
+ pProcess->uPID,
+ pProcess->hPipeStdOutR == NIL_RTPIPE ? "closed" : "open",
+ pProcess->hPipeStdErrR == NIL_RTPIPE ? "closed" : "open");
+
+ /* Signal that this thread is in progress of shutting down. */
+ ASMAtomicXchgBool(&pProcess->fShutdown, true);
+
+ /*
+ * Try killing the process if it's still alive at this point.
+ */
+ if (fProcessAlive)
+ {
+ if (MsProcessKilled == UINT64_MAX)
+ {
+ VBoxServiceVerbose(2, "[PID %RU32]: Is still alive and not killed yet\n",
+ pProcess->uPID);
+
+ MsProcessKilled = RTTimeMilliTS();
+ rc2 = RTProcTerminate(pProcess->hProcess);
+ if (rc2 == VERR_NOT_FOUND)
+ {
+ fProcessAlive = false;
+ }
+ else if (RT_FAILURE(rc2))
+ VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n",
+ pProcess->uPID, rc2);
+ RTThreadSleep(500);
+ }
+
+ for (int i = 0; i < 10 && fProcessAlive; i++)
+ {
+ VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Waiting to exit ...\n",
+ pProcess->uPID, i + 1);
+ rc2 = RTProcWait(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
+ if (RT_SUCCESS(rc2))
+ {
+ VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Exited\n",
+ pProcess->uPID, i + 1);
+ fProcessAlive = false;
+ break;
+ }
+ if (i >= 5)
+ {
+ VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Trying to terminate ...\n",
+ pProcess->uPID, i + 1);
+ rc2 = RTProcTerminate(pProcess->hProcess);
+ if ( RT_FAILURE(rc)
+ && rc2 != VERR_NOT_FOUND)
+ VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n",
+ pProcess->uPID, rc2);
+ }
+ RTThreadSleep(i >= 5 ? 2000 : 500);
+ }
+
+ if (fProcessAlive)
+ VBoxServiceError("[PID %RU32]: Could not be killed\n", pProcess->uPID);
+ }
+
+ /*
+ * Shutdown procedure:
+ * - Set the pProcess->fShutdown indicator to let others know we're
+ * not accepting any new requests anymore.
+ * - After setting the indicator, try to process all outstanding
+ * requests to make sure they're getting delivered.
+ *
+ * Note: After removing the process from the session's list it's not
+ * even possible for the session anymore to control what's
+ * happening to this thread, so be careful and don't mess it up.
+ */
+
+ rc2 = gstcntlProcessLock(pProcess);
+ if (RT_SUCCESS(rc2))
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests ...\n",
+ pProcess->uPID);
+
+ /* Process all pending requests (but don't wait for new ones). */
+ Assert(pProcess->hReqQueue != NIL_RTREQQUEUE);
+ rc2 = RTReqQueueProcess(pProcess->hReqQueue, 0 /* No timeout */);
+ if ( RT_FAILURE(rc2)
+ && rc2 != VERR_TIMEOUT)
+ VBoxServiceError("[PID %RU32]: Processing outstanding requests failed with with rc=%Rrc\n",
+ pProcess->uPID, rc2);
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests done, rc=%Rrc\n",
+ pProcess->uPID, rc2);
+
+ rc2 = gstcntlProcessUnlock(pProcess);
+ AssertRC(rc2);
+ }
+
+ /*
+ * If we don't have a client problem (RT_FAILURE(rc)) we'll reply to the
+ * clients exec packet now.
+ */
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t uStatus = PROC_STS_UNDEFINED;
+ uint32_t uFlags = 0;
+
+ if ( fProcessTimedOut && !fProcessAlive && MsProcessKilled != UINT64_MAX)
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Timed out and got killed\n",
+ pProcess->uPID);
+ uStatus = PROC_STS_TOK;
+ }
+ else if (fProcessTimedOut && fProcessAlive && MsProcessKilled != UINT64_MAX)
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Timed out and did *not* get killed\n",
+ pProcess->uPID);
+ uStatus = PROC_STS_TOA;
+ }
+ else if (pProcess->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Got terminated because system/service is about to shutdown\n",
+ pProcess->uPID);
+ uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
+ uFlags = pProcess->StartupInfo.uFlags; /* Return handed-in execution flags back to the host. */
+ }
+ else if (fProcessAlive)
+ {
+ VBoxServiceError("[PID %RU32]: Is alive when it should not!\n",
+ pProcess->uPID);
+ }
+ else if (MsProcessKilled != UINT64_MAX)
+ {
+ VBoxServiceError("[PID %RU32]: Has been killed when it should not!\n",
+ pProcess->uPID);
+ }
+ else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %d)\n",
+ pProcess->uPID, ProcessStatus.iStatus);
+
+ uStatus = PROC_STS_TEN;
+ uFlags = ProcessStatus.iStatus;
+ }
+ else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",
+ pProcess->uPID, ProcessStatus.iStatus);
+
+ uStatus = PROC_STS_TES;
+ uFlags = ProcessStatus.iStatus;
+ }
+ else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
+ {
+ /* ProcessStatus.iStatus will be undefined. */
+ VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_ABEND\n",
+ pProcess->uPID);
+
+ uStatus = PROC_STS_TEA;
+ uFlags = ProcessStatus.iStatus;
+ }
+ else
+ VBoxServiceVerbose(1, "[PID %RU32]: Handling process status %u not implemented\n",
+ pProcess->uPID, ProcessStatus.enmReason);
+
+ VBoxServiceVerbose(2, "[PID %RU32]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
+ pProcess->uPID, pProcess->uClientID, pProcess->uContextID, uStatus, uFlags);
+
+ VBGLR3GUESTCTRLCMDCTX ctxEnd = { pProcess->uClientID, pProcess->uContextID };
+ rc2 = VbglR3GuestCtrlProcCbStatus(&ctxEnd,
+ pProcess->uPID, uStatus, uFlags,
+ NULL /* pvData */, 0 /* cbData */);
+ if ( RT_FAILURE(rc2)
+ && rc2 == VERR_NOT_FOUND)
+ VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n",
+ pProcess->uPID, rc2);
+ }
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Process loop returned with rc=%Rrc\n",
+ pProcess->uPID, rc);
+ return rc;
+}
+
+
+/**
+ * Initializes a pipe's handle and pipe object.
+ *
+ * @return IPRT status code.
+ * @param ph The pipe's handle to initialize.
+ * @param phPipe The pipe's object to initialize.
+ */
+static int gstcntlProcessInitPipe(PRTHANDLE ph, PRTPIPE phPipe)
+{
+ AssertPtrReturn(ph, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER);
+
+ ph->enmType = RTHANDLETYPE_PIPE;
+ ph->u.hPipe = NIL_RTPIPE;
+ *phPipe = NIL_RTPIPE;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets up the redirection / pipe / nothing for one of the standard handles.
+ *
+ * @returns IPRT status code. No client replies made.
+ * @param pszHowTo How to set up this standard handle.
+ * @param fd Which standard handle it is (0 == stdin, 1 ==
+ * stdout, 2 == stderr).
+ * @param ph The generic handle that @a pph may be set
+ * pointing to. Always set.
+ * @param pph Pointer to the RTProcCreateExec argument.
+ * Always set.
+ * @param phPipe Where to return the end of the pipe that we
+ * should service.
+ */
+static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd,
+ PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
+{
+ AssertPtrReturn(ph, VERR_INVALID_POINTER);
+ AssertPtrReturn(pph, VERR_INVALID_POINTER);
+ AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
+
+ int rc;
+
+ ph->enmType = RTHANDLETYPE_PIPE;
+ ph->u.hPipe = NIL_RTPIPE;
+ *pph = NULL;
+ *phPipe = NIL_RTPIPE;
+
+ if (!strcmp(pszHowTo, "|"))
+ {
+ /*
+ * Setup a pipe for forwarding to/from the client.
+ * The ph union struct will be filled with a pipe read/write handle
+ * to represent the "other" end to phPipe.
+ */
+ if (fd == 0) /* stdin? */
+ {
+ /* Connect a wrtie pipe specified by phPipe to stdin. */
+ rc = RTPipeCreate(&ph->u.hPipe, phPipe, RTPIPE_C_INHERIT_READ);
+ }
+ else /* stdout or stderr? */
+ {
+ /* Connect a read pipe specified by phPipe to stdout or stderr. */
+ rc = RTPipeCreate(phPipe, &ph->u.hPipe, RTPIPE_C_INHERIT_WRITE);
+ }
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ ph->enmType = RTHANDLETYPE_PIPE;
+ *pph = ph;
+ }
+ else if (!strcmp(pszHowTo, "/dev/null"))
+ {
+ /*
+ * Redirect to/from /dev/null.
+ */
+ RTFILE hFile;
+ rc = RTFileOpenBitBucket(&hFile, fd == 0 ? RTFILE_O_READ : RTFILE_O_WRITE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ ph->enmType = RTHANDLETYPE_FILE;
+ ph->u.hFile = hFile;
+ *pph = ph;
+ }
+ else /* Add other piping stuff here. */
+ rc = VINF_SUCCESS; /* Same as parent (us). */
+
+ return rc;
+}
+
+
+/**
+ * Expands a file name / path to its real content. This only works on Windows
+ * for now (e.g. translating "%TEMP%\foo.exe" to "C:\Windows\Temp" when starting
+ * with system / administrative rights).
+ *
+ * @return IPRT status code.
+ * @param pszPath Path to resolve.
+ * @param pszExpanded Pointer to string to store the resolved path in.
+ * @param cbExpanded Size (in bytes) of string to store the resolved path.
+ */
+static int gstcntlProcessMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded)
+{
+ int rc = VINF_SUCCESS;
+#ifdef RT_OS_WINDOWS
+ if (!ExpandEnvironmentStrings(pszPath, pszExpanded, cbExpanded))
+ rc = RTErrConvertFromWin32(GetLastError());
+#else
+ /* No expansion for non-Windows yet. */
+ rc = RTStrCopy(pszExpanded, cbExpanded, pszPath);
+#endif
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "VBoxServiceControlExecMakeFullPath: %s -> %s\n",
+ pszPath, pszExpanded);
+#endif
+ return rc;
+}
+
+
+/**
+ * Resolves the full path of a specified executable name. This function also
+ * resolves internal VBoxService tools to its appropriate executable path + name if
+ * VBOXSERVICE_NAME is specified as pszFileName.
+ *
+ * @return IPRT status code.
+ * @param pszFileName File name to resolve.
+ * @param pszResolved Pointer to a string where the resolved file name will be stored.
+ * @param cbResolved Size (in bytes) of resolved file name string.
+ */
+static int gstcntlProcessResolveExecutable(const char *pszFileName,
+ char *pszResolved, size_t cbResolved)
+{
+ AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszResolved, VERR_INVALID_POINTER);
+ AssertReturn(cbResolved, VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+
+ char szPathToResolve[RTPATH_MAX];
+ if ( (g_pszProgName && (RTStrICmp(pszFileName, g_pszProgName) == 0))
+ || !RTStrICmp(pszFileName, VBOXSERVICE_NAME))
+ {
+ /* Resolve executable name of this process. */
+ if (!RTProcGetExecutablePath(szPathToResolve, sizeof(szPathToResolve)))
+ rc = VERR_FILE_NOT_FOUND;
+ }
+ else
+ {
+ /* Take the raw argument to resolve. */
+ rc = RTStrCopy(szPathToResolve, sizeof(szPathToResolve), pszFileName);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = gstcntlProcessMakeFullPath(szPathToResolve, pszResolved, cbResolved);
+ if (RT_SUCCESS(rc))
+ VBoxServiceVerbose(3, "Looked up executable: %s -> %s\n",
+ pszFileName, pszResolved);
+ }
+
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Failed to lookup executable \"%s\" with rc=%Rrc\n",
+ pszFileName, rc);
+ return rc;
+}
+
+
+/**
+ * Constructs the argv command line by resolving environment variables
+ * and relative paths.
+ *
+ * @return IPRT status code.
+ * @param pszArgv0 First argument (argv0), either original or modified version. Optional.
+ * @param papszArgs Original argv command line from the host, starting at argv[1].
+ * @param ppapszArgv Pointer to a pointer with the new argv command line.
+ * Needs to be freed with RTGetOptArgvFree.
+ */
+static int gstcntlProcessAllocateArgv(const char *pszArgv0,
+ const char * const *papszArgs,
+ bool fExpandArgs, char ***ppapszArgv)
+{
+ AssertPtrReturn(ppapszArgv, VERR_INVALID_POINTER);
+
+ VBoxServiceVerbose(3, "GstCntlProcessPrepareArgv: pszArgv0=%p, papszArgs=%p, fExpandArgs=%RTbool, ppapszArgv=%p\n",
+ pszArgv0, papszArgs, fExpandArgs, ppapszArgv);
+
+ int rc = VINF_SUCCESS;
+ uint32_t cArgs;
+ for (cArgs = 0; papszArgs[cArgs]; cArgs++)
+ {
+ if (cArgs >= UINT32_MAX - 2)
+ return VERR_BUFFER_OVERFLOW;
+ }
+
+ /* Allocate new argv vector (adding + 2 for argv0 + termination). */
+ size_t cbSize = (cArgs + 2) * sizeof(char*);
+ char **papszNewArgv = (char**)RTMemAlloc(cbSize);
+ if (!papszNewArgv)
+ return VERR_NO_MEMORY;
+
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "GstCntlProcessAllocateArgv: cbSize=%RU32, cArgs=%RU32\n",
+ cbSize, cArgs);
+#endif
+
+ size_t i = 0; /* Keep the argument counter in scope for cleaning up on failure. */
+
+ rc = RTStrDupEx(&papszNewArgv[0], pszArgv0);
+ if (RT_SUCCESS(rc))
+ {
+ for (; i < cArgs; i++)
+ {
+ char *pszArg;
+#if 0 /* Arguments expansion -- untested. */
+ if (fExpandArgs)
+ {
+ /* According to MSDN the limit on older Windows version is 32K, whereas
+ * Vista+ there are no limits anymore. We still stick to 4K. */
+ char szExpanded[_4K];
+# ifdef RT_OS_WINDOWS
+ if (!ExpandEnvironmentStrings(papszArgs[i], szExpanded, sizeof(szExpanded)))
+ rc = RTErrConvertFromWin32(GetLastError());
+# else
+ /* No expansion for non-Windows yet. */
+ rc = RTStrCopy(papszArgs[i], sizeof(szExpanded), szExpanded);
+# endif
+ if (RT_SUCCESS(rc))
+ rc = RTStrDupEx(&pszArg, szExpanded);
+ }
+ else
+#endif
+ rc = RTStrDupEx(&pszArg, papszArgs[i]);
+
+ if (RT_FAILURE(rc))
+ break;
+
+ papszNewArgv[i + 1] = pszArg;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Terminate array. */
+ papszNewArgv[cArgs + 1] = NULL;
+
+ *ppapszArgv = papszNewArgv;
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ for (i; i > 0; i--)
+ RTStrFree(papszNewArgv[i]);
+ RTMemFree(papszNewArgv);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Assigns a valid PID to a guest control thread and also checks if there already was
+ * another (stale) guest process which was using that PID before and destroys it.
+ *
+ * @return IPRT status code.
+ * @param pProcess Process to assign PID to.
+ * @param uPID PID to assign to the specified guest control execution thread.
+ */
+int gstcntlProcessAssignPID(PVBOXSERVICECTRLPROCESS pProcess, uint32_t uPID)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ AssertReturn(uPID, VERR_INVALID_PARAMETER);
+
+ AssertPtr(pProcess->pSession);
+ int rc = RTCritSectEnter(&pProcess->pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /* Search old threads using the desired PID and shut them down completely -- it's
+ * not used anymore. */
+ PVBOXSERVICECTRLPROCESS pProcessCur;
+ bool fTryAgain;
+ do
+ {
+ fTryAgain = false;
+ RTListForEach(&pProcess->pSession->lstProcesses, pProcessCur, VBOXSERVICECTRLPROCESS, Node)
+ {
+ if (pProcessCur->uPID == uPID)
+ {
+ Assert(pProcessCur != pProcess); /* can't happen */
+ uint32_t uTriedPID = uPID;
+ uPID += 391939;
+ VBoxServiceVerbose(2, "PID %RU32 was used before (process %p), trying again with %RU32 ...\n",
+ uTriedPID, pProcessCur, uPID);
+ fTryAgain = true;
+ break;
+ }
+ }
+ } while (fTryAgain);
+
+ /* Assign PID to current thread. */
+ pProcess->uPID = uPID;
+
+ rc = RTCritSectLeave(&pProcess->pSession->CritSect);
+ AssertRC(rc);
+ }
+
+ return rc;
+}
+
+
+void gstcntlProcessFreeArgv(char **papszArgv)
+{
+ if (papszArgv)
+ {
+ size_t i = 0;
+ while (papszArgv[i])
+ RTStrFree(papszArgv[i++]);
+ RTMemFree(papszArgv);
+ }
+}
+
+
+/**
+ * Helper function to create/start a process on the guest.
+ *
+ * @return IPRT status code.
+ * @param pszExec Full qualified path of process to start (without arguments).
+ * @param papszArgs Pointer to array of command line arguments.
+ * @param hEnv Handle to environment block to use.
+ * @param fFlags Process execution flags.
+ * @param phStdIn Handle for the process' stdin pipe.
+ * @param phStdOut Handle for the process' stdout pipe.
+ * @param phStdErr Handle for the process' stderr pipe.
+ * @param pszAsUser User name (account) to start the process under.
+ * @param pszPassword Password of the specified user.
+ * @param phProcess Pointer which will receive the process handle after
+ * successful process start.
+ */
+static int gstcntlProcessCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
+ PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
+ const char *pszPassword, PRTPROCESS phProcess)
+{
+ AssertPtrReturn(pszExec, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(phProcess, VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ char szExecExp[RTPATH_MAX];
+
+ /* Do we need to expand environment variables in arguments? */
+ bool fExpandArgs = (fFlags & EXECUTEPROCESSFLAG_EXPAND_ARGUMENTS) ? true : false;
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * If sysprep should be executed do this in the context of VBoxService, which
+ * (usually, if started by SCM) has administrator rights. Because of that a UI
+ * won't be shown (doesn't have a desktop).
+ */
+ if (!RTStrICmp(pszExec, "sysprep"))
+ {
+ /* Use a predefined sysprep path as default. */
+ char szSysprepCmd[RTPATH_MAX] = "C:\\sysprep\\sysprep.exe";
+ /** @todo Check digital signature of file above before executing it? */
+
+ /*
+ * On Windows Vista (and up) sysprep is located in "system32\\Sysprep\\sysprep.exe",
+ * so detect the OS and use a different path.
+ */
+ OSVERSIONINFOEX OSInfoEx;
+ RT_ZERO(OSInfoEx);
+ OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ BOOL fRet = GetVersionEx((LPOSVERSIONINFO) &OSInfoEx);
+ if ( fRet
+ && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && OSInfoEx.dwMajorVersion >= 6 /* Vista or later */)
+ {
+ rc = RTEnvGetEx(RTENV_DEFAULT, "windir", szSysprepCmd, sizeof(szSysprepCmd), NULL);
+#ifndef RT_ARCH_AMD64
+ /* Don't execute 64-bit sysprep from a 32-bit service host! */
+ char szSysWow64[RTPATH_MAX];
+ if (RTStrPrintf(szSysWow64, sizeof(szSysWow64), "%s", szSysprepCmd))
+ {
+ rc = RTPathAppend(szSysWow64, sizeof(szSysWow64), "SysWow64");
+ AssertRC(rc);
+ }
+ if ( RT_SUCCESS(rc)
+ && RTPathExists(szSysWow64))
+ VBoxServiceVerbose(0, "Warning: This service is 32-bit; could not execute sysprep on 64-bit OS!\n");
+#endif
+ if (RT_SUCCESS(rc))
+ rc = RTPathAppend(szSysprepCmd, sizeof(szSysprepCmd), "system32\\Sysprep\\sysprep.exe");
+ if (RT_SUCCESS(rc))
+ RTPathChangeToDosSlashes(szSysprepCmd, false /* No forcing necessary */);
+
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Failed to detect sysrep location, rc=%Rrc\n", rc);
+ }
+ else if (!fRet)
+ VBoxServiceError("Failed to retrieve OS information, last error=%ld\n", GetLastError());
+
+ VBoxServiceVerbose(3, "Sysprep executable is: %s\n", szSysprepCmd);
+
+ if (RT_SUCCESS(rc))
+ {
+ char **papszArgsExp;
+ rc = gstcntlProcessAllocateArgv(szSysprepCmd /* argv0 */, papszArgs,
+ fExpandArgs, &papszArgsExp);
+ if (RT_SUCCESS(rc))
+ {
+ /* As we don't specify credentials for the sysprep process, it will
+ * run under behalf of the account VBoxService was started under, most
+ * likely local system. */
+ rc = RTProcCreateEx(szSysprepCmd, papszArgsExp, hEnv, 0 /* fFlags */,
+ phStdIn, phStdOut, phStdErr, NULL /* pszAsUser */,
+ NULL /* pszPassword */, phProcess);
+ gstcntlProcessFreeArgv(papszArgsExp);
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ VBoxServiceVerbose(3, "Starting sysprep returned rc=%Rrc\n", rc);
+
+ return rc;
+ }
+#endif /* RT_OS_WINDOWS */
+
+#ifdef VBOXSERVICE_TOOLBOX
+ if (RTStrStr(pszExec, "vbox_") == pszExec)
+ {
+ /* We want to use the internal toolbox (all internal
+ * tools are starting with "vbox_" (e.g. "vbox_cat"). */
+ rc = gstcntlProcessResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp));
+ }
+ else
+ {
+#endif
+ /*
+ * Do the environment variables expansion on executable and arguments.
+ */
+ rc = gstcntlProcessResolveExecutable(pszExec, szExecExp, sizeof(szExecExp));
+#ifdef VBOXSERVICE_TOOLBOX
+ }
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ char **papszArgsExp;
+ rc = gstcntlProcessAllocateArgv(pszExec /* Always use the unmodified executable name as argv0. */,
+ papszArgs /* Append the rest of the argument vector (if any). */,
+ fExpandArgs, &papszArgsExp);
+ if (RT_FAILURE(rc))
+ {
+ /* Don't print any arguments -- may contain passwords or other sensible data! */
+ VBoxServiceError("Could not prepare arguments, rc=%Rrc\n", rc);
+ }
+ else
+ {
+ uint32_t uProcFlags = 0;
+ if (fFlags)
+ {
+ if (fFlags & EXECUTEPROCESSFLAG_HIDDEN)
+ uProcFlags |= RTPROC_FLAGS_HIDDEN;
+ if (fFlags & EXECUTEPROCESSFLAG_NO_PROFILE)
+ uProcFlags |= RTPROC_FLAGS_NO_PROFILE;
+ }
+
+ /* If no user name specified run with current credentials (e.g.
+ * full service/system rights). This is prohibited via official Main API!
+ *
+ * Otherwise use the RTPROC_FLAGS_SERVICE to use some special authentication
+ * code (at least on Windows) for running processes as different users
+ * started from our system service. */
+ if (pszAsUser && *pszAsUser)
+ uProcFlags |= RTPROC_FLAGS_SERVICE;
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "Command: %s\n", szExecExp);
+ for (size_t i = 0; papszArgsExp[i]; i++)
+ VBoxServiceVerbose(3, "\targv[%ld]: %s\n", i, papszArgsExp[i]);
+#endif
+ VBoxServiceVerbose(3, "Starting process \"%s\" ...\n", szExecExp);
+
+ /* Do normal execution. */
+ rc = RTProcCreateEx(szExecExp, papszArgsExp, hEnv, uProcFlags,
+ phStdIn, phStdOut, phStdErr,
+ pszAsUser && *pszAsUser ? pszAsUser : NULL,
+ pszPassword && *pszPassword ? pszPassword : NULL,
+ phProcess);
+
+ VBoxServiceVerbose(3, "Starting process \"%s\" returned rc=%Rrc\n",
+ szExecExp, rc);
+
+ gstcntlProcessFreeArgv(papszArgsExp);
+ }
+ }
+ return rc;
+}
+
+
+#ifdef DEBUG
+static int gstcntlProcessDumpToFile(const char *pszFileName, void *pvBuf, size_t cbBuf)
+{
+ AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+
+ if (!cbBuf)
+ return VINF_SUCCESS;
+
+ char szFile[RTPATH_MAX];
+
+ int rc = RTPathTemp(szFile, sizeof(szFile));
+ if (RT_SUCCESS(rc))
+ rc = RTPathAppend(szFile, sizeof(szFile), pszFileName);
+
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(4, "Dumping %ld bytes to \"%s\"\n", cbBuf, szFile);
+
+ RTFILE fh;
+ rc = RTFileOpen(&fh, szFile, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTFileWrite(fh, pvBuf, cbBuf, NULL /* pcbWritten */);
+ RTFileClose(fh);
+ }
+ }
+
+ return rc;
+}
+#endif
+
+
+/**
+ * The actual worker routine (loop) for a started guest process.
+ *
+ * @return IPRT status code.
+ * @param PVBOXSERVICECTRLPROCESS Guest process.
+ */
+static int gstcntlProcessProcessWorker(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ VBoxServiceVerbose(3, "Thread of process pThread=0x%p = \"%s\" started\n",
+ pProcess, pProcess->StartupInfo.szCmd);
+
+ int rc = VbglR3GuestCtrlConnect(&pProcess->uClientID);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Process thread \"%s\" (%p) failed to connect to the guest control service, rc=%Rrc\n",
+ pProcess->StartupInfo.szCmd, pProcess, rc);
+ RTThreadUserSignal(RTThreadSelf());
+ return rc;
+ }
+
+ VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n",
+ pProcess->StartupInfo.szCmd, pProcess->uClientID, pProcess->StartupInfo.uFlags);
+
+ /* The process thread is not interested in receiving any commands;
+ * tell the host service. */
+ rc = VbglR3GuestCtrlMsgFilterSet(pProcess->uClientID, 0 /* Skip all */,
+ 0 /* Filter mask to add */, 0 /* Filter mask to remove */);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Unable to set message filter, rc=%Rrc\n", rc);
+ /* Non-critical. */
+ }
+
+ rc = GstCntlSessionProcessAdd(pProcess->pSession, pProcess);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Errorwhile adding guest process \"%s\" (%p) to session process list, rc=%Rrc\n",
+ pProcess->StartupInfo.szCmd, pProcess, rc);
+ RTThreadUserSignal(RTThreadSelf());
+ return rc;
+ }
+
+ bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */
+
+ /*
+ * Prepare argument list.
+ */
+ char **papszArgs;
+ uint32_t uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
+ rc = RTGetOptArgvFromString(&papszArgs, (int*)&uNumArgs,
+ (pProcess->StartupInfo.uNumArgs > 0) ? pProcess->StartupInfo.szArgs : "", NULL);
+ /* Did we get the same result? */
+ Assert(pProcess->StartupInfo.uNumArgs == uNumArgs);
+
+ /*
+ * Prepare environment variables list.
+ */
+ char **papszEnv = NULL;
+ uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */
+ if (RT_SUCCESS(rc))
+ {
+ /* Prepare environment list. */
+ if (pProcess->StartupInfo.uNumEnvVars)
+ {
+ papszEnv = (char **)RTMemAlloc(pProcess->StartupInfo.uNumEnvVars * sizeof(char*));
+ AssertPtr(papszEnv);
+ uNumEnvVars = pProcess->StartupInfo.uNumEnvVars;
+
+ const char *pszCur = pProcess->StartupInfo.szEnv;
+ uint32_t i = 0;
+ uint32_t cbLen = 0;
+ while (cbLen < pProcess->StartupInfo.cbEnv)
+ {
+ /* sanity check */
+ if (i >= pProcess->StartupInfo.uNumEnvVars)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ int cbStr = RTStrAPrintf(&papszEnv[i++], "%s", pszCur);
+ if (cbStr < 0)
+ {
+ rc = VERR_NO_STR_MEMORY;
+ break;
+ }
+ pszCur += cbStr + 1; /* Skip terminating '\0' */
+ cbLen += cbStr + 1; /* Skip terminating '\0' */
+ }
+ Assert(i == pProcess->StartupInfo.uNumEnvVars);
+ }
+ }
+
+ /*
+ * Create the environment.
+ */
+ RTENV hEnv;
+ if (RT_SUCCESS(rc))
+ rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
+ if (RT_SUCCESS(rc))
+ {
+ size_t i;
+ for (i = 0; i < uNumEnvVars && papszEnv; i++)
+ {
+ rc = RTEnvPutEx(hEnv, papszEnv[i]);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Setup the redirection of the standard stuff.
+ */
+ /** @todo consider supporting: gcc stuff.c >file 2>&1. */
+ RTHANDLE hStdIn;
+ PRTHANDLE phStdIn;
+ rc = gstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
+ &hStdIn, &phStdIn, &pProcess->hPipeStdInW);
+ if (RT_SUCCESS(rc))
+ {
+ RTHANDLE hStdOut;
+ PRTHANDLE phStdOut;
+ rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
+ ? "|" : "/dev/null",
+ 1 /*STDOUT_FILENO*/,
+ &hStdOut, &phStdOut, &pProcess->hPipeStdOutR);
+ if (RT_SUCCESS(rc))
+ {
+ RTHANDLE hStdErr;
+ PRTHANDLE phStdErr;
+ rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
+ ? "|" : "/dev/null",
+ 2 /*STDERR_FILENO*/,
+ &hStdErr, &phStdErr, &pProcess->hPipeStdErrR);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create a poll set for the pipes and let the
+ * transport layer add stuff to it as well.
+ */
+ rc = RTPollSetCreate(&pProcess->hPollSet);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t uFlags = RTPOLL_EVT_ERROR;
+#if 0
+ /* Add reading event to pollset to get some more information. */
+ uFlags |= RTPOLL_EVT_READ;
+#endif
+ /* Stdin. */
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pProcess->hPollSet,
+ pProcess->hPipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN);
+ /* Stdout. */
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pProcess->hPollSet,
+ pProcess->hPipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
+ /* Stderr. */
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pProcess->hPollSet,
+ pProcess->hPipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
+ /* IPC notification pipe. */
+ if (RT_SUCCESS(rc))
+ rc = RTPipeCreate(&pProcess->hNotificationPipeR, &pProcess->hNotificationPipeW, 0 /* Flags */);
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pProcess->hPollSet,
+ pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);
+ if (RT_SUCCESS(rc))
+ {
+ AssertPtr(pProcess->pSession);
+ bool fNeedsImpersonation = !(pProcess->pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_FORK);
+
+ rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags,
+ phStdIn, phStdOut, phStdErr,
+ fNeedsImpersonation ? pProcess->StartupInfo.szUser : NULL,
+ fNeedsImpersonation ? pProcess->StartupInfo.szPassword : NULL,
+ &pProcess->hProcess);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error starting process, rc=%Rrc\n", rc);
+ /*
+ * Tell the session thread that it can continue
+ * spawning guest processes. This needs to be done after the new
+ * process has been started because otherwise signal handling
+ * on (Open) Solaris does not work correctly (see @bugref{5068}).
+ */
+ int rc2 = RTThreadUserSignal(RTThreadSelf());
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ fSignalled = true;
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Close the child ends of any pipes and redirected files.
+ */
+ rc2 = RTHandleClose(phStdIn); AssertRC(rc2);
+ phStdIn = NULL;
+ rc2 = RTHandleClose(phStdOut); AssertRC(rc2);
+ phStdOut = NULL;
+ rc2 = RTHandleClose(phStdErr); AssertRC(rc2);
+ phStdErr = NULL;
+
+ /* Enter the process main loop. */
+ rc = gstcntlProcessProcLoop(pProcess);
+
+ /*
+ * The handles that are no longer in the set have
+ * been closed by the above call in order to prevent
+ * the guest from getting stuck accessing them.
+ * So, NIL the handles to avoid closing them again.
+ */
+ if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
+ VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL)))
+ {
+ pProcess->hNotificationPipeR = NIL_RTPIPE;
+ pProcess->hNotificationPipeW = NIL_RTPIPE;
+ }
+ if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
+ VBOXSERVICECTRLPIPEID_STDERR, NULL)))
+ pProcess->hPipeStdErrR = NIL_RTPIPE;
+ if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
+ VBOXSERVICECTRLPIPEID_STDOUT, NULL)))
+ pProcess->hPipeStdOutR = NIL_RTPIPE;
+ if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
+ VBOXSERVICECTRLPIPEID_STDIN, NULL)))
+ pProcess->hPipeStdInW = NIL_RTPIPE;
+ }
+ }
+ RTPollSetDestroy(pProcess->hPollSet);
+
+ RTPipeClose(pProcess->hNotificationPipeR);
+ pProcess->hNotificationPipeR = NIL_RTPIPE;
+ RTPipeClose(pProcess->hNotificationPipeW);
+ pProcess->hNotificationPipeW = NIL_RTPIPE;
+ }
+ RTPipeClose(pProcess->hPipeStdErrR);
+ pProcess->hPipeStdErrR = NIL_RTPIPE;
+ RTHandleClose(phStdErr);
+ if (phStdErr)
+ RTHandleClose(phStdErr);
+ }
+ RTPipeClose(pProcess->hPipeStdOutR);
+ pProcess->hPipeStdOutR = NIL_RTPIPE;
+ RTHandleClose(&hStdOut);
+ if (phStdOut)
+ RTHandleClose(phStdOut);
+ }
+ RTPipeClose(pProcess->hPipeStdInW);
+ pProcess->hPipeStdInW = NIL_RTPIPE;
+ RTHandleClose(phStdIn);
+ }
+ }
+ RTEnvDestroy(hEnv);
+ }
+
+ if (pProcess->uClientID)
+ {
+ if (RT_FAILURE(rc))
+ {
+ VBGLR3GUESTCTRLCMDCTX ctx = { pProcess->uClientID, pProcess->uContextID };
+ int rc2 = VbglR3GuestCtrlProcCbStatus(&ctx,
+ pProcess->uPID, PROC_STS_ERROR, rc,
+ NULL /* pvData */, 0 /* cbData */);
+ if ( RT_FAILURE(rc2)
+ && rc2 != VERR_NOT_FOUND)
+ VBoxServiceError("[PID %RU32]: Could not report process failure error; rc=%Rrc (process error %Rrc)\n",
+ pProcess->uPID, rc2, rc);
+ }
+
+ /* Disconnect this client from the guest control service. This also cancels all
+ * outstanding host requests. */
+ VBoxServiceVerbose(3, "[PID %RU32]: Disconnecting (client ID=%u) ...\n",
+ pProcess->uPID, pProcess->uClientID);
+ VbglR3GuestCtrlDisconnect(pProcess->uClientID);
+ pProcess->uClientID = 0;
+ }
+
+ /* Free argument + environment variable lists. */
+ if (uNumEnvVars)
+ {
+ for (uint32_t i = 0; i < uNumEnvVars; i++)
+ RTStrFree(papszEnv[i]);
+ RTMemFree(papszEnv);
+ }
+ if (uNumArgs)
+ RTGetOptArgvFree(papszArgs);
+
+ /*
+ * If something went wrong signal the user event so that others don't wait
+ * forever on this thread.
+ */
+ if (RT_FAILURE(rc) && !fSignalled)
+ RTThreadUserSignal(RTThreadSelf());
+
+ VBoxServiceVerbose(3, "[PID %RU32]: Thread of process \"%s\" ended with rc=%Rrc\n",
+ pProcess->uPID, pProcess->StartupInfo.szCmd, rc);
+
+ /* Finally, update stopped status. */
+ ASMAtomicXchgBool(&pProcess->fStopped, true);
+
+ return rc;
+}
+
+
+static int gstcntlProcessLock(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ int rc = RTCritSectEnter(&pProcess->CritSect);
+ AssertRC(rc);
+ return rc;
+}
+
+
+/**
+ * Thread main routine for a started process.
+ *
+ * @return IPRT status code.
+ * @param RTTHREAD Pointer to the thread's data.
+ * @param void* User-supplied argument pointer.
+ *
+ */
+static DECLCALLBACK(int) gstcntlProcessThread(RTTHREAD ThreadSelf, void *pvUser)
+{
+ PVBOXSERVICECTRLPROCESS pProcess = (VBOXSERVICECTRLPROCESS*)pvUser;
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ return gstcntlProcessProcessWorker(pProcess);
+}
+
+
+static int gstcntlProcessUnlock(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ int rc = RTCritSectLeave(&pProcess->CritSect);
+ AssertRC(rc);
+ return rc;
+}
+
+
+/**
+ * Executes (starts) a process on the guest. This causes a new thread to be created
+ * so that this function will not block the overall program execution.
+ *
+ * @return IPRT status code.
+ * @param pSession Guest session.
+ * @param pStartupInfo Startup info.
+ * @param uContextID Context ID to associate the process to start with.
+
+ */
+int GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession,
+ const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo,
+ uint32_t uContextID)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStartupInfo, VERR_INVALID_POINTER);
+
+ /*
+ * Allocate new thread data and assign it to our thread list.
+ */
+ PVBOXSERVICECTRLPROCESS pProcess = (PVBOXSERVICECTRLPROCESS)RTMemAlloc(sizeof(VBOXSERVICECTRLPROCESS));
+ if (!pProcess)
+ return VERR_NO_MEMORY;
+
+ int rc = gstcntlProcessInit(pProcess, pSession, pStartupInfo, uContextID);
+ if (RT_SUCCESS(rc))
+ {
+ static uint32_t s_uCtrlExecThread = 0;
+ if (s_uCtrlExecThread++ == UINT32_MAX)
+ s_uCtrlExecThread = 0; /* Wrap around to not let IPRT freak out. */
+ rc = RTThreadCreateF(&pProcess->Thread, gstcntlProcessThread,
+ pProcess /*pvUser*/, 0 /*cbStack*/,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "gctl%u", s_uCtrlExecThread);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Creating thread for guest process \"%s\" failed: rc=%Rrc, pProcess=%p\n",
+ pStartupInfo->szCmd, rc, pProcess);
+
+ GstCntlProcessFree(pProcess);
+ }
+ else
+ {
+ VBoxServiceVerbose(4, "Waiting for thread to initialize ...\n");
+
+ /* Wait for the thread to initialize. */
+ rc = RTThreadUserWait(pProcess->Thread, 60 * 1000 /* 60 seconds max. */);
+ AssertRC(rc);
+ if ( ASMAtomicReadBool(&pProcess->fShutdown)
+ || RT_FAILURE(rc))
+ {
+ VBoxServiceError("Thread for process \"%s\" failed to start, rc=%Rrc\n",
+ pStartupInfo->szCmd, rc);
+
+ GstCntlProcessFree(pProcess);
+ }
+ else
+ {
+ ASMAtomicXchgBool(&pProcess->fStarted, true);
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+static DECLCALLBACK(int) gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis,
+ const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ bool fPendingClose, void *pvBuf, uint32_t cbBuf)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ int rc;
+
+ size_t cbWritten = 0;
+ if (pvBuf && cbBuf)
+ {
+ if (pThis->hPipeStdInW != NIL_RTPIPE)
+ {
+ rc = RTPipeWrite(pThis->hPipeStdInW,
+ pvBuf, cbBuf, &cbWritten);
+ }
+ else
+ rc = VINF_EOF;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ /*
+ * If this is the last write + we have really have written all data
+ * we need to close the stdin pipe on our end and remove it from
+ * the poll set.
+ */
+ if ( fPendingClose
+ && (cbBuf == cbWritten))
+ {
+ int rc2 = gstcntlProcessPollsetCloseInput(pThis, &pThis->hPipeStdInW);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status to send back to the host. */
+ uint32_t uFlags = 0; /* No flags at the moment. */
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(4, "[PID %RU32]: Written %RU32 bytes input, CID=%RU32, fPendingClose=%RTbool\n",
+ pThis->uPID, cbWritten, pHostCtx->uContextID, fPendingClose);
+ uStatus = INPUT_STS_WRITTEN;
+ }
+ else
+ {
+ if (rc == VERR_BAD_PIPE)
+ uStatus = INPUT_STS_TERMINATED;
+ else if (rc == VERR_BUFFER_OVERFLOW)
+ uStatus = INPUT_STS_OVERFLOW;
+ /* else undefined */
+ }
+
+ /*
+ * If there was an error and we did not set the host status
+ * yet, then do it now.
+ */
+ if ( RT_FAILURE(rc)
+ && uStatus == INPUT_STS_UNDEFINED)
+ {
+ uStatus = INPUT_STS_ERROR;
+ uFlags = rc;
+ }
+ Assert(uStatus > INPUT_STS_UNDEFINED);
+
+#ifdef DEBUG
+
+#endif
+ int rc2 = VbglR3GuestCtrlProcCbStatusInput(pHostCtx, pThis->uPID,
+ uStatus, uFlags, (uint32_t)cbWritten);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessOnInput returned with rc=%Rrc\n",
+ pThis->uPID, rc);
+#endif
+ return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
+}
+
+
+static DECLCALLBACK(int) gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis,
+ const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ const PVBOXSERVICECTRLSESSION pSession = pThis->pSession;
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+
+ int rc;
+
+ uint32_t cbBuf = cbToRead;
+ uint8_t *pvBuf = (uint8_t *)RTMemAlloc(cbBuf);
+ if (pvBuf)
+ {
+ PRTPIPE phPipe = uHandle == OUTPUT_HANDLE_ID_STDOUT
+ ? &pThis->hPipeStdOutR
+ : &pThis->hPipeStdErrR;
+ AssertPtr(phPipe);
+
+ size_t cbRead = 0;
+ if (*phPipe != NIL_RTPIPE)
+ {
+ rc = RTPipeRead(*phPipe, pvBuf, cbBuf, &cbRead);
+ if (RT_FAILURE(rc))
+ {
+ RTPollSetRemove(pThis->hPollSet, uHandle == OUTPUT_HANDLE_ID_STDERR
+ ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT);
+ RTPipeClose(*phPipe);
+ *phPipe = NIL_RTPIPE;
+ if (rc == VERR_BROKEN_PIPE)
+ rc = VINF_EOF;
+ }
+ }
+ else
+ rc = VINF_EOF;
+
+#ifdef DEBUG
+ if (RT_SUCCESS(rc))
+ {
+ if ( pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT
+ && ( uHandle == OUTPUT_HANDLE_ID_STDOUT
+ || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)
+ )
+ {
+ char szDumpFile[RTPATH_MAX];
+ if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt",
+ pSession->StartupInfo.uSessionID, pThis->uPID)) rc = VERR_BUFFER_UNDERFLOW;
+ if (RT_SUCCESS(rc))
+ rc = gstcntlProcessDumpToFile(szDumpFile, pvBuf, cbRead);
+ AssertRC(rc);
+ }
+ else if ( pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR
+ && uHandle == OUTPUT_HANDLE_ID_STDERR)
+ {
+ char szDumpFile[RTPATH_MAX];
+ if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt",
+ pSession->StartupInfo.uSessionID, pThis->uPID))
+ rc = VERR_BUFFER_UNDERFLOW;
+ if (RT_SUCCESS(rc))
+ rc = gstcntlProcessDumpToFile(szDumpFile, pvBuf, cbRead);
+ AssertRC(rc);
+ }
+ }
+#endif
+
+ if (RT_SUCCESS(rc))
+ {
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: Read %RU32 bytes output: uHandle=%RU32, CID=%RU32, uFlags=%x\n",
+ pThis->uPID, cbRead, uHandle, pHostCtx->uContextID, uFlags);
+#endif
+ /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
+ * data which the host needs to work with -- so just pass through all data unfiltered! */
+
+ /* Note: Since the context ID is unique the request *has* to be completed here,
+ * regardless whether we got data or not! Otherwise the waiting events
+ * on the host never will get completed! */
+ rc = VbglR3GuestCtrlProcCbOutput(pHostCtx, pThis->uPID, uHandle, uFlags,
+ pvBuf, cbRead);
+ if ( RT_FAILURE(rc)
+ && rc == VERR_NOT_FOUND) /* Not critical if guest PID is not found on the host (anymore). */
+ rc = VINF_SUCCESS;
+ }
+
+ RTMemFree(pvBuf);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: Reading output returned with rc=%Rrc\n",
+ pThis->uPID, rc);
+#endif
+ return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
+}
+
+
+static DECLCALLBACK(int) gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+ if (!ASMAtomicXchgBool(&pThis->fShutdown, true))
+ {
+ VBoxServiceVerbose(3, "[PID %RU32]: Setting shutdown flag ...\n",
+ pThis->uPID);
+ }
+
+ return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
+}
+
+
+int gstcntlProcessRequestExV(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ bool fAsync, RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction,
+ unsigned cArgs, va_list Args)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ /* pHostCtx is optional. */
+ AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
+ if (!fAsync)
+ AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
+
+ int rc = gstcntlProcessLock(pProcess);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV fAsync=%RTbool, uTimeoutMS=%RU32, cArgs=%u\n",
+ pProcess->uPID, fAsync, uTimeoutMS, cArgs);
+#endif
+ uint32_t uFlags = RTREQFLAGS_IPRT_STATUS;
+ if (fAsync)
+ {
+ Assert(uTimeoutMS == 0);
+ uFlags |= RTREQFLAGS_NO_WAIT;
+ }
+
+ rc = RTReqQueueCallV(pProcess->hReqQueue, &pReq, uTimeoutMS, uFlags,
+ pfnFunction, cArgs, Args);
+ if (RT_SUCCESS(rc))
+ {
+ /* Wake up the process' notification pipe to get
+ * the request being processed. */
+ Assert(pProcess->hNotificationPipeW != NIL_RTPIPE);
+ size_t cbWritten = 0;
+ rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten);
+ if ( RT_SUCCESS(rc)
+ && cbWritten != 1)
+ {
+ VBoxServiceError("[PID %RU32]: Notification pipe got %zu bytes instead of 1\n",
+ pProcess->uPID, cbWritten);
+ }
+ else if (RT_UNLIKELY(RT_FAILURE(rc)))
+ VBoxServiceError("[PID %RU32]: Writing to notification pipe failed, rc=%Rrc\n",
+ pProcess->uPID, rc);
+ }
+ else
+ VBoxServiceError("[PID %RU32]: RTReqQueueCallV failed, rc=%Rrc\n",
+ pProcess->uPID, rc);
+
+ int rc2 = gstcntlProcessUnlock(pProcess);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV returned rc=%Rrc\n",
+ pProcess->uPID, rc);
+#endif
+ return rc;
+}
+
+
+int gstcntlProcessRequestAsync(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ PFNRT pfnFunction, unsigned cArgs, ...)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ /* pHostCtx is optional. */
+ AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
+
+ va_list va;
+ va_start(va, cArgs);
+ int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, true /* fAsync */, 0 /* uTimeoutMS */,
+ NULL /* pReq */, pfnFunction, cArgs, va);
+ va_end(va);
+
+ return rc;
+}
+
+
+int gstcntlProcessRequestWait(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+ /* pHostCtx is optional. */
+ AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
+
+ va_list va;
+ va_start(va, cArgs);
+ int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, false /* fAsync */, uTimeoutMS,
+ pReq, pfnFunction, cArgs, va);
+ va_end(va);
+
+ return rc;
+}
+
+
+int GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ bool fPendingClose, void *pvBuf, uint32_t cbBuf)
+{
+ if (!ASMAtomicReadBool(&pProcess->fShutdown))
+ return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnInput,
+ 5 /* cArgs */, pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf);
+
+ return gstcntlProcessOnInput(pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf);
+}
+
+
+int GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags)
+{
+ if (!ASMAtomicReadBool(&pProcess->fShutdown))
+ return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnOutput,
+ 5 /* cArgs */, pProcess, pHostCtx, uHandle, cbToRead, uFlags);
+
+ return gstcntlProcessOnOutput(pProcess, pHostCtx, uHandle, cbToRead, uFlags);
+}
+
+
+int GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess)
+{
+ if (!ASMAtomicReadBool(&pProcess->fShutdown))
+ return gstcntlProcessRequestAsync(pProcess, NULL /* pHostCtx */, (PFNRT)gstcntlProcessOnTerm,
+ 1 /* cArgs */, pProcess);
+
+ return gstcntlProcessOnTerm(pProcess);
+}
+
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
new file mode 100644
index 00000000..d96b13ad
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
@@ -0,0 +1,2364 @@
+/* $Id: VBoxServiceControlSession.cpp $ */
+/** @file
+ * VBoxServiceControlSession - Guest session handling. Also handles
+ * the forked session processes.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/dir.h>
+#include <iprt/env.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/handle.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/pipe.h>
+#include <iprt/poll.h>
+#include <iprt/process.h>
+
+#include "VBoxServiceInternal.h"
+#include "VBoxServiceUtils.h"
+#include "VBoxServiceControl.h"
+
+using namespace guestControl;
+
+/*******************************************************************************
+* Externals *
+*******************************************************************************/
+extern RTLISTANCHOR g_lstControlSessionThreads;
+extern VBOXSERVICECTRLSESSION g_Session;
+
+extern int VBoxServiceLogCreate(const char *pszLogFile);
+extern void VBoxServiceLogDestroy(void);
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile);
+static int gstcntlSessionFileAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLFILE pFile);
+static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle);
+static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser);
+/* Host -> Guest handlers. */
+static int gstcntlSessionHandleDirRemove(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
+static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandlePathRename(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
+static int gstcntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+static int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
+
+
+/** Generic option indices for session fork arguments. */
+enum
+{
+ VBOXSERVICESESSIONOPT_FIRST = 1000, /* For initialization. */
+#ifdef DEBUG
+ VBOXSERVICESESSIONOPT_DUMP_STDOUT,
+ VBOXSERVICESESSIONOPT_DUMP_STDERR,
+#endif
+ VBOXSERVICESESSIONOPT_LOG_FILE,
+ VBOXSERVICESESSIONOPT_USERNAME,
+ VBOXSERVICESESSIONOPT_SESSION_ID,
+ VBOXSERVICESESSIONOPT_SESSION_PROTO,
+ VBOXSERVICESESSIONOPT_THREAD_ID
+};
+
+
+static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile)
+{
+ AssertPtrReturn(pFile, VERR_INVALID_POINTER);
+
+ int rc = RTFileClose(pFile->hFile);
+ if (RT_SUCCESS(rc))
+ {
+ /* Remove file entry in any case. */
+ RTListNodeRemove(&pFile->Node);
+ /* Destroy this object. */
+ RTMemFree(pFile);
+ }
+
+ return rc;
+}
+
+
+/** @todo No locking done yet! */
+static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession,
+ uint32_t uHandle)
+{
+ AssertPtrReturn(pSession, NULL);
+
+ PVBOXSERVICECTRLFILE pFileCur = NULL;
+ /** @todo Use a map later! */
+ RTListForEach(&pSession->lstFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
+ {
+ if (pFileCur->uHandle == uHandle)
+ return pFileCur;
+ }
+
+ return NULL;
+}
+
+
+static int gstcntlSessionHandleDirRemove(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ char szDir[RTPATH_MAX];
+ uint32_t uFlags = 0;
+
+ int rc = VbglR3GuestCtrlDirGetRemove(pHostCtx,
+ /* Directory to remove. */
+ szDir, sizeof(szDir),
+ /* Flags of type DIRREMOVE_FLAG_. */
+ &uFlags);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t uFlagsRemRec = 0;
+ bool fRecursive = false;
+
+ if (!(uFlags & ~DIRREMOVE_FLAG_VALID_MASK))
+ {
+ if (uFlags & DIRREMOVE_FLAG_RECURSIVE)
+ {
+ /* Note: DIRREMOVE_FLAG_RECURSIVE must be set explicitly.
+ * Play safe here. */
+ fRecursive = true;
+ }
+
+ if (uFlags & DIRREMOVE_FLAG_CONTENT_AND_DIR)
+ {
+ /* Setting direct value is intentional. */
+ uFlagsRemRec = RTDIRRMREC_F_CONTENT_AND_DIR;
+ }
+
+ if (uFlags & DIRREMOVE_FLAG_CONTENT_ONLY)
+ {
+ /* Setting direct value is intentional. */
+ uFlagsRemRec |= RTDIRRMREC_F_CONTENT_ONLY;
+ }
+ }
+ else
+ rc = VERR_NOT_SUPPORTED;
+
+ VBoxServiceVerbose(4, "[Dir %s]: Removing with uFlags=0x%x, fRecursive=%RTbool\n",
+ szDir, uFlags, fRecursive);
+
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo Add own recursive function (or a new IPRT function w/ callback?) to
+ * provide guest-to-host progress reporting. */
+ if (fRecursive)
+ rc = RTDirRemoveRecursive(szDir, uFlagsRemRec);
+ else
+ rc = RTDirRemove(szDir);
+ }
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("[Dir %s]: Failed to report removing status, rc=%Rrc\n",
+ szDir, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Removing directory \"%s\" returned rc=%Rrc\n",
+ szDir, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ char szFile[RTPATH_MAX];
+ char szAccess[64];
+ char szDisposition[64];
+ char szSharing[64];
+ uint32_t uCreationMode = 0;
+ uint64_t uOffset = 0;
+ uint32_t uHandle = 0;
+
+ int rc = VbglR3GuestCtrlFileGetOpen(pHostCtx,
+ /* File to open. */
+ szFile, sizeof(szFile),
+ /* Open mode. */
+ szAccess, sizeof(szAccess),
+ /* Disposition. */
+ szDisposition, sizeof(szDisposition),
+ /* Sharing. */
+ szSharing, sizeof(szSharing),
+ /* Creation mode. */
+ &uCreationMode,
+ /* Offset. */
+ &uOffset);
+ VBoxServiceVerbose(4, "[File %s]: szAccess=%s, szDisposition=%s, szSharing=%s, uOffset=%RU64, rc=%Rrc\n",
+ szFile, szAccess, szDisposition, szSharing, uOffset, rc);
+
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLFILE pFile = (PVBOXSERVICECTRLFILE)RTMemAllocZ(sizeof(VBOXSERVICECTRLFILE));
+ if (pFile)
+ {
+ if (!strlen(szFile))
+ rc = VERR_INVALID_PARAMETER;
+
+ if ( RT_SUCCESS(rc)
+ && !RTStrPrintf(pFile->szName, sizeof(pFile->szName), "%s", szFile))
+ rc = VERR_NO_MEMORY;
+
+ if (RT_SUCCESS(rc))
+ {
+ uint64_t fFlags;
+ rc = RTFileModeToFlagsEx(szAccess, szDisposition,
+ NULL /* pszSharing, not used yet */, &fFlags);
+ VBoxServiceVerbose(4, "[File %s]: Opening flags=0x%x, rc=%Rrc\n",
+ pFile->szName, fFlags, rc);
+ if (RT_SUCCESS(rc))
+ rc = RTFileOpen(&pFile->hFile, pFile->szName, fFlags);
+ if ( RT_SUCCESS(rc)
+ && uOffset)
+ {
+ /* Seeking is optional. However, the whole operation
+ * will fail if we don't succeed seeking to the wanted position. */
+ rc = RTFileSeek(pFile->hFile, (int64_t)uOffset, RTFILE_SEEK_BEGIN, NULL /* Current offset */);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("[File %s]: Seeking to offset %RU64 failed; rc=%Rrc\n",
+ pFile->szName, uOffset, rc);
+ }
+ else if (RT_FAILURE(rc))
+ VBoxServiceError("[File %s]: Opening failed; rc=%Rrc\n",
+ pFile->szName, rc);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
+ pFile->uHandle = uHandle;
+
+ /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node);
+
+ VBoxServiceVerbose(3, "[File %s]: Opened (ID=%RU32)\n",
+ pFile->szName, pFile->uHandle);
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ if (pFile->hFile)
+ RTFileClose(pFile->hFile);
+ RTMemFree(pFile);
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbOpen(pHostCtx, rc, uHandle);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("[File %s]: Failed to report file open status, rc=%Rrc\n",
+ szFile, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Opening file \"%s\" (open mode=\"%s\", disposition=\"%s\", creation mode=0x%x returned rc=%Rrc\n",
+ szFile, szAccess, szDisposition, uCreationMode, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ int rc = VbglR3GuestCtrlFileGetClose(pHostCtx, &uHandle /* File handle to close */);
+ if (RT_SUCCESS(rc))
+ {
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ rc = gstcntlSessionFileDestroy(pFile);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbClose(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file close status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Closing file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint32_t cbToRead;
+ int rc = VbglR3GuestCtrlFileGetRead(pHostCtx, &uHandle, &cbToRead);
+ if (RT_SUCCESS(rc))
+ {
+ void *pvDataRead = pvScratchBuf;
+ size_t cbRead = 0;
+
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ if (cbToRead)
+ {
+ if (cbToRead > cbScratchBuf)
+ {
+ pvDataRead = RTMemAlloc(cbToRead);
+ if (!pvDataRead)
+ rc = VERR_NO_MEMORY;
+ }
+
+ if (RT_LIKELY(RT_SUCCESS(rc)))
+ rc = RTFileRead(pFile->hFile, pvDataRead, cbToRead, &cbRead);
+ }
+ else
+ rc = VERR_BUFFER_UNDERFLOW;
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbRead(pHostCtx, rc, pvDataRead, (uint32_t)cbRead);
+ if ( cbToRead > cbScratchBuf
+ && pvDataRead)
+ RTMemFree(pvDataRead);
+
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file read status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Reading file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileReadAt(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint32_t cbToRead; int64_t iOffset;
+
+ int rc = VbglR3GuestCtrlFileGetReadAt(pHostCtx,
+ &uHandle, &cbToRead, (uint64_t *)&iOffset);
+ if (RT_SUCCESS(rc))
+ {
+ void *pvDataRead = pvScratchBuf;
+ size_t cbRead = 0;
+
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ if (cbToRead)
+ {
+ if (cbToRead > cbScratchBuf)
+ {
+ pvDataRead = RTMemAlloc(cbToRead);
+ if (!pvDataRead)
+ rc = VERR_NO_MEMORY;
+ }
+
+ if (RT_LIKELY(RT_SUCCESS(rc)))
+ rc = RTFileReadAt(pFile->hFile, iOffset, pvDataRead, cbToRead, &cbRead);
+ }
+ else
+ rc = VERR_BUFFER_UNDERFLOW;
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbRead(pHostCtx, rc, pvDataRead, (uint32_t)cbRead);
+ if ( cbToRead > cbScratchBuf
+ && pvDataRead)
+ RTMemFree(pvDataRead);
+
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file read status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Reading file \"%s\" at offset (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint32_t cbToWrite;
+
+ int rc = VbglR3GuestCtrlFileGetWrite(pHostCtx, &uHandle,
+ pvScratchBuf, cbScratchBuf,
+ &cbToWrite);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cbWritten = 0;
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ rc = RTFileWrite(pFile->hFile, pvScratchBuf, cbToWrite, &cbWritten);
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[File %s]: Writing pvScratchBuf=%p, cbToWrite=%RU32, cbWritten=%zu, rc=%Rrc\n",
+ pFile->szName, pvScratchBuf, cbToWrite, cbWritten, rc);
+#endif
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbWrite(pHostCtx, rc, (uint32_t)cbWritten);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Writing file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileWriteAt(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint32_t cbToWrite; int64_t iOffset;
+
+ int rc = VbglR3GuestCtrlFileGetWriteAt(pHostCtx, &uHandle,
+ pvScratchBuf, cbScratchBuf,
+ &cbToWrite, (uint64_t *)&iOffset);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cbWritten = 0;
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ rc = RTFileWriteAt(pFile->hFile, iOffset,
+ pvScratchBuf, cbToWrite, &cbWritten);
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[File %s]: Writing iOffset=%RI64, pvScratchBuf=%p, cbToWrite=%RU32, cbWritten=%zu, rc=%Rrc\n",
+ pFile->szName, iOffset, pvScratchBuf, cbToWrite, cbWritten, rc);
+#endif
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbWrite(pHostCtx, rc, (uint32_t)cbWritten);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Writing file \"%s\" at offset (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint32_t uSeekMethod;
+ uint64_t uOffset; /* Will be converted to int64_t. */
+
+ uint64_t uOffsetActual = 0;
+
+ int rc = VbglR3GuestCtrlFileGetSeek(pHostCtx, &uHandle,
+ &uSeekMethod, &uOffset);
+ if (RT_SUCCESS(rc))
+ {
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ unsigned uSeekMethodIPRT;
+ switch (uSeekMethod)
+ {
+ case GUEST_FILE_SEEKTYPE_BEGIN:
+ uSeekMethodIPRT = RTFILE_SEEK_BEGIN;
+ break;
+
+ case GUEST_FILE_SEEKTYPE_CURRENT:
+ uSeekMethodIPRT = RTFILE_SEEK_CURRENT;
+ break;
+
+ case GUEST_FILE_SEEKTYPE_END:
+ uSeekMethodIPRT = RTFILE_SEEK_END;
+ break;
+
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTFileSeek(pFile->hFile, (int64_t)uOffset,
+ uSeekMethodIPRT, &uOffsetActual);
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[File %s]: Seeking to iOffset=%RI64, uSeekMethodIPRT=%RU16, rc=%Rrc\n",
+ pFile->szName, (int64_t)uOffset, uSeekMethodIPRT, rc);
+#endif
+ }
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbSeek(pHostCtx, rc, uOffsetActual);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file seek status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Seeking file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ PVBOXSERVICECTRLFILE pFile = NULL;
+
+ uint32_t uHandle = 0;
+ uint64_t uOffsetActual = 0;
+
+ int rc = VbglR3GuestCtrlFileGetTell(pHostCtx, &uHandle);
+ if (RT_SUCCESS(rc))
+ {
+ pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
+ if (pFile)
+ {
+ uOffsetActual = RTFileTell(pFile->hFile);
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "[File %s]: Telling uOffsetActual=%RU64\n",
+ pFile->szName, uOffsetActual);
+#endif
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlFileCbTell(pHostCtx, rc, uOffsetActual);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report file tell status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Telling file \"%s\" (handle=%RU32) returned rc=%Rrc\n",
+ pFile ? pFile->szName : "<Not found>", uHandle, rc);
+#endif
+ return rc;
+}
+
+
+static int gstcntlSessionHandlePathRename(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ char szSource[RTPATH_MAX];
+ char szDest[RTPATH_MAX];
+ uint32_t uFlags = 0;
+
+ int rc = VbglR3GuestCtrlPathGetRename(pHostCtx,
+ szSource, sizeof(szSource),
+ szDest, sizeof(szDest),
+ /* Flags of type PATHRENAME_FLAG_. */
+ &uFlags);
+ if (RT_SUCCESS(rc))
+ {
+ if (uFlags & ~PATHRENAME_FLAG_VALID_MASK)
+ rc = VERR_NOT_SUPPORTED;
+
+ VBoxServiceVerbose(4, "Renaming \"%s\" to \"%s\", uFlags=0x%x, rc=%Rrc\n",
+ szSource, szDest, uFlags, rc);
+
+ if (RT_SUCCESS(rc))
+ {
+ if (uFlags & PATHRENAME_FLAG_NO_REPLACE)
+ uFlags |= RTPATHRENAME_FLAGS_NO_REPLACE;
+
+ if (uFlags & PATHRENAME_FLAG_REPLACE)
+ uFlags |= RTPATHRENAME_FLAGS_REPLACE;
+
+ if (uFlags & PATHRENAME_FLAG_NO_SYMLINKS)
+ uFlags |= RTPATHRENAME_FLAGS_NO_SYMLINKS;
+
+ rc = RTPathRename(szSource, szDest, uFlags);
+ }
+
+ /* Report back in any case. */
+ int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to report renaming status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Renaming \"%s\" to \"%s\" returned rc=%Rrc\n",
+ szSource, szDest, rc);
+#endif
+ return rc;
+}
+
+
+/**
+ * Handles starting a guest processes.
+ *
+ * @returns IPRT status code.
+ * @param pSession Guest session.
+ * @param pHostCtx Host context.
+ */
+int gstcntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+ bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */
+
+ switch (pHostCtx->uProtocol)
+ {
+ case 1: /* Guest Additions < 4.3. */
+ if (pHostCtx->uNumParms != 11)
+ rc = VERR_NOT_SUPPORTED;
+ break;
+
+ case 2: /* Guest Additions >= 4.3. */
+ if (pHostCtx->uNumParms != 12)
+ rc = VERR_NOT_SUPPORTED;
+ break;
+
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ VBOXSERVICECTRLPROCSTARTUPINFO startupInfo;
+ RT_ZERO(startupInfo);
+
+ /* Initialize maximum environment block size -- needed as input
+ * parameter to retrieve the stuff from the host. On output this then
+ * will contain the actual block size. */
+ startupInfo.cbEnv = sizeof(startupInfo.szEnv);
+
+ rc = VbglR3GuestCtrlProcGetStart(pHostCtx,
+ /* Command */
+ startupInfo.szCmd, sizeof(startupInfo.szCmd),
+ /* Flags */
+ &startupInfo.uFlags,
+ /* Arguments */
+ startupInfo.szArgs, sizeof(startupInfo.szArgs), &startupInfo.uNumArgs,
+ /* Environment */
+ startupInfo.szEnv, &startupInfo.cbEnv, &startupInfo.uNumEnvVars,
+ /* Credentials; for hosts with VBox < 4.3 (protocol version 1).
+ * For protocl v2 and up the credentials are part of the session
+ * opening call. */
+ startupInfo.szUser, sizeof(startupInfo.szUser),
+ startupInfo.szPassword, sizeof(startupInfo.szPassword),
+ /* Timeout (in ms) */
+ &startupInfo.uTimeLimitMS,
+ /* Process priority */
+ &startupInfo.uPriority,
+ /* Process affinity */
+ startupInfo.uAffinity, sizeof(startupInfo.uAffinity), &startupInfo.uNumAffinity);
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, uTimeout=%RU32\n",
+ startupInfo.szCmd, startupInfo.uFlags,
+ startupInfo.uNumArgs ? startupInfo.szArgs : "<None>",
+ startupInfo.uNumEnvVars ? startupInfo.szEnv : "<None>",
+ startupInfo.uTimeLimitMS);
+
+ rc = GstCntlSessionProcessStartAllowed(pSession, &fStartAllowed);
+ if (RT_SUCCESS(rc))
+ {
+ if (fStartAllowed)
+ {
+ rc = GstCntlProcessStart(pSession, &startupInfo, pHostCtx->uContextID);
+ }
+ else
+ rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */
+ }
+ }
+ }
+
+ /* In case of an error we need to notify the host to not wait forever for our response. */
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Starting process failed with rc=%Rrc, protocol=%RU32, parameters=%RU32\n",
+ rc, pHostCtx->uProtocol, pHostCtx->uNumParms);
+
+ /* Don't report back if we didn't supply sufficient buffer for getting
+ * the actual command -- we don't have the matching context ID. */
+ if (rc != VERR_TOO_MUCH_DATA)
+ {
+ /*
+ * Note: The context ID can be 0 because we mabye weren't able to fetch the command
+ * from the host. The host in case has to deal with that!
+ */
+ int rc2 = VbglR3GuestCtrlProcCbStatus(pHostCtx, 0 /* PID, invalid */,
+ PROC_STS_ERROR, rc,
+ NULL /* pvData */, 0 /* cbData */);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Error sending start process status to host, rc=%Rrc\n", rc2);
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * Sends stdin input to a specific guest process.
+ *
+ * @returns IPRT status code.
+ * @param pSession The session which is in charge.
+ * @param pHostCtx The host context to use.
+ * @param pvScratchBuf The scratch buffer.
+ * @param cbScratchBuf The scratch buffer size for retrieving the input data.
+ */
+int gstcntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
+
+ uint32_t uPID;
+ uint32_t uFlags;
+ uint32_t cbSize;
+
+ uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status sent back to the host. */
+ uint32_t cbWritten = 0; /* Number of bytes written to the guest. */
+
+ /*
+ * Ask the host for the input data.
+ */
+ int rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &uFlags,
+ pvScratchBuf, cbScratchBuf, &cbSize);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Failed to retrieve process input command for PID=%RU32, rc=%Rrc\n",
+ uPID, rc);
+ }
+ else if (cbSize > cbScratchBuf)
+ {
+ VBoxServiceError("Too much process input received, rejecting: uPID=%RU32, cbSize=%RU32, cbScratchBuf=%RU32\n",
+ uPID, cbSize, cbScratchBuf);
+ rc = VERR_TOO_MUCH_DATA;
+ }
+ else
+ {
+ /*
+ * Is this the last input block we need to deliver? Then let the pipe know ...
+ */
+ bool fPendingClose = false;
+ if (uFlags & INPUT_FLAG_EOF)
+ {
+ fPendingClose = true;
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Got last process input block for PID=%RU32 (%RU32 bytes) ...\n",
+ uPID, cbSize);
+#endif
+ }
+
+ PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
+ if (pProcess)
+ {
+ rc = GstCntlProcessHandleInput(pProcess, pHostCtx, fPendingClose,
+ pvScratchBuf, cbSize);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error handling input command for PID=%RU32, rc=%Rrc\n",
+ uPID, rc);
+ GstCntlProcessRelease(pProcess);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Setting input for PID=%RU32 resulted in rc=%Rrc\n",
+ uPID, rc);
+#endif
+ return rc;
+}
+
+
+/**
+ * Gets stdout/stderr output of a specific guest process.
+ *
+ * @return IPRT status code.
+ * @param pSession The session which is in charge.
+ * @param pHostCtx The host context to use.
+ */
+int gstcntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ uint32_t uPID;
+ uint32_t uHandleID;
+ uint32_t uFlags;
+
+ int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags);
+#ifdef DEBUG_andy
+ VBoxServiceVerbose(4, "Getting output for PID=%RU32, CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n",
+ uPID, pHostCtx->uContextID, uHandleID, uFlags);
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
+ if (pProcess)
+ {
+ rc = GstCntlProcessHandleOutput(pProcess, pHostCtx,
+ uHandleID, _64K /* cbToRead */, uFlags);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error getting output for PID=%RU32, rc=%Rrc\n",
+ uPID, rc);
+ GstCntlProcessRelease(pProcess);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+#ifdef DEBUG_andy
+ VBoxServiceVerbose(4, "Getting output for PID=%RU32 resulted in rc=%Rrc\n",
+ uPID, rc);
+#endif
+ return rc;
+}
+
+
+/**
+ * Tells a guest process to terminate.
+ *
+ * @return IPRT status code.
+ * @param pSession The session which is in charge.
+ * @param pHostCtx The host context to use.
+ */
+int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ uint32_t uPID;
+ int rc = VbglR3GuestCtrlProcGetTerminate(pHostCtx, &uPID);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
+ if (pProcess)
+ {
+ rc = GstCntlProcessHandleTerm(pProcess);
+
+ GstCntlProcessRelease(pProcess);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+#ifdef DEBUG_andy
+ VBoxServiceVerbose(4, "Terminating PID=%RU32 resulted in rc=%Rrc\n",
+ uPID, rc);
+#endif
+ return rc;
+}
+
+
+int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession,
+ PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ uint32_t uPID;
+ uint32_t uWaitFlags; uint32_t uTimeoutMS;
+
+ int rc = VbglR3GuestCtrlProcGetWaitFor(pHostCtx, &uPID, &uWaitFlags, &uTimeoutMS);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
+ if (pProcess)
+ {
+ rc = VERR_NOT_IMPLEMENTED; /** @todo */
+ GstCntlProcessRelease(pProcess);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+ return rc;
+}
+
+
+int GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession,
+ uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
+ void *pvScratchBuf, size_t cbScratchBuf,
+ volatile bool *pfShutdown)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfShutdown, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+ /**
+ * Only anonymous sessions (that is, sessions which run with local
+ * service privileges) or forked session processes can do certain
+ * operations.
+ */
+ bool fImpersonated = ( pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_FORK
+ || pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_ANONYMOUS);
+
+ switch (uMsg)
+ {
+ case HOST_SESSION_CLOSE:
+ /* Shutdown (this fork). */
+ rc = GstCntlSessionClose(pSession);
+ *pfShutdown = true; /* Shutdown in any case. */
+ break;
+
+ case HOST_DIR_REMOVE:
+ rc = fImpersonated
+ ? gstcntlSessionHandleDirRemove(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_EXEC_CMD:
+ rc = gstcntlSessionHandleProcExec(pSession, pHostCtx);
+ break;
+
+ case HOST_EXEC_SET_INPUT:
+ rc = gstcntlSessionHandleProcInput(pSession, pHostCtx,
+ pvScratchBuf, cbScratchBuf);
+ break;
+
+ case HOST_EXEC_GET_OUTPUT:
+ rc = gstcntlSessionHandleProcOutput(pSession, pHostCtx);
+ break;
+
+ case HOST_EXEC_TERMINATE:
+ rc = gstcntlSessionHandleProcTerminate(pSession, pHostCtx);
+ break;
+
+ case HOST_EXEC_WAIT_FOR:
+ rc = gstcntlSessionHandleProcWaitFor(pSession, pHostCtx);
+ break;
+
+ case HOST_FILE_OPEN:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileOpen(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_CLOSE:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileClose(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_READ:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileRead(pSession, pHostCtx,
+ pvScratchBuf, cbScratchBuf)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_READ_AT:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileReadAt(pSession, pHostCtx,
+ pvScratchBuf, cbScratchBuf)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_WRITE:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileWrite(pSession, pHostCtx,
+ pvScratchBuf, cbScratchBuf)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_WRITE_AT:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileWriteAt(pSession, pHostCtx,
+ pvScratchBuf, cbScratchBuf)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_SEEK:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileSeek(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_FILE_TELL:
+ rc = fImpersonated
+ ? gstcntlSessionHandleFileTell(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ case HOST_PATH_RENAME:
+ rc = fImpersonated
+ ? gstcntlSessionHandlePathRename(pSession, pHostCtx)
+ : VERR_NOT_SUPPORTED;
+ break;
+
+ default:
+ rc = VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID);
+ VBoxServiceVerbose(3, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n",
+ uMsg, pHostCtx->uNumParms);
+ break;
+ }
+
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error while handling message (uMsg=%RU32, cParms=%RU32), rc=%Rrc\n",
+ uMsg, pHostCtx->uNumParms, rc);
+
+ return rc;
+}
+
+
+/**
+ * Thread main routine for a forked guest session process.
+ * This thread runs in the main executable to control the forked
+ * session process.
+ *
+ * @return IPRT status code.
+ * @param RTTHREAD Pointer to the thread's data.
+ * @param void* User-supplied argument pointer.
+ *
+ */
+static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser)
+{
+ PVBOXSERVICECTRLSESSIONTHREAD pThread = (PVBOXSERVICECTRLSESSIONTHREAD)pvUser;
+ AssertPtrReturn(pThread, VERR_INVALID_POINTER);
+
+ uint32_t uSessionID = pThread->StartupInfo.uSessionID;
+
+ uint32_t uClientID;
+ int rc = VbglR3GuestCtrlConnect(&uClientID);
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(3, "Session ID=%RU32 thread running, client ID=%RU32\n",
+ uSessionID, uClientID);
+
+ /* The session thread is not interested in receiving any commands;
+ * tell the host service. */
+ rc = VbglR3GuestCtrlMsgFilterSet(uClientID, 0 /* Skip all */,
+ 0 /* Filter mask to add */, 0 /* Filter mask to remove */);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Unable to set message filter, rc=%Rrc\n", rc);
+ /* Non-critical. */
+ rc = VINF_SUCCESS;
+ }
+ }
+ else
+ VBoxServiceError("Error connecting to guest control service, rc=%Rrc\n", rc);
+
+ if (RT_FAILURE(rc))
+ pThread->fShutdown = true;
+
+ /* Let caller know that we're done initializing, regardless of the result. */
+ int rc2 = RTThreadUserSignal(RTThreadSelf());
+ AssertRC(rc2);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ bool fProcessAlive = true;
+ RTPROCSTATUS ProcessStatus;
+ RT_ZERO(ProcessStatus);
+
+ int rcWait;
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t uTimeoutsMS = 30 * 1000; /** @todo Make this configurable. Later. */
+ uint64_t u64TimeoutStart = 0;
+
+ for (;;)
+ {
+ rcWait = RTProcWaitNoResume(pThread->hProcess, RTPROCWAIT_FLAGS_NOBLOCK,
+ &ProcessStatus);
+ if (RT_UNLIKELY(rcWait == VERR_INTERRUPTED))
+ continue;
+ else if ( rcWait == VINF_SUCCESS
+ || rcWait == VERR_PROCESS_NOT_FOUND)
+ {
+ fProcessAlive = false;
+ break;
+ }
+ else
+ AssertMsgBreak(rcWait == VERR_PROCESS_RUNNING,
+ ("Got unexpected rc=%Rrc while waiting for session process termination\n", rcWait));
+
+ if (ASMAtomicReadBool(&pThread->fShutdown))
+ {
+ if (!u64TimeoutStart)
+ {
+ VBoxServiceVerbose(3, "Notifying guest session process (PID=%RU32, session ID=%RU32) ...\n",
+ pThread->hProcess, uSessionID);
+
+ VBGLR3GUESTCTRLCMDCTX hostCtx = { uClientID,
+ VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSessionID),
+ pThread->StartupInfo.uProtocol, 2 /* uNumParms */ };
+ rc = VbglR3GuestCtrlSessionClose(&hostCtx, 0 /* uFlags */);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Unable to notify guest session process (PID=%RU32, session ID=%RU32), rc=%Rrc\n",
+ pThread->hProcess, uSessionID, rc);
+
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ /* Terminate guest session process in case it's not supported by a too old host. */
+ rc = RTProcTerminate(pThread->hProcess);
+ VBoxServiceVerbose(3, "Terminating guest session process (PID=%RU32) ended with rc=%Rrc\n",
+ pThread->hProcess, rc);
+ }
+ break;
+ }
+
+ VBoxServiceVerbose(3, "Guest session ID=%RU32 thread was asked to terminate, waiting for session process to exit (%RU32ms timeout) ...\n",
+ uSessionID, uTimeoutsMS);
+ u64TimeoutStart = RTTimeMilliTS();
+
+ continue; /* Don't waste time on waiting. */
+ }
+ if (RTTimeMilliTS() - u64TimeoutStart > uTimeoutsMS)
+ {
+ VBoxServiceVerbose(3, "Guest session ID=%RU32 process did not shut down within time\n",
+ uSessionID);
+ break;
+ }
+ }
+
+ RTThreadSleep(100); /* Wait a bit. */
+ }
+
+ if (!fProcessAlive)
+ {
+ VBoxServiceVerbose(2, "Guest session ID=%RU32 process terminated with rc=%Rrc, reason=%ld, status=%d\n",
+ uSessionID, rcWait,
+ ProcessStatus.enmReason, ProcessStatus.iStatus);
+ }
+ }
+
+ uint32_t uSessionStatus = GUEST_SESSION_NOTIFYTYPE_UNDEFINED;
+ uint32_t uSessionRc = VINF_SUCCESS; /** uint32_t vs. int. */
+
+ if (fProcessAlive)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ VBoxServiceVerbose(2, "Guest session ID=%RU32 process still alive, killing attempt %d/3\n",
+ uSessionID, i + 1);
+
+ rc = RTProcTerminate(pThread->hProcess);
+ if (RT_SUCCESS(rc))
+ break;
+ RTThreadSleep(3000);
+ }
+
+ VBoxServiceVerbose(2, "Guest session ID=%RU32 process termination resulted in rc=%Rrc\n",
+ uSessionID, rc);
+
+ uSessionStatus = RT_SUCCESS(rc)
+ ? GUEST_SESSION_NOTIFYTYPE_TOK : GUEST_SESSION_NOTIFYTYPE_TOA;
+ }
+ else
+ {
+ if (RT_SUCCESS(rcWait))
+ {
+ switch (ProcessStatus.enmReason)
+ {
+ case RTPROCEXITREASON_NORMAL:
+ uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
+ break;
+
+ case RTPROCEXITREASON_ABEND:
+ uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
+ break;
+
+ case RTPROCEXITREASON_SIGNAL:
+ uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES;
+ break;
+
+ default:
+ AssertMsgFailed(("Unhandled process termination reason (%ld)\n",
+ ProcessStatus.enmReason));
+ uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
+ break;
+ }
+ }
+ else
+ {
+ /* If we didn't find the guest process anymore, just assume it
+ * terminated normally. */
+ uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
+ }
+ }
+
+ VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%RU32, sessionRc=%Rrc\n",
+ uSessionID, uSessionStatus, uSessionRc);
+
+ /* Report final status. */
+ Assert(uSessionStatus != GUEST_SESSION_NOTIFYTYPE_UNDEFINED);
+ VBGLR3GUESTCTRLCMDCTX ctx = { uClientID, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSessionID) };
+ rc2 = VbglR3GuestCtrlSessionNotify(&ctx,
+ uSessionStatus, uSessionRc);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Reporting session ID=%RU32 final status failed with rc=%Rrc\n",
+ uSessionID, rc2);
+
+ VbglR3GuestCtrlDisconnect(uClientID);
+
+ VBoxServiceVerbose(3, "Session ID=%RU32 thread ended with rc=%Rrc\n",
+ uSessionID, rc);
+ return rc;
+}
+
+
+RTEXITCODE gstcntlSessionForkWorker(PVBOXSERVICECTRLSESSION pSession)
+{
+ AssertPtrReturn(pSession, RTEXITCODE_FAILURE);
+
+ bool fSessionFilter = true;
+
+ VBoxServiceVerbose(0, "Hi, this is guest session ID=%RU32\n",
+ pSession->StartupInfo.uSessionID);
+
+ uint32_t uClientID;
+ int rc = VbglR3GuestCtrlConnect(&uClientID);
+ if (RT_SUCCESS(rc))
+ {
+ /* Set session filter. This prevents the guest control
+ * host service to send messages which belong to another
+ * session we don't want to handle. */
+ uint32_t uFilterAdd =
+ VBOX_GUESTCTRL_FILTER_BY_SESSION(pSession->StartupInfo.uSessionID);
+ rc = VbglR3GuestCtrlMsgFilterSet(uClientID,
+ VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(pSession->StartupInfo.uSessionID),
+ uFilterAdd, 0 /* Filter remove */);
+ VBoxServiceVerbose(3, "Setting message filterAdd=0x%x returned %Rrc\n",
+ uFilterAdd, rc);
+
+ if ( RT_FAILURE(rc)
+ && rc == VERR_NOT_SUPPORTED)
+ {
+ /* No session filter available. Skip. */
+ fSessionFilter = false;
+
+ rc = VINF_SUCCESS;
+ }
+
+ VBoxServiceVerbose(1, "Using client ID=%RU32\n", uClientID);
+ }
+ else
+ VBoxServiceError("Error connecting to guest control service, rc=%Rrc\n", rc);
+
+ /* Report started status. */
+ VBGLR3GUESTCTRLCMDCTX ctx = { uClientID, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(pSession->StartupInfo.uSessionID) };
+ int rc2 = VbglR3GuestCtrlSessionNotify(&ctx,
+ GUEST_SESSION_NOTIFYTYPE_STARTED, VINF_SUCCESS);
+ if (RT_FAILURE(rc2))
+ {
+ VBoxServiceError("Reporting session ID=%RU32 started status failed with rc=%Rrc\n",
+ pSession->StartupInfo.uSessionID, rc2);
+
+ /*
+ * If session status cannot be posted to the host for
+ * some reason, bail out.
+ */
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ /* Allocate a scratch buffer for commands which also send
+ * payload data with them. */
+ uint32_t cbScratchBuf = _64K; /** @todo Make buffer size configurable via guest properties/argv! */
+ AssertReturn(RT_IS_POWER_OF_TWO(cbScratchBuf), RTEXITCODE_FAILURE);
+ uint8_t *pvScratchBuf = NULL;
+
+ if (RT_SUCCESS(rc))
+ {
+ pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
+ if (!pvScratchBuf)
+ rc = VERR_NO_MEMORY;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ bool fShutdown = false;
+
+ VBGLR3GUESTCTRLCMDCTX ctxHost = { uClientID, 0 /* Context ID, zeroed */,
+ pSession->StartupInfo.uProtocol };
+ for (;;)
+ {
+ VBoxServiceVerbose(3, "Waiting for host msg ...\n");
+ uint32_t uMsg = 0;
+ uint32_t cParms = 0;
+ rc = VbglR3GuestCtrlMsgWaitFor(uClientID, &uMsg, &cParms);
+ if (rc == VERR_TOO_MUCH_DATA)
+ {
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Message requires %RU32 parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms);
+#endif
+ rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */
+ }
+ else if (RT_FAILURE(rc))
+ VBoxServiceVerbose(3, "Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(4, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
+
+ /* Set number of parameters for current host context. */
+ ctxHost.uNumParms = cParms;
+
+ /* ... and pass it on to the session handler. */
+ rc = GstCntlSessionHandler(pSession, uMsg, &ctxHost,
+ pvScratchBuf, cbScratchBuf, &fShutdown);
+ }
+
+ if (fShutdown)
+ break;
+
+ /* Let's sleep for a bit and let others run ... */
+ RTThreadYield();
+ }
+ }
+
+ VBoxServiceVerbose(0, "Session %RU32 ended\n", pSession->StartupInfo.uSessionID);
+
+ if (pvScratchBuf)
+ RTMemFree(pvScratchBuf);
+
+ if (uClientID)
+ {
+ VBoxServiceVerbose(3, "Disconnecting client ID=%RU32 ...\n", uClientID);
+ VbglR3GuestCtrlDisconnect(uClientID);
+ }
+
+ VBoxServiceVerbose(3, "Session worker returned with rc=%Rrc\n", rc);
+ return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+
+/**
+ * Finds a (formerly) started guest process given by its PID and increases
+ * its reference count. Must be decreased by the caller with GstCntlProcessRelease().
+ * Note: This does *not lock the process!
+ *
+ * @return PVBOXSERVICECTRLTHREAD Guest process if found, otherwise NULL.
+ * @param PVBOXSERVICECTRLSESSION Pointer to guest session where to search process in.
+ * @param uPID PID to search for.
+ */
+PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)
+{
+ AssertPtrReturn(pSession, NULL);
+
+ PVBOXSERVICECTRLPROCESS pProcess = NULL;
+ int rc = RTCritSectEnter(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLPROCESS pCurProcess;
+ RTListForEach(&pSession->lstProcesses, pCurProcess, VBOXSERVICECTRLPROCESS, Node)
+ {
+ if (pCurProcess->uPID == uPID)
+ {
+ rc = RTCritSectEnter(&pCurProcess->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ pCurProcess->cRefs++;
+ rc = RTCritSectLeave(&pCurProcess->CritSect);
+ AssertRC(rc);
+ }
+
+ if (RT_SUCCESS(rc))
+ pProcess = pCurProcess;
+ break;
+ }
+ }
+
+ rc = RTCritSectLeave(&pSession->CritSect);
+ AssertRC(rc);
+ }
+
+ return pProcess;
+}
+
+
+int GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+
+ VBoxServiceVerbose(0, "Session %RU32 is about to close ...\n",
+ pSession->StartupInfo.uSessionID);
+
+ int rc = RTCritSectEnter(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Close all guest processes.
+ */
+ VBoxServiceVerbose(0, "Stopping all guest processes ...\n");
+
+ /* Signal all guest processes in the active list that we want to shutdown. */
+ size_t cProcesses = 0;
+ PVBOXSERVICECTRLPROCESS pProcess;
+ RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
+ {
+ GstCntlProcessStop(pProcess);
+ cProcesses++;
+ }
+
+ VBoxServiceVerbose(1, "%zu guest processes were signalled to stop\n", cProcesses);
+
+ /* Wait for all active threads to shutdown and destroy the active thread list. */
+ pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node);
+ while (pProcess)
+ {
+ PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
+ bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node);
+
+ int rc2 = RTCritSectLeave(&pSession->CritSect);
+ AssertRC(rc2);
+
+ rc2 = GstCntlProcessWait(pProcess,
+ 30 * 1000 /* Wait 30 seconds max. */,
+ NULL /* rc */);
+
+ int rc3 = RTCritSectEnter(&pSession->CritSect);
+ AssertRC(rc3);
+
+ if (RT_SUCCESS(rc2))
+ GstCntlProcessFree(pProcess);
+
+ if (fLast)
+ break;
+
+ pProcess = pNext;
+ }
+
+#ifdef DEBUG
+ pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node);
+ while (pProcess)
+ {
+ PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
+ bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node);
+
+ VBoxServiceVerbose(1, "Process %p (PID %RU32) still in list\n",
+ pProcess, pProcess->uPID);
+ if (fLast)
+ break;
+
+ pProcess = pNext;
+ }
+#endif
+ AssertMsg(RTListIsEmpty(&pSession->lstProcesses),
+ ("Guest process list still contains entries when it should not\n"));
+
+ /*
+ * Close all left guest files.
+ */
+ VBoxServiceVerbose(0, "Closing all guest files ...\n");
+
+ PVBOXSERVICECTRLFILE pFile;
+ pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node);
+ while (pFile)
+ {
+ PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
+ bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node);
+
+ int rc2 = gstcntlSessionFileDestroy(pFile);
+ if (RT_FAILURE(rc2))
+ {
+ VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n",
+ pFile->szName, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ /* Keep going. */
+ }
+
+ if (fLast)
+ break;
+
+ pFile = pNext;
+ }
+
+ AssertMsg(RTListIsEmpty(&pSession->lstFiles),
+ ("Guest file list still contains entries when it should not\n"));
+
+ int rc2 = RTCritSectLeave(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return rc;
+}
+
+
+int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+
+ int rc = GstCntlSessionClose(pSession);
+
+ /* Destroy critical section. */
+ RTCritSectDelete(&pSession->CritSect);
+
+ return rc;
+}
+
+
+int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+
+ RTListInit(&pSession->lstProcesses);
+ RTListInit(&pSession->lstFiles);
+
+ pSession->uFlags = uFlags;
+
+ /* Init critical section for protecting the thread lists. */
+ int rc = RTCritSectInit(&pSession->CritSect);
+ AssertRC(rc);
+
+ return rc;
+}
+
+
+/**
+ * Adds a guest process to a session's process list.
+ *
+ * @return IPRT status code.
+ * @param pSession Guest session to add process to.
+ * @param pProcess Guest process to add.
+ */
+int GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession,
+ PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectEnter(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(3, "Adding process (PID %RU32) to session ID=%RU32\n",
+ pProcess->uPID, pSession->StartupInfo.uSessionID);
+
+ /* Add process to session list. */
+ /* rc = */ RTListAppend(&pSession->lstProcesses, &pProcess->Node);
+
+ int rc2 = RTCritSectLeave(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Removes a guest process from a session's process list.
+ *
+ * @return IPRT status code.
+ * @param pSession Guest session to remove process from.
+ * @param pProcess Guest process to remove.
+ */
+int GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession,
+ PVBOXSERVICECTRLPROCESS pProcess)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectEnter(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ VBoxServiceVerbose(3, "Removing process (PID %RU32) from session ID=%RU32\n",
+ pProcess->uPID, pSession->StartupInfo.uSessionID);
+ Assert(pProcess->cRefs == 0);
+
+ RTListNodeRemove(&pProcess->Node);
+
+ int rc2 = RTCritSectLeave(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Determines whether starting a new guest process according to the
+ * maximum number of concurrent guest processes defined is allowed or not.
+ *
+ * @return IPRT status code.
+ * @param pbAllowed True if starting (another) guest process
+ * is allowed, false if not.
+ */
+int GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession,
+ bool *pbAllowed)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectEnter(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Check if we're respecting our memory policy by checking
+ * how many guest processes are started and served already.
+ */
+ bool fLimitReached = false;
+ if (pSession->uProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */
+ {
+ uint32_t uProcsRunning = 0;
+ PVBOXSERVICECTRLPROCESS pProcess;
+ RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
+ uProcsRunning++;
+
+ VBoxServiceVerbose(3, "Maximum served guest processes set to %u, running=%u\n",
+ pSession->uProcsMaxKept, uProcsRunning);
+
+ int32_t iProcsLeft = (pSession->uProcsMaxKept - uProcsRunning - 1);
+ if (iProcsLeft < 0)
+ {
+ VBoxServiceVerbose(3, "Maximum running guest processes reached (%u)\n",
+ pSession->uProcsMaxKept);
+ fLimitReached = true;
+ }
+ }
+
+ *pbAllowed = !fLimitReached;
+
+ int rc2 = RTCritSectLeave(&pSession->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Creates a guest session. This will spawn a new VBoxService.exe instance under
+ * behalf of the given user which then will act as a session host. On successful
+ * open, the session will be added to the given session thread list.
+ *
+ * @return IPRT status code.
+ * @param pList Which list to use to store the session thread in.
+ * @param pSessionStartupInfo Session startup info.
+ * @param ppSessionThread Returns newly created session thread on success.
+ * Optional.
+ */
+int GstCntlSessionThreadCreate(PRTLISTANCHOR pList,
+ const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
+ PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)
+{
+ AssertPtrReturn(pList, VERR_INVALID_POINTER);
+ AssertPtrReturn(pSessionStartupInfo, VERR_INVALID_POINTER);
+ /* ppSessionThread is optional. */
+
+#ifdef DEBUG
+ PVBOXSERVICECTRLSESSIONTHREAD pSessionCur;
+ /* Check for existing session in debug mode. Should never happen because of
+ * Main consistency. */
+ RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node)
+ {
+ if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID)
+ {
+ AssertMsgFailed(("Guest session thread ID=%RU32 (%p) already exists when it should not\n",
+ pSessionCur->StartupInfo.uSessionID, pSessionCur));
+ return VERR_ALREADY_EXISTS;
+ }
+ }
+#endif
+ int rc = VINF_SUCCESS;
+
+ /* Static counter to help tracking session thread <-> process relations. */
+ static uint32_t s_uCtrlSessionThread = 0;
+ if (s_uCtrlSessionThread++ == UINT32_MAX)
+ s_uCtrlSessionThread = 0; /* Wrap around to not let IPRT freak out. */
+
+ PVBOXSERVICECTRLSESSIONTHREAD pSessionThread =
+ (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD));
+ if (pSessionThread)
+ {
+ /* Copy over session startup info. */
+ memcpy(&pSessionThread->StartupInfo, pSessionStartupInfo,
+ sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO));
+
+ pSessionThread->fShutdown = false;
+ pSessionThread->fStarted = false;
+ pSessionThread->fStopped = false;
+
+ /* Is this an anonymous session? */
+ /* Anonymous sessions run with the same privileges as the main VBoxService executable. */
+ bool fAnonymous = !RT_BOOL(strlen(pSessionThread->StartupInfo.szUser));
+ if (fAnonymous)
+ {
+ Assert(!strlen(pSessionThread->StartupInfo.szPassword));
+ Assert(!strlen(pSessionThread->StartupInfo.szDomain));
+
+ VBoxServiceVerbose(3, "New anonymous guest session ID=%RU32 created, uFlags=%x, using protocol %RU32\n",
+ pSessionStartupInfo->uSessionID,
+ pSessionStartupInfo->uFlags,
+ pSessionStartupInfo->uProtocol);
+ }
+ else
+ {
+ VBoxServiceVerbose(3, "Forking new guest session ID=%RU32, szUser=%s, szPassword=%s, szDomain=%s, uFlags=%x, using protocol %RU32\n",
+ pSessionStartupInfo->uSessionID,
+ pSessionStartupInfo->szUser,
+#ifdef DEBUG
+ pSessionStartupInfo->szPassword,
+#else
+ "XXX", /* Never show passwords in release mode. */
+#endif
+ pSessionStartupInfo->szDomain,
+ pSessionStartupInfo->uFlags,
+ pSessionStartupInfo->uProtocol);
+ }
+
+ rc = RTCritSectInit(&pSessionThread->CritSect);
+ AssertRC(rc);
+
+ /* Fork child doing the actual session handling. */
+ char szExeName[RTPATH_MAX];
+ char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
+ if (pszExeName)
+ {
+ char szParmUserName[GUESTPROCESS_MAX_USER_LEN + 32];
+ if (!fAnonymous)
+ {
+ if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--user=%s", pSessionThread->StartupInfo.szUser))
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+ char szParmSessionID[32];
+ if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionID, sizeof(szParmSessionID), "--session-id=%RU32",
+ pSessionThread->StartupInfo.uSessionID))
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+ char szParmSessionProto[32];
+ if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32",
+ pSessionThread->StartupInfo.uProtocol))
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+#ifdef DEBUG
+ char szParmThreadId[32];
+ if (RT_SUCCESS(rc) && !RTStrPrintf(szParmThreadId, sizeof(szParmThreadId), "--thread-id=%RU32",
+ s_uCtrlSessionThread))
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+#endif /* DEBUG */
+ if (RT_SUCCESS(rc))
+ {
+ int iOptIdx = 0; /* Current index in argument vector. */
+
+ char const *papszArgs[16];
+ papszArgs[iOptIdx++] = pszExeName;
+ papszArgs[iOptIdx++] = "guestsession";
+ papszArgs[iOptIdx++] = szParmSessionID;
+ papszArgs[iOptIdx++] = szParmSessionProto;
+#ifdef DEBUG
+ papszArgs[iOptIdx++] = szParmThreadId;
+#endif /* DEBUG */
+ if (!fAnonymous)
+ papszArgs[iOptIdx++] = szParmUserName;
+
+ /* Add same verbose flags as parent process. */
+ int rc2 = VINF_SUCCESS;
+ char szParmVerbose[32] = { 0 };
+ for (int i = 0; i < g_cVerbosity && RT_SUCCESS(rc2); i++)
+ {
+ if (i == 0)
+ rc2 = RTStrCat(szParmVerbose, sizeof(szParmVerbose), "-");
+ if (RT_FAILURE(rc2))
+ break;
+ rc2 = RTStrCat(szParmVerbose, sizeof(szParmVerbose), "v");
+ }
+ if (RT_SUCCESS(rc2))
+ papszArgs[iOptIdx++] = szParmVerbose;
+
+ /* Add log file handling. Each session will have an own
+ * log file, naming based on the parent log file. */
+ char szParmLogFile[RTPATH_MAX];
+ if ( RT_SUCCESS(rc2)
+ && strlen(g_szLogFile))
+ {
+ char *pszLogFile = RTStrDup(g_szLogFile);
+ if (pszLogFile)
+ {
+ char *pszLogExt = NULL;
+ if (RTPathHasExt(pszLogFile))
+ pszLogExt = RTStrDup(RTPathExt(pszLogFile));
+ RTPathStripExt(pszLogFile);
+ char *pszLogSuffix;
+#ifndef DEBUG
+ if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%s",
+ pSessionStartupInfo->uSessionID,
+ pSessionStartupInfo->szUser) < 0)
+ {
+ rc2 = VERR_NO_MEMORY;
+ }
+#else
+ if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%RU32-%s",
+ pSessionStartupInfo->uSessionID,
+ s_uCtrlSessionThread,
+ pSessionStartupInfo->szUser) < 0)
+ {
+ rc2 = VERR_NO_MEMORY;
+ }
+#endif /* DEBUG */
+ else
+ {
+ rc2 = RTStrAAppend(&pszLogFile, pszLogSuffix);
+ if (RT_SUCCESS(rc2) && pszLogExt)
+ rc2 = RTStrAAppend(&pszLogFile, pszLogExt);
+ if (RT_SUCCESS(rc2))
+ {
+ if (!RTStrPrintf(szParmLogFile, sizeof(szParmLogFile),
+ "--logfile=%s", pszLogFile))
+ {
+ rc2 = VERR_BUFFER_OVERFLOW;
+ }
+ }
+ RTStrFree(pszLogSuffix);
+ }
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Error building session logfile string for session %RU32 (user %s), rc=%Rrc\n",
+ pSessionStartupInfo->uSessionID, pSessionStartupInfo->szUser, rc2);
+ if (pszLogExt)
+ RTStrFree(pszLogExt);
+ RTStrFree(pszLogFile);
+ }
+ if (RT_SUCCESS(rc2))
+ papszArgs[iOptIdx++] = szParmLogFile;
+
+ rc = rc2;
+ }
+ else if (RT_FAILURE(rc2))
+ rc = rc2;
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "Argv building rc=%Rrc, session flags=%x\n",
+ rc, g_Session.uFlags);
+ char szParmDumpStdOut[32];
+ if ( RT_SUCCESS(rc)
+ && g_Session.uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT)
+ {
+ if (!RTStrPrintf(szParmDumpStdOut, sizeof(szParmDumpStdOut), "--dump-stdout"))
+ rc = VERR_BUFFER_OVERFLOW;
+ if (RT_SUCCESS(rc))
+ papszArgs[iOptIdx++] = szParmDumpStdOut;
+ }
+ char szParmDumpStdErr[32];
+ if ( RT_SUCCESS(rc)
+ && g_Session.uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR)
+ {
+ if (!RTStrPrintf(szParmDumpStdErr, sizeof(szParmDumpStdErr), "--dump-stderr"))
+ rc = VERR_BUFFER_OVERFLOW;
+ if (RT_SUCCESS(rc))
+ papszArgs[iOptIdx++] = szParmDumpStdErr;
+ }
+#endif
+ papszArgs[iOptIdx++] = NULL;
+
+ if (g_cVerbosity > 3)
+ {
+ VBoxServiceVerbose(4, "Forking parameters:\n");
+
+ iOptIdx = 0;
+ while (papszArgs[iOptIdx])
+ VBoxServiceVerbose(4, "\t%s\n", papszArgs[iOptIdx++]);
+ }
+
+ uint32_t uProcFlags = RTPROC_FLAGS_SERVICE
+ | RTPROC_FLAGS_HIDDEN; /** @todo More flags from startup info? */
+
+#if 0 /* Pipe handling not needed (yet). */
+ /* Setup pipes. */
+ rc = GstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
+ &pSession->StdIn.hChild, &pSession->StdIn.phChild, &pSession->hStdInW);
+ if (RT_SUCCESS(rc))
+ {
+ rc = GstcntlProcessSetupPipe("|", 1 /*STDOUT_FILENO*/,
+ &pSession->StdOut.hChild, &pSession->StdOut.phChild, &pSession->hStdOutR);
+ if (RT_SUCCESS(rc))
+ {
+ rc = GstcntlProcessSetupPipe("|", 2 /*STDERR_FILENO*/,
+ &pSession->StdErr.hChild, &pSession->StdErr.phChild, &pSession->hStdErrR);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTPollSetCreate(&pSession->hPollSet);
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdInW, RTPOLL_EVT_ERROR,
+ VBOXSERVICECTRLPIPEID_STDIN);
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdOutR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
+ VBOXSERVICECTRLPIPEID_STDOUT);
+ if (RT_SUCCESS(rc))
+ rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdErrR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
+ VBOXSERVICECTRLPIPEID_STDERR);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Fork the thing. */
+ /** @todo Do we need a custom environment block? */
+ rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags,
+ pSession->StdIn.phChild, pSession->StdOut.phChild, pSession->StdErr.phChild,
+ !fAnonymous ? pSession->StartupInfo.szUser : NULL,
+ !fAnonymous ? pSession->StartupInfo.szPassword : NULL,
+ &pSession->hProcess);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Close the child ends of any pipes and redirected files.
+ */
+ int rc2 = RTHandleClose(pSession->StdIn.phChild); AssertRC(rc2);
+ pSession->StdIn.phChild = NULL;
+ rc2 = RTHandleClose(pSession->StdOut.phChild); AssertRC(rc2);
+ pSession->StdOut.phChild = NULL;
+ rc2 = RTHandleClose(pSession->StdErr.phChild); AssertRC(rc2);
+ pSession->StdErr.phChild = NULL;
+ }
+ }
+ }
+#else
+ RTHANDLE hStdIn;
+ if (RT_SUCCESS(rc))
+ rc = RTFileOpenBitBucket(&hStdIn.u.hFile, RTFILE_O_READ);
+ if (RT_SUCCESS(rc))
+ {
+ hStdIn.enmType = RTHANDLETYPE_FILE;
+
+ RTHANDLE hStdOutAndErr;
+ rc = RTFileOpenBitBucket(&hStdOutAndErr.u.hFile, RTFILE_O_WRITE);
+ if (RT_SUCCESS(rc))
+ {
+ hStdOutAndErr.enmType = RTHANDLETYPE_FILE;
+
+ /** @todo Set custom/cloned guest session environment block. */
+ rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags,
+ &hStdIn, &hStdOutAndErr, &hStdOutAndErr,
+ !fAnonymous ? pSessionThread->StartupInfo.szUser : NULL,
+ !fAnonymous ? pSessionThread->StartupInfo.szPassword : NULL,
+ &pSessionThread->hProcess);
+
+ RTFileClose(hStdOutAndErr.u.hFile);
+ }
+
+ RTFileClose(hStdIn.u.hFile);
+ }
+#endif
+ }
+ }
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Start session thread. */
+ rc = RTThreadCreateF(&pSessionThread->Thread, gstcntlSessionThread,
+ pSessionThread /*pvUser*/, 0 /*cbStack*/,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "sess%u", s_uCtrlSessionThread);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Creating session thread failed, rc=%Rrc\n", rc);
+ }
+ else
+ {
+ /* Wait for the thread to initialize. */
+ rc = RTThreadUserWait(pSessionThread->Thread, 60 * 1000 /* 60s timeout */);
+ if ( ASMAtomicReadBool(&pSessionThread->fShutdown)
+ || RT_FAILURE(rc))
+ {
+ VBoxServiceError("Thread for session ID=%RU32 failed to start, rc=%Rrc\n",
+ pSessionThread->StartupInfo.uSessionID, rc);
+ if (RT_SUCCESS(rc))
+ rc = VERR_CANT_CREATE; /** @todo Find a better rc. */
+ }
+ else
+ {
+ VBoxServiceVerbose(2, "Thread for session ID=%RU32 started\n",
+ pSessionThread->StartupInfo.uSessionID);
+
+ ASMAtomicXchgBool(&pSessionThread->fStarted, true);
+
+ /* Add session to list. */
+ /* rc = */ RTListAppend(pList, &pSessionThread->Node);
+ if (ppSessionThread) /* Return session if wanted. */
+ *ppSessionThread = pSessionThread;
+ }
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(pSessionThread);
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ VBoxServiceVerbose(3, "Forking session thread returned returned rc=%Rrc\n", rc);
+ return rc;
+}
+
+
+/**
+ * Waits for a formerly opened guest session process to close.
+ *
+ * @return IPRT status code.
+ * @param pThread Guest session thread to wait for.
+ * @param uTimeoutMS Waiting timeout (in ms).
+ * @param uFlags Closing flags.
+ */
+int GstCntlSessionThreadWait(PVBOXSERVICECTRLSESSIONTHREAD pThread,
+ uint32_t uTimeoutMS, uint32_t uFlags)
+{
+ AssertPtrReturn(pThread, VERR_INVALID_POINTER);
+ /** @todo Validate closing flags. */
+
+ if (pThread->Thread == NIL_RTTHREAD)
+ {
+ AssertMsgFailed(("Guest session thread of session %p does not exist when it should\n",
+ pThread));
+ return VERR_NOT_FOUND;
+ }
+
+ int rc = VINF_SUCCESS;
+
+ /*
+ * The fork should have received the same closing request,
+ * so just wait for the process to close.
+ */
+ if (ASMAtomicReadBool(&pThread->fStarted))
+ {
+ /* Ask the thread to shutdown. */
+ ASMAtomicXchgBool(&pThread->fShutdown, true);
+
+ VBoxServiceVerbose(3, "Waiting for session thread ID=%RU32 to close (%RU32ms) ...\n",
+ pThread->StartupInfo.uSessionID, uTimeoutMS);
+
+ int rcThread;
+ rc = RTThreadWait(pThread->Thread, uTimeoutMS, &rcThread);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("Waiting for session thread ID=%RU32 to close failed with rc=%Rrc\n",
+ pThread->StartupInfo.uSessionID, rc);
+ }
+ else
+ VBoxServiceVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n",
+ pThread->StartupInfo.uSessionID, rcThread);
+ }
+
+ return rc;
+}
+
+/**
+ * Waits for the specified session thread to end and remove
+ * it from the session thread list.
+ *
+ * @return IPRT status code.
+ * @param pThread Session thread to destroy.
+ * @param uFlags Closing flags.
+ */
+int GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uFlags)
+{
+ AssertPtrReturn(pThread, VERR_INVALID_POINTER);
+
+ int rc = GstCntlSessionThreadWait(pThread,
+ 5 * 60 * 1000 /* 5 minutes timeout */, uFlags);
+
+ /* Remove session from list and destroy object. */
+ RTListNodeRemove(&pThread->Node);
+
+ RTMemFree(pThread);
+ pThread = NULL;
+
+ return rc;
+}
+
+/**
+ * Close all formerly opened guest session threads.
+ * Note: Caller is responsible for locking!
+ *
+ * @return IPRT status code.
+ * @param pList Which list to close the session threads for.
+ * @param uFlags Closing flags.
+ */
+int GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags)
+{
+ AssertPtrReturn(pList, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ /*int rc = VbglR3GuestCtrlClose
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Cancelling pending waits failed; rc=%Rrc\n", rc);*/
+
+ PVBOXSERVICECTRLSESSIONTHREAD pSessionThread
+ = RTListGetFirst(pList, VBOXSERVICECTRLSESSIONTHREAD, Node);
+ while (pSessionThread)
+ {
+ PVBOXSERVICECTRLSESSIONTHREAD pSessionThreadNext =
+ RTListGetNext(pList, pSessionThread, VBOXSERVICECTRLSESSIONTHREAD, Node);
+ bool fLast = RTListNodeIsLast(pList, &pSessionThread->Node);
+
+ int rc2 = GstCntlSessionThreadDestroy(pSessionThread, uFlags);
+ if (RT_FAILURE(rc2))
+ {
+ VBoxServiceError("Closing session thread failed with rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ /* Keep going. */
+ }
+
+ if (fLast)
+ break;
+
+ pSessionThread = pSessionThreadNext;
+ }
+
+ return rc;
+}
+
+RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv)
+{
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+#ifdef DEBUG
+ { "--dump-stdout", VBOXSERVICESESSIONOPT_DUMP_STDOUT, RTGETOPT_REQ_NOTHING },
+ { "--dump-stderr", VBOXSERVICESESSIONOPT_DUMP_STDERR, RTGETOPT_REQ_NOTHING },
+#endif
+ { "--logfile", VBOXSERVICESESSIONOPT_LOG_FILE, RTGETOPT_REQ_STRING },
+ { "--user", VBOXSERVICESESSIONOPT_USERNAME, RTGETOPT_REQ_STRING },
+ { "--session-id", VBOXSERVICESESSIONOPT_SESSION_ID, RTGETOPT_REQ_UINT32 },
+ { "--session-proto", VBOXSERVICESESSIONOPT_SESSION_PROTO, RTGETOPT_REQ_UINT32 },
+#ifdef DEBUG
+ { "--thread-id", VBOXSERVICESESSIONOPT_THREAD_ID, RTGETOPT_REQ_UINT32 },
+#endif /* DEBUG */
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, argc, argv,
+ s_aOptions, RT_ELEMENTS(s_aOptions),
+ 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ uint32_t uSessionFlags = VBOXSERVICECTRLSESSION_FLAG_FORK;
+
+ /* Protocol and session ID must be specified explicitly. */
+ g_Session.StartupInfo.uProtocol = UINT32_MAX;
+ g_Session.StartupInfo.uSessionID = UINT32_MAX;
+
+ int rc = VINF_SUCCESS;
+
+ while ( (ch = RTGetOpt(&GetState, &ValueUnion))
+ && RT_SUCCESS(rc))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case VBOXSERVICESESSIONOPT_LOG_FILE:
+ if (!RTStrPrintf(g_szLogFile, sizeof(g_szLogFile), "%s", ValueUnion.psz))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unable to set logfile name to '%s'",
+ ValueUnion.psz);
+ break;
+#ifdef DEBUG
+ case VBOXSERVICESESSIONOPT_DUMP_STDOUT:
+ uSessionFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT;
+ break;
+
+ case VBOXSERVICESESSIONOPT_DUMP_STDERR:
+ uSessionFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR;
+ break;
+#endif
+ case VBOXSERVICESESSIONOPT_USERNAME:
+ /** @todo Information not needed right now, skip. */
+ break;
+
+ case VBOXSERVICESESSIONOPT_SESSION_ID:
+ g_Session.StartupInfo.uSessionID = ValueUnion.u32;
+ break;
+
+ case VBOXSERVICESESSIONOPT_SESSION_PROTO:
+ g_Session.StartupInfo.uProtocol = ValueUnion.u32;
+ break;
+
+#ifdef DEBUG
+ case VBOXSERVICESESSIONOPT_THREAD_ID:
+ /* Not handled. */
+ break;
+#endif
+ /** @todo Implement help? */
+
+ case 'v':
+ g_cVerbosity++;
+ break;
+
+ case VINF_GETOPT_NOT_OPTION:
+ /* Ignore; might be "guestsession" main command. */
+ break;
+
+ default:
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown command '%s'", ValueUnion.psz);
+ break; /* Never reached. */
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Initialization failed with rc=%Rrc", rc);
+
+ if (g_Session.StartupInfo.uProtocol == UINT32_MAX)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No protocol version specified");
+
+ if (g_Session.StartupInfo.uSessionID == UINT32_MAX)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No session ID specified");
+
+ /* Init the session object. */
+ rc = GstCntlSessionInit(&g_Session, uSessionFlags);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize session object, rc=%Rrc\n", rc);
+
+ rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
+ strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);
+
+ RTEXITCODE rcExit = gstcntlSessionForkWorker(&g_Session);
+
+ VBoxServiceLogDestroy();
+ return rcExit;
+}
+
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp
deleted file mode 100644
index 78ec20a8..00000000
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp
+++ /dev/null
@@ -1,1794 +0,0 @@
-/* $Id: VBoxServiceControlThread.cpp $ */
-/** @file
- * VBoxServiceControlExecThread - Thread for every started guest process.
- */
-
-/*
- * Copyright (C) 2012 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/env.h>
-#include <iprt/file.h>
-#include <iprt/getopt.h>
-#include <iprt/handle.h>
-#include <iprt/mem.h>
-#include <iprt/path.h>
-#include <iprt/pipe.h>
-#include <iprt/poll.h>
-#include <iprt/process.h>
-#include <iprt/semaphore.h>
-#include <iprt/string.h>
-#include <iprt/thread.h>
-
-#include <VBox/VBoxGuestLib.h>
-#include <VBox/HostServices/GuestControlSvc.h>
-
-#include "VBoxServiceInternal.h"
-
-using namespace guestControl;
-
-/* Internal functions. */
-static int vboxServiceControlThreadRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
-
-/**
- * Initialies the passed in thread data structure with the parameters given.
- *
- * @return IPRT status code.
- * @param pThread The thread's handle to allocate the data for.
- * @param u32ContextID The context ID bound to this request / command.
- @ @param pProcess Process information.
- */
-static int gstsvcCntlExecThreadInit(PVBOXSERVICECTRLTHREAD pThread,
- PVBOXSERVICECTRLPROCESS pProcess,
- uint32_t u32ContextID)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
-
- /* General stuff. */
- pThread->pAnchor = NULL;
- pThread->Node.pPrev = NULL;
- pThread->Node.pNext = NULL;
-
- pThread->fShutdown = false;
- pThread->fStarted = false;
- pThread->fStopped = false;
-
- pThread->uContextID = u32ContextID;
- /* ClientID will be assigned when thread is started; every guest
- * process has its own client ID to detect crashes on a per-guest-process
- * level. */
-
- int rc = RTCritSectInit(&pThread->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- pThread->uPID = 0; /* Don't have a PID yet. */
- pThread->pRequest = NULL; /* No request assigned yet. */
- pThread->uFlags = pProcess->uFlags;
- pThread->uTimeLimitMS = ( pProcess->uTimeLimitMS == UINT32_MAX
- || pProcess->uTimeLimitMS == 0)
- ? RT_INDEFINITE_WAIT : pProcess->uTimeLimitMS;
-
- /* Prepare argument list. */
- pThread->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
- rc = RTGetOptArgvFromString(&pThread->papszArgs, (int*)&pThread->uNumArgs,
- (pProcess->uNumArgs > 0) ? pProcess->szArgs : "", NULL);
- /* Did we get the same result? */
- Assert(pProcess->uNumArgs == pThread->uNumArgs);
-
- if (RT_SUCCESS(rc))
- {
- /* Prepare environment list. */
- pThread->uNumEnvVars = 0;
- if (pProcess->uNumEnvVars)
- {
- pThread->papszEnv = (char **)RTMemAlloc(pProcess->uNumEnvVars * sizeof(char*));
- AssertPtr(pThread->papszEnv);
- pThread->uNumEnvVars = pProcess->uNumEnvVars;
-
- const char *pszCur = pProcess->szEnv;
- uint32_t i = 0;
- uint32_t cbLen = 0;
- while (cbLen < pProcess->cbEnv)
- {
- /* sanity check */
- if (i >= pProcess->uNumEnvVars)
- {
- rc = VERR_INVALID_PARAMETER;
- break;
- }
- int cbStr = RTStrAPrintf(&pThread->papszEnv[i++], "%s", pszCur);
- if (cbStr < 0)
- {
- rc = VERR_NO_STR_MEMORY;
- break;
- }
- pszCur += cbStr + 1; /* Skip terminating '\0' */
- cbLen += cbStr + 1; /* Skip terminating '\0' */
- }
- Assert(i == pThread->uNumEnvVars);
- }
-
- /* The actual command to execute. */
- pThread->pszCmd = RTStrDup(pProcess->szCmd);
- AssertPtr(pThread->pszCmd);
-
- /* User management. */
- pThread->pszUser = RTStrDup(pProcess->szUser);
- AssertPtr(pThread->pszUser);
- pThread->pszPassword = RTStrDup(pProcess->szPassword);
- AssertPtr(pThread->pszPassword);
- }
-
- if (RT_FAILURE(rc)) /* Clean up on failure. */
- VBoxServiceControlThreadFree(pThread);
- return rc;
-}
-
-
-/**
- * Frees a guest thread.
- *
- * @return IPRT status code.
- * @param pThread Thread to shut down.
- */
-int VBoxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-
- VBoxServiceVerbose(3, "[PID %u]: Freeing ...\n",
- pThread->uPID);
-
- int rc = RTCritSectEnter(&pThread->CritSect);
- if (RT_SUCCESS(rc))
- {
- if (pThread->uNumEnvVars)
- {
- for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
- RTStrFree(pThread->papszEnv[i]);
- RTMemFree(pThread->papszEnv);
- }
- RTGetOptArgvFree(pThread->papszArgs);
-
- RTStrFree(pThread->pszCmd);
- RTStrFree(pThread->pszUser);
- RTStrFree(pThread->pszPassword);
-
- VBoxServiceVerbose(3, "[PID %u]: Setting stopped state\n",
- pThread->uPID);
-
- rc = RTCritSectLeave(&pThread->CritSect);
- AssertRC(rc);
- }
-
- /*
- * Destroy other thread data.
- */
- if (RTCritSectIsInitialized(&pThread->CritSect))
- RTCritSectDelete(&pThread->CritSect);
-
- /*
- * Destroy thread structure as final step.
- */
- RTMemFree(pThread);
- pThread = NULL;
-
- return rc;
-}
-
-
-/**
- * Signals a guest process thread that we want it to shut down in
- * a gentle way.
- *
- * @return IPRT status code.
- * @param pThread Thread to shut down.
- */
-int VBoxServiceControlThreadStop(const PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-
- VBoxServiceVerbose(3, "[PID %u]: Stopping ...\n",
- pThread->uPID);
-
- int rc = vboxServiceControlThreadRequestCancel(pThread->pRequest);
- if (RT_FAILURE(rc))
- VBoxServiceError("[PID %u]: Signalling request event failed, rc=%Rrc\n",
- pThread->uPID, rc);
-
- /* Do *not* set pThread->fShutdown or other stuff here!
- * The guest thread loop will do that as soon as it processes the quit message. */
-
- PVBOXSERVICECTRLREQUEST pRequest;
- rc = VBoxServiceControlThreadRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT);
- if (RT_SUCCESS(rc))
- {
- rc = VBoxServiceControlThreadPerform(pThread->uPID, pRequest);
- if (RT_FAILURE(rc))
- VBoxServiceVerbose(3, "[PID %u]: Sending quit request failed with rc=%Rrc\n",
- pThread->uPID, rc);
-
- VBoxServiceControlThreadRequestFree(pRequest);
- }
- return rc;
-}
-
-
-/**
- * Wait for a guest process thread to shut down.
- *
- * @return IPRT status code.
- * @param pThread Thread to wait shutting down for.
- * @param RTMSINTERVAL Timeout in ms to wait for shutdown.
- * @param prc Where to store the thread's return code. Optional.
- */
-int VBoxServiceControlThreadWait(const PVBOXSERVICECTRLTHREAD pThread,
- RTMSINTERVAL msTimeout, int *prc)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- /* prc is optional. */
-
- int rc = VINF_SUCCESS;
- if ( pThread->Thread != NIL_RTTHREAD
- && ASMAtomicReadBool(&pThread->fStarted))
- {
- VBoxServiceVerbose(2, "[PID %u]: Waiting for shutdown of pThread=0x%p = \"%s\"...\n",
- pThread->uPID, pThread, pThread->pszCmd);
-
- /* Wait a bit ... */
- int rcThread;
- rc = RTThreadWait(pThread->Thread, msTimeout, &rcThread);
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("[PID %u]: Waiting for shutting down thread returned error rc=%Rrc\n",
- pThread->uPID, rc);
- }
- else
- {
- VBoxServiceVerbose(3, "[PID %u]: Thread reported exit code=%Rrc\n",
- pThread->uPID, rcThread);
- if (prc)
- *prc = rcThread;
- }
- }
- return rc;
-}
-
-
-/**
- * Closes the stdin pipe of a guest process.
- *
- * @return IPRT status code.
- * @param hPollSet The polling set.
- * @param phStdInW The standard input pipe handle.
- */
-static int VBoxServiceControlThreadCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW)
-{
- AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
-
- int rc = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN);
- if (rc != VERR_POLL_HANDLE_ID_NOT_FOUND)
- AssertRC(rc);
-
- if (*phStdInW != NIL_RTPIPE)
- {
- rc = RTPipeClose(*phStdInW);
- AssertRC(rc);
- *phStdInW = NIL_RTPIPE;
- }
-
- return rc;
-}
-
-
-/**
- * Handle an error event on standard input.
- *
- * @return IPRT status code.
- * @param hPollSet The polling set.
- * @param fPollEvt The event mask returned by RTPollNoResume.
- * @param phStdInW The standard input pipe handle.
- */
-static int VBoxServiceControlThreadHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)
-{
- NOREF(fPollEvt);
-
- return VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW);
-}
-
-
-/**
- * Handle pending output data or error on standard out or standard error.
- *
- * @returns IPRT status code from client send.
- * @param hPollSet The polling set.
- * @param fPollEvt The event mask returned by RTPollNoResume.
- * @param phPipeR The pipe handle.
- * @param idPollHnd The pipe ID to handle.
- *
- */
-static int VBoxServiceControlThreadHandleOutputError(RTPOLLSET hPollSet, uint32_t fPollEvt,
- PRTPIPE phPipeR, uint32_t idPollHnd)
-{
- AssertPtrReturn(phPipeR, VERR_INVALID_POINTER);
-
-#ifdef DEBUG
- VBoxServiceVerbose(4, "VBoxServiceControlThreadHandleOutputError: fPollEvt=0x%x, idPollHnd=%u\n",
- fPollEvt, idPollHnd);
-#endif
-
- /* Remove pipe from poll set. */
- int rc2 = RTPollSetRemove(hPollSet, idPollHnd);
- AssertMsg(RT_SUCCESS(rc2) || rc2 == VERR_POLL_HANDLE_ID_NOT_FOUND, ("%Rrc\n", rc2));
-
- bool fClosePipe = true; /* By default close the pipe. */
-
- /* Check if there's remaining data to read from the pipe. */
- size_t cbReadable;
- rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable);
- if ( RT_SUCCESS(rc2)
- && cbReadable)
- {
- VBoxServiceVerbose(3, "VBoxServiceControlThreadHandleOutputError: idPollHnd=%u has %ld bytes left, vetoing close\n",
- idPollHnd, cbReadable);
-
- /* Veto closing the pipe yet because there's still stuff to read
- * from the pipe. This can happen on UNIX-y systems where on
- * error/hangup there still can be data to be read out. */
- fClosePipe = false;
- }
- else
- VBoxServiceVerbose(3, "VBoxServiceControlThreadHandleOutputError: idPollHnd=%u will be closed\n",
- idPollHnd);
-
- if ( *phPipeR != NIL_RTPIPE
- && fClosePipe)
- {
- rc2 = RTPipeClose(*phPipeR);
- AssertRC(rc2);
- *phPipeR = NIL_RTPIPE;
- }
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Handle pending output data or error on standard out or standard error.
- *
- * @returns IPRT status code from client send.
- * @param hPollSet The polling set.
- * @param fPollEvt The event mask returned by RTPollNoResume.
- * @param phPipeR The pipe handle.
- * @param idPollHnd The pipe ID to handle.
- *
- */
-static int VBoxServiceControlThreadHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,
- PRTPIPE phPipeR, uint32_t idPollHnd)
-{
-#if 0
- VBoxServiceVerbose(4, "VBoxServiceControlThreadHandleOutputEvent: fPollEvt=0x%x, idPollHnd=%u\n",
- fPollEvt, idPollHnd);
-#endif
-
- int rc = VINF_SUCCESS;
-
-#ifdef DEBUG
- size_t cbReadable;
- rc = RTPipeQueryReadable(*phPipeR, &cbReadable);
- if ( RT_SUCCESS(rc)
- && cbReadable)
- {
- VBoxServiceVerbose(4, "VBoxServiceControlThreadHandleOutputEvent: cbReadable=%ld\n",
- cbReadable);
- }
-#endif
-
-#if 0
- //if (fPollEvt & RTPOLL_EVT_READ)
- {
- size_t cbRead = 0;
- uint8_t byData[_64K];
- rc = RTPipeRead(*phPipeR,
- byData, sizeof(byData), &cbRead);
- VBoxServiceVerbose(4, "VBoxServiceControlThreadHandleOutputEvent cbRead=%u, rc=%Rrc\n",
- cbRead, rc);
-
- /* Make sure we go another poll round in case there was too much data
- for the buffer to hold. */
- fPollEvt &= RTPOLL_EVT_ERROR;
- }
-#endif
-
- if (fPollEvt & RTPOLL_EVT_ERROR)
- rc = VBoxServiceControlThreadHandleOutputError(hPollSet, fPollEvt,
- phPipeR, idPollHnd);
- return rc;
-}
-
-
-static int VBoxServiceControlThreadHandleRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
- PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
- PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
- AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER);
- AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER);
-
- /* Drain the notification pipe. */
- uint8_t abBuf[8];
- size_t cbIgnore;
- int rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
- if (RT_FAILURE(rc))
- VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc);
-
- int rcReq = VINF_SUCCESS; /* Actual request result. */
-
- PVBOXSERVICECTRLREQUEST pRequest = pThread->pRequest;
- if (!pRequest)
- {
- VBoxServiceError("IPC request is invalid\n");
- return VERR_INVALID_POINTER;
- }
-
- switch (pRequest->enmType)
- {
- case VBOXSERVICECTRLREQUEST_QUIT: /* Main control asked us to quit. */
- {
- /** @todo Check for some conditions to check to
- * veto quitting. */
- ASMAtomicXchgBool(&pThread->fShutdown, true);
- rcReq = VERR_CANCELLED;
- break;
- }
-
- case VBOXSERVICECTRLREQUEST_STDIN_WRITE:
- case VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF:
- {
- size_t cbWritten = 0;
- if (pRequest->cbData)
- {
- AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
- if (*phStdInW != NIL_RTPIPE)
- {
- rcReq = RTPipeWrite(*phStdInW,
- pRequest->pvData, pRequest->cbData, &cbWritten);
- }
- else
- rcReq = VINF_EOF;
- }
-
- /*
- * If this is the last write + we have really have written all data
- * we need to close the stdin pipe on our end and remove it from
- * the poll set.
- */
- if ( pRequest->enmType == VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF
- && pRequest->cbData == cbWritten)
- {
- rc = VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW);
- }
-
- /* Report back actual data written (if any). */
- pRequest->cbData = cbWritten;
- break;
- }
-
- case VBOXSERVICECTRLREQUEST_STDOUT_READ:
- case VBOXSERVICECTRLREQUEST_STDERR_READ:
- {
- AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
- AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
-
- PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ
- ? phStdErrR : phStdOutR;
- AssertPtr(pPipeR);
-
- size_t cbRead = 0;
- if (*pPipeR != NIL_RTPIPE)
- {
- rcReq = RTPipeRead(*pPipeR,
- pRequest->pvData, pRequest->cbData, &cbRead);
- if (RT_FAILURE(rcReq))
- {
- RTPollSetRemove(hPollSet, pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ
- ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT);
- RTPipeClose(*pPipeR);
- *pPipeR = NIL_RTPIPE;
- if (rcReq == VERR_BROKEN_PIPE)
- rcReq = VINF_EOF;
- }
- }
- else
- rcReq = VINF_EOF;
-
- /* Report back actual data read (if any). */
- pRequest->cbData = cbRead;
- break;
- }
-
- default:
- rcReq = VERR_NOT_IMPLEMENTED;
- break;
- }
-
- /* Assign overall result. */
- pRequest->rc = RT_SUCCESS(rc)
- ? rcReq : rc;
-
- VBoxServiceVerbose(2, "[PID %u]: Handled req=%u, CID=%u, rc=%Rrc, cbData=%u\n",
- pThread->uPID, pRequest->enmType, pRequest->uCID, pRequest->rc, pRequest->cbData);
-
- /* In any case, regardless of the result, we notify
- * the main guest control to unblock it. */
- int rc2 = RTSemEventMultiSignal(pRequest->Event);
- AssertRC(rc2);
-
- /* No access to pRequest here anymore -- could be out of scope
- * or modified already! */
- pThread->pRequest = pRequest = NULL;
-
- return rc;
-}
-
-
-/**
- * Execution loop which runs in a dedicated per-started-process thread and
- * handles all pipe input/output and signalling stuff.
- *
- * @return IPRT status code.
- * @param pThread The process' thread handle.
- * @param hProcess The actual process handle.
- * @param cMsTimeout Time limit (in ms) of the process' life time.
- * @param hPollSet The poll set to use.
- * @param hStdInW Handle to the process' stdin write end.
- * @param hStdOutR Handle to the process' stdout read end.
- * @param hStdErrR Handle to the process' stderr read end.
- */
-static int VBoxServiceControlThreadProcLoop(PVBOXSERVICECTRLTHREAD pThread,
- RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet,
- PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER);
- /* Rest is optional. */
-
- int rc;
- int rc2;
- uint64_t const MsStart = RTTimeMilliTS();
- RTPROCSTATUS ProcessStatus = { 254, RTPROCEXITREASON_ABEND };
- bool fProcessAlive = true;
- bool fProcessTimedOut = false;
- uint64_t MsProcessKilled = UINT64_MAX;
- RTMSINTERVAL const cMsPollBase = *phStdInW != NIL_RTPIPE
- ? 100 /* Need to poll for input. */
- : 1000; /* Need only poll for process exit and aborts. */
- RTMSINTERVAL cMsPollCur = 0;
-
- /*
- * Assign PID to thread data.
- * Also check if there already was a thread with the same PID and shut it down -- otherwise
- * the first (stale) entry will be found and we get really weird results!
- */
- rc = VBoxServiceControlAssignPID(pThread, hProcess);
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("Unable to assign PID=%u, to new thread, rc=%Rrc\n",
- hProcess, rc);
- return rc;
- }
-
- /*
- * Before entering the loop, tell the host that we've started the guest
- * and that it's now OK to send input to the process.
- */
- VBoxServiceVerbose(2, "[PID %u]: Process \"%s\" started, CID=%u, User=%s\n",
- pThread->uPID, pThread->pszCmd, pThread->uContextID, pThread->pszUser);
- rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
- pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
- NULL /* pvData */, 0 /* cbData */);
-
- /*
- * Process input, output, the test pipe and client requests.
- */
- while ( RT_SUCCESS(rc)
- && RT_UNLIKELY(!pThread->fShutdown))
- {
- /*
- * Wait/Process all pending events.
- */
- uint32_t idPollHnd;
- uint32_t fPollEvt;
- rc2 = RTPollNoResume(hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
- if (pThread->fShutdown)
- continue;
-
- cMsPollCur = 0; /* No rest until we've checked everything. */
-
- if (RT_SUCCESS(rc2))
- {
- /*VBoxServiceVerbose(4, "[PID %u}: RTPollNoResume idPollHnd=%u\n",
- pThread->uPID, idPollHnd);*/
- switch (idPollHnd)
- {
- case VBOXSERVICECTRLPIPEID_STDIN:
- rc = VBoxServiceControlThreadHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW);
- break;
-
- case VBOXSERVICECTRLPIPEID_STDOUT:
- rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt,
- phStdOutR, idPollHnd);
- break;
-
- case VBOXSERVICECTRLPIPEID_STDERR:
- rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt,
- phStdErrR, idPollHnd);
- break;
-
- case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
- rc = VBoxServiceControlThreadHandleRequest(hPollSet, fPollEvt,
- phStdInW, phStdOutR, phStdErrR, pThread);
- break;
- }
-
- if (RT_FAILURE(rc) || rc == VINF_EOF)
- break; /* Abort command, or client dead or something. */
-
- if (RT_UNLIKELY(pThread->fShutdown))
- break; /* We were asked to shutdown. */
-
- continue;
- }
-
-#if 0
- VBoxServiceVerbose(4, "[PID %u]: Polling done, pollRC=%Rrc, pollCnt=%u, rc=%Rrc, fShutdown=%RTbool\n",
- pThread->uPID, rc2, RTPollSetGetCount(hPollSet), rc, pThread->fShutdown);
-#endif
- /*
- * Check for process death.
- */
- if (fProcessAlive)
- {
- rc2 = RTProcWaitNoResume(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
- if (RT_SUCCESS_NP(rc2))
- {
- fProcessAlive = false;
- continue;
- }
- if (RT_UNLIKELY(rc2 == VERR_INTERRUPTED))
- continue;
- if (RT_UNLIKELY(rc2 == VERR_PROCESS_NOT_FOUND))
- {
- fProcessAlive = false;
- ProcessStatus.enmReason = RTPROCEXITREASON_ABEND;
- ProcessStatus.iStatus = 255;
- AssertFailed();
- }
- else
- AssertMsg(rc2 == VERR_PROCESS_RUNNING, ("%Rrc\n", rc2));
- }
-
- /*
- * If the process has terminated and all output has been consumed,
- * we should be heading out.
- */
- if ( !fProcessAlive
- && *phStdOutR == NIL_RTPIPE
- && *phStdErrR == NIL_RTPIPE)
- break;
-
- /*
- * Check for timed out, killing the process.
- */
- uint32_t cMilliesLeft = RT_INDEFINITE_WAIT;
- if (cMsTimeout != RT_INDEFINITE_WAIT)
- {
- uint64_t u64Now = RTTimeMilliTS();
- uint64_t cMsElapsed = u64Now - MsStart;
- if (cMsElapsed >= cMsTimeout)
- {
- VBoxServiceVerbose(3, "[PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...",
- pThread->uPID, cMsElapsed, cMsTimeout);
-
- fProcessTimedOut = true;
- if ( MsProcessKilled == UINT64_MAX
- || u64Now - MsProcessKilled > 1000)
- {
- if (u64Now - MsProcessKilled > 20*60*1000)
- break; /* Give up after 20 mins. */
- RTProcTerminate(hProcess);
- MsProcessKilled = u64Now;
- continue;
- }
- cMilliesLeft = 10000;
- }
- else
- cMilliesLeft = cMsTimeout - (uint32_t)cMsElapsed;
- }
-
- /* Reset the polling interval since we've done all pending work. */
- cMsPollCur = fProcessAlive
- ? cMsPollBase
- : RT_MS_1MIN;
- if (cMilliesLeft < cMsPollCur)
- cMsPollCur = cMilliesLeft;
-
- /*
- * Need to exit?
- */
- if (pThread->fShutdown)
- break;
- }
-
- rc2 = RTCritSectEnter(&pThread->CritSect);
- if (RT_SUCCESS(rc2))
- {
- ASMAtomicXchgBool(&pThread->fShutdown, true);
-
- rc2 = RTCritSectLeave(&pThread->CritSect);
- AssertRC(rc2);
- }
-
- /*
- * Try kill the process if it's still alive at this point.
- */
- if (fProcessAlive)
- {
- if (MsProcessKilled == UINT64_MAX)
- {
- VBoxServiceVerbose(3, "[PID %u]: Is still alive and not killed yet\n",
- pThread->uPID);
-
- MsProcessKilled = RTTimeMilliTS();
- RTProcTerminate(hProcess);
- RTThreadSleep(500);
- }
-
- for (size_t i = 0; i < 10; i++)
- {
- VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Waiting to exit ...\n",
- pThread->uPID, i + 1);
- rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
- if (RT_SUCCESS(rc2))
- {
- VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Exited\n",
- pThread->uPID, i + 1);
- fProcessAlive = false;
- break;
- }
- if (i >= 5)
- {
- VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Trying to terminate ...\n",
- pThread->uPID, i + 1);
- RTProcTerminate(hProcess);
- }
- RTThreadSleep(i >= 5 ? 2000 : 500);
- }
-
- if (fProcessAlive)
- VBoxServiceVerbose(3, "[PID %u]: Could not be killed\n", pThread->uPID);
- }
-
- /*
- * If we don't have a client problem (RT_FAILURE(rc)) we'll reply to the
- * clients exec packet now.
- */
- if (RT_SUCCESS(rc))
- {
- uint32_t uStatus = PROC_STS_UNDEFINED;
- uint32_t uFlags = 0;
-
- if ( fProcessTimedOut && !fProcessAlive && MsProcessKilled != UINT64_MAX)
- {
- VBoxServiceVerbose(3, "[PID %u]: Timed out and got killed\n",
- pThread->uPID);
- uStatus = PROC_STS_TOK;
- }
- else if (fProcessTimedOut && fProcessAlive && MsProcessKilled != UINT64_MAX)
- {
- VBoxServiceVerbose(3, "[PID %u]: Timed out and did *not* get killed\n",
- pThread->uPID);
- uStatus = PROC_STS_TOA;
- }
- else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
- {
- VBoxServiceVerbose(3, "[PID %u]: Got terminated because system/service is about to shutdown\n",
- pThread->uPID);
- uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
- uFlags = pThread->uFlags; /* Return handed-in execution flags back to the host. */
- }
- else if (fProcessAlive)
- {
- VBoxServiceError("[PID %u]: Is alive when it should not!\n",
- pThread->uPID);
- }
- else if (MsProcessKilled != UINT64_MAX)
- {
- VBoxServiceError("[PID %u]: Has been killed when it should not!\n",
- pThread->uPID);
- }
- else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
- {
- VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",
- pThread->uPID, ProcessStatus.iStatus);
-
- uStatus = PROC_STS_TEN;
- uFlags = ProcessStatus.iStatus;
- }
- else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
- {
- VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",
- pThread->uPID, ProcessStatus.iStatus);
-
- uStatus = PROC_STS_TES;
- uFlags = ProcessStatus.iStatus;
- }
- else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
- {
- /* ProcessStatus.iStatus will be undefined. */
- VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_ABEND\n",
- pThread->uPID);
-
- uStatus = PROC_STS_TEA;
- uFlags = ProcessStatus.iStatus;
- }
- else
- VBoxServiceVerbose(1, "[PID %u]: Handling process status %u not implemented\n",
- pThread->uPID, ProcessStatus.enmReason);
-
- VBoxServiceVerbose(2, "[PID %u]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
- pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags);
- rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
- pThread->uPID, uStatus, uFlags,
- NULL /* pvData */, 0 /* cbData */);
- if (RT_FAILURE(rc))
- VBoxServiceError("[PID %u]: Error reporting final status to host; rc=%Rrc\n",
- pThread->uPID, rc);
-
- VBoxServiceVerbose(3, "[PID %u]: Process loop ended with rc=%Rrc\n",
- pThread->uPID, rc);
- }
- else
- VBoxServiceError("[PID %u]: Loop failed with rc=%Rrc\n",
- pThread->uPID, rc);
- return rc;
-}
-
-
-/**
- * Initializes a pipe's handle and pipe object.
- *
- * @return IPRT status code.
- * @param ph The pipe's handle to initialize.
- * @param phPipe The pipe's object to initialize.
- */
-static int vboxServiceControlThreadInitPipe(PRTHANDLE ph, PRTPIPE phPipe)
-{
- AssertPtrReturn(ph, VERR_INVALID_PARAMETER);
- AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER);
-
- ph->enmType = RTHANDLETYPE_PIPE;
- ph->u.hPipe = NIL_RTPIPE;
- *phPipe = NIL_RTPIPE;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Allocates a guest thread request with the specified request data.
- *
- * @return IPRT status code.
- * @param ppReq Pointer that will receive the newly allocated request.
- * Must be freed later with VBoxServiceControlThreadRequestFree().
- * @param enmType Request type.
- * @param pbData Payload data, based on request type.
- * @param cbData Size of payload data (in bytes).
- * @param uCID Context ID to which this request belongs to.
- */
-int VBoxServiceControlThreadRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq,
- VBOXSERVICECTRLREQUESTTYPE enmType,
- void* pbData,
- size_t cbData,
- uint32_t uCID)
-{
- AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
-
- PVBOXSERVICECTRLREQUEST pReq = (PVBOXSERVICECTRLREQUEST)
- RTMemAlloc(sizeof(VBOXSERVICECTRLREQUEST));
- AssertPtrReturn(pReq, VERR_NO_MEMORY);
-
- RT_ZERO(*pReq);
- pReq->enmType = enmType;
- pReq->uCID = uCID;
- pReq->cbData = cbData;
- pReq->pvData = (uint8_t*)pbData;
-
- /* Set request result to some defined state in case
- * it got cancelled. */
- pReq->rc = VERR_CANCELLED;
-
- int rc = RTSemEventMultiCreate(&pReq->Event);
- AssertRC(rc);
-
- if (RT_SUCCESS(rc))
- {
- *ppReq = pReq;
- return VINF_SUCCESS;
- }
-
- RTMemFree(pReq);
- return rc;
-}
-
-
-/**
- * Allocates a guest thread request with the specified request data.
- *
- * @return IPRT status code.
- * @param ppReq Pointer that will receive the newly allocated request.
- * Must be freed later with VBoxServiceControlThreadRequestFree().
- * @param enmType Request type.
- */
-int VBoxServiceControlThreadRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq,
- VBOXSERVICECTRLREQUESTTYPE enmType)
-{
- return VBoxServiceControlThreadRequestAllocEx(ppReq, enmType,
- NULL /* pvData */, 0 /* cbData */,
- 0 /* ContextID */);
-}
-
-
-/**
- * Cancels a previously fired off guest thread request.
- *
- * Note: Does *not* do locking since VBoxServiceControlThreadRequestWait()
- * holds the lock (critsect); so only trigger the signal; the owner
- * needs to clean up afterwards.
- *
- * @return IPRT status code.
- * @param pReq Request to cancel.
- */
-static int vboxServiceControlThreadRequestCancel(PVBOXSERVICECTRLREQUEST pReq)
-{
- if (!pReq) /* Silently skip non-initialized requests. */
- return VINF_SUCCESS;
-
- VBoxServiceVerbose(4, "Cancelling request=0x%p\n", pReq);
-
- return RTSemEventMultiSignal(pReq->Event);
-}
-
-
-/**
- * Frees a formerly allocated guest thread request.
- *
- * @return IPRT status code.
- * @param pReq Request to free.
- */
-void VBoxServiceControlThreadRequestFree(PVBOXSERVICECTRLREQUEST pReq)
-{
- AssertPtrReturnVoid(pReq);
-
- VBoxServiceVerbose(4, "Freeing request=0x%p (event=%RTsem)\n",
- pReq, &pReq->Event);
-
- int rc = RTSemEventMultiDestroy(pReq->Event);
- AssertRC(rc);
-
- RTMemFree(pReq);
- pReq = NULL;
-}
-
-
-/**
- * Waits for a guest thread's event to get triggered.
- *
- * @return IPRT status code.
- * @param pReq Request to wait for.
- */
-int VBoxServiceControlThreadRequestWait(PVBOXSERVICECTRLREQUEST pReq)
-{
- AssertPtrReturn(pReq, VERR_INVALID_POINTER);
-
- /* Wait on the request to get completed (or we are asked to abort/shutdown). */
- int rc = RTSemEventMultiWait(pReq->Event, RT_INDEFINITE_WAIT);
- if (RT_SUCCESS(rc))
- {
- VBoxServiceVerbose(4, "Performed request with rc=%Rrc, cbData=%u\n",
- pReq->rc, pReq->cbData);
-
- /* Give back overall request result. */
- rc = pReq->rc;
- }
- else
- VBoxServiceError("Waiting for request failed, rc=%Rrc\n", rc);
-
- return rc;
-}
-
-
-/**
- * Sets up the redirection / pipe / nothing for one of the standard handles.
- *
- * @returns IPRT status code. No client replies made.
- * @param pszHowTo How to set up this standard handle.
- * @param fd Which standard handle it is (0 == stdin, 1 ==
- * stdout, 2 == stderr).
- * @param ph The generic handle that @a pph may be set
- * pointing to. Always set.
- * @param pph Pointer to the RTProcCreateExec argument.
- * Always set.
- * @param phPipe Where to return the end of the pipe that we
- * should service.
- */
-static int VBoxServiceControlThreadSetupPipe(const char *pszHowTo, int fd,
- PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
-{
- AssertPtrReturn(ph, VERR_INVALID_POINTER);
- AssertPtrReturn(pph, VERR_INVALID_POINTER);
- AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
-
- int rc;
-
- ph->enmType = RTHANDLETYPE_PIPE;
- ph->u.hPipe = NIL_RTPIPE;
- *pph = NULL;
- *phPipe = NIL_RTPIPE;
-
- if (!strcmp(pszHowTo, "|"))
- {
- /*
- * Setup a pipe for forwarding to/from the client.
- * The ph union struct will be filled with a pipe read/write handle
- * to represent the "other" end to phPipe.
- */
- if (fd == 0) /* stdin? */
- {
- /* Connect a wrtie pipe specified by phPipe to stdin. */
- rc = RTPipeCreate(&ph->u.hPipe, phPipe, RTPIPE_C_INHERIT_READ);
- }
- else /* stdout or stderr? */
- {
- /* Connect a read pipe specified by phPipe to stdout or stderr. */
- rc = RTPipeCreate(phPipe, &ph->u.hPipe, RTPIPE_C_INHERIT_WRITE);
- }
-
- if (RT_FAILURE(rc))
- return rc;
-
- ph->enmType = RTHANDLETYPE_PIPE;
- *pph = ph;
- }
- else if (!strcmp(pszHowTo, "/dev/null"))
- {
- /*
- * Redirect to/from /dev/null.
- */
- RTFILE hFile;
- rc = RTFileOpenBitBucket(&hFile, fd == 0 ? RTFILE_O_READ : RTFILE_O_WRITE);
- if (RT_FAILURE(rc))
- return rc;
-
- ph->enmType = RTHANDLETYPE_FILE;
- ph->u.hFile = hFile;
- *pph = ph;
- }
- else /* Add other piping stuff here. */
- rc = VINF_SUCCESS; /* Same as parent (us). */
-
- return rc;
-}
-
-
-/**
- * Expands a file name / path to its real content. This only works on Windows
- * for now (e.g. translating "%TEMP%\foo.exe" to "C:\Windows\Temp" when starting
- * with system / administrative rights).
- *
- * @return IPRT status code.
- * @param pszPath Path to resolve.
- * @param pszExpanded Pointer to string to store the resolved path in.
- * @param cbExpanded Size (in bytes) of string to store the resolved path.
- */
-static int VBoxServiceControlThreadMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded)
-{
- int rc = VINF_SUCCESS;
-#ifdef RT_OS_WINDOWS
- if (!ExpandEnvironmentStrings(pszPath, pszExpanded, cbExpanded))
- rc = RTErrConvertFromWin32(GetLastError());
-#else
- /* No expansion for non-Windows yet. */
- rc = RTStrCopy(pszExpanded, cbExpanded, pszPath);
-#endif
-#ifdef DEBUG
- VBoxServiceVerbose(3, "VBoxServiceControlExecMakeFullPath: %s -> %s\n",
- pszPath, pszExpanded);
-#endif
- return rc;
-}
-
-
-/**
- * Resolves the full path of a specified executable name. This function also
- * resolves internal VBoxService tools to its appropriate executable path + name if
- * VBOXSERVICE_NAME is specified as pszFileName.
- *
- * @return IPRT status code.
- * @param pszFileName File name to resolve.
- * @param pszResolved Pointer to a string where the resolved file name will be stored.
- * @param cbResolved Size (in bytes) of resolved file name string.
- */
-static int VBoxServiceControlThreadResolveExecutable(const char *pszFileName,
- char *pszResolved, size_t cbResolved)
-{
- AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
- AssertPtrReturn(pszResolved, VERR_INVALID_POINTER);
- AssertReturn(cbResolved, VERR_INVALID_PARAMETER);
-
- int rc = VINF_SUCCESS;
-
- char szPathToResolve[RTPATH_MAX];
- if ( (g_pszProgName && (RTStrICmp(pszFileName, g_pszProgName) == 0))
- || !RTStrICmp(pszFileName, VBOXSERVICE_NAME))
- {
- /* Resolve executable name of this process. */
- if (!RTProcGetExecutablePath(szPathToResolve, sizeof(szPathToResolve)))
- rc = VERR_FILE_NOT_FOUND;
- }
- else
- {
- /* Take the raw argument to resolve. */
- rc = RTStrCopy(szPathToResolve, sizeof(szPathToResolve), pszFileName);
- }
-
- if (RT_SUCCESS(rc))
- {
- rc = VBoxServiceControlThreadMakeFullPath(szPathToResolve, pszResolved, cbResolved);
- if (RT_SUCCESS(rc))
- VBoxServiceVerbose(3, "Looked up executable: %s -> %s\n",
- pszFileName, pszResolved);
- }
-
- if (RT_FAILURE(rc))
- VBoxServiceError("Failed to lookup executable \"%s\" with rc=%Rrc\n",
- pszFileName, rc);
- return rc;
-}
-
-
-/**
- * Constructs the argv command line by resolving environment variables
- * and relative paths.
- *
- * @return IPRT status code.
- * @param pszArgv0 First argument (argv0), either original or modified version. Optional.
- * @param papszArgs Original argv command line from the host, starting at argv[1].
- * @param ppapszArgv Pointer to a pointer with the new argv command line.
- * Needs to be freed with RTGetOptArgvFree.
- */
-static int VBoxServiceControlThreadAllocateArgv(const char *pszArgv0,
- const char * const *papszArgs,
- bool fExpandArgs, char ***ppapszArgv)
-{
- AssertPtrReturn(ppapszArgv, VERR_INVALID_POINTER);
-
- VBoxServiceVerbose(3, "VBoxServiceControlThreadPrepareArgv: pszArgv0=%p, papszArgs=%p, fExpandArgs=%RTbool, ppapszArgv=%p\n",
- pszArgv0, papszArgs, fExpandArgs, ppapszArgv);
-
- int rc = VINF_SUCCESS;
- uint32_t cArgs;
- for (cArgs = 0; papszArgs[cArgs]; cArgs++)
- {
- if (cArgs >= UINT32_MAX - 2)
- return VERR_BUFFER_OVERFLOW;
- }
-
- /* Allocate new argv vector (adding + 2 for argv0 + termination). */
- size_t cbSize = (cArgs + 2) * sizeof(char*);
- char **papszNewArgv = (char**)RTMemAlloc(cbSize);
- if (!papszNewArgv)
- return VERR_NO_MEMORY;
-
-#ifdef DEBUG
- VBoxServiceVerbose(3, "VBoxServiceControlThreadPrepareArgv: cbSize=%RU32, cArgs=%RU32\n",
- cbSize, cArgs);
-#endif
-
- size_t i = 0; /* Keep the argument counter in scope for cleaning up on failure. */
-
- rc = RTStrDupEx(&papszNewArgv[0], pszArgv0);
- if (RT_SUCCESS(rc))
- {
- for (; i < cArgs; i++)
- {
- char *pszArg;
-#if 0 /* Arguments expansion -- untested. */
- if (fExpandArgs)
- {
- /* According to MSDN the limit on older Windows version is 32K, whereas
- * Vista+ there are no limits anymore. We still stick to 4K. */
- char szExpanded[_4K];
-# ifdef RT_OS_WINDOWS
- if (!ExpandEnvironmentStrings(papszArgs[i], szExpanded, sizeof(szExpanded)))
- rc = RTErrConvertFromWin32(GetLastError());
-# else
- /* No expansion for non-Windows yet. */
- rc = RTStrCopy(papszArgs[i], sizeof(szExpanded), szExpanded);
-# endif
- if (RT_SUCCESS(rc))
- rc = RTStrDupEx(&pszArg, szExpanded);
- }
- else
-#endif
- rc = RTStrDupEx(&pszArg, papszArgs[i]);
-
- if (RT_FAILURE(rc))
- break;
-
- papszNewArgv[i + 1] = pszArg;
- }
-
- if (RT_SUCCESS(rc))
- {
- /* Terminate array. */
- papszNewArgv[cArgs + 1] = NULL;
-
- *ppapszArgv = papszNewArgv;
- }
- }
-
- if (RT_FAILURE(rc))
- {
- for (i; i > 0; i--)
- RTStrFree(papszNewArgv[i]);
- RTMemFree(papszNewArgv);
- }
-
- return rc;
-}
-
-
-void VBoxServiceControlThreadFreeArgv(char **papszArgv)
-{
- if (papszArgv)
- {
- size_t i = 0;
- while (papszArgv[i])
- RTStrFree(papszArgv[i++]);
- RTMemFree(papszArgv);
- }
-}
-
-
-/**
- * Helper function to create/start a process on the guest.
- *
- * @return IPRT status code.
- * @param pszExec Full qualified path of process to start (without arguments).
- * @param papszArgs Pointer to array of command line arguments.
- * @param hEnv Handle to environment block to use.
- * @param fFlags Process execution flags.
- * @param phStdIn Handle for the process' stdin pipe.
- * @param phStdOut Handle for the process' stdout pipe.
- * @param phStdErr Handle for the process' stderr pipe.
- * @param pszAsUser User name (account) to start the process under.
- * @param pszPassword Password of the specified user.
- * @param phProcess Pointer which will receive the process handle after
- * successful process start.
- */
-static int VBoxServiceControlThreadCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
- PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
- const char *pszPassword, PRTPROCESS phProcess)
-{
- AssertPtrReturn(pszExec, VERR_INVALID_PARAMETER);
- AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
- AssertPtrReturn(phProcess, VERR_INVALID_PARAMETER);
-
- int rc = VINF_SUCCESS;
- char szExecExp[RTPATH_MAX];
-
- /* Do we need to expand environment variables in arguments? */
- bool fExpandArgs = (fFlags & EXECUTEPROCESSFLAG_EXPAND_ARGUMENTS) ? true : false;
-
-#ifdef RT_OS_WINDOWS
- /*
- * If sysprep should be executed do this in the context of VBoxService, which
- * (usually, if started by SCM) has administrator rights. Because of that a UI
- * won't be shown (doesn't have a desktop).
- */
- if (!RTStrICmp(pszExec, "sysprep"))
- {
- /* Use a predefined sysprep path as default. */
- char szSysprepCmd[RTPATH_MAX] = "C:\\sysprep\\sysprep.exe";
-
- /*
- * On Windows Vista (and up) sysprep is located in "system32\\sysprep\\sysprep.exe",
- * so detect the OS and use a different path.
- */
- OSVERSIONINFOEX OSInfoEx;
- RT_ZERO(OSInfoEx);
- OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
- && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
- && OSInfoEx.dwMajorVersion >= 6 /* Vista or later */)
- {
- rc = RTEnvGetEx(RTENV_DEFAULT, "windir", szSysprepCmd, sizeof(szSysprepCmd), NULL);
- if (RT_SUCCESS(rc))
- rc = RTPathAppend(szSysprepCmd, sizeof(szSysprepCmd), "system32\\sysprep\\sysprep.exe");
- }
-
- if (RT_SUCCESS(rc))
- {
- char **papszArgsExp;
- rc = VBoxServiceControlThreadAllocateArgv(szSysprepCmd /* argv0 */, papszArgs,
- fExpandArgs, &papszArgsExp);
- if (RT_SUCCESS(rc))
- {
- rc = RTProcCreateEx(szSysprepCmd, papszArgsExp, hEnv, 0 /* fFlags */,
- phStdIn, phStdOut, phStdErr, NULL /* pszAsUser */,
- NULL /* pszPassword */, phProcess);
- VBoxServiceControlThreadFreeArgv(papszArgsExp);
- }
- }
-
- if (RT_FAILURE(rc))
- VBoxServiceVerbose(3, "Starting sysprep returned rc=%Rrc\n", rc);
-
- return rc;
- }
-#endif /* RT_OS_WINDOWS */
-
-#ifdef VBOXSERVICE_TOOLBOX
- if (RTStrStr(pszExec, "vbox_") == pszExec)
- {
- /* We want to use the internal toolbox (all internal
- * tools are starting with "vbox_" (e.g. "vbox_cat"). */
- rc = VBoxServiceControlThreadResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp));
- }
- else
- {
-#endif
- /*
- * Do the environment variables expansion on executable and arguments.
- */
- rc = VBoxServiceControlThreadResolveExecutable(pszExec, szExecExp, sizeof(szExecExp));
-#ifdef VBOXSERVICE_TOOLBOX
- }
-#endif
- if (RT_SUCCESS(rc))
- {
- char **papszArgsExp;
- rc = VBoxServiceControlThreadAllocateArgv(pszExec /* Always use the unmodified executable name as argv0. */,
- papszArgs /* Append the rest of the argument vector (if any). */,
- fExpandArgs, &papszArgsExp);
- if (RT_FAILURE(rc))
- {
- /* Don't print any arguments -- may contain passwords or other sensible data! */
- VBoxServiceError("Could not prepare arguments, rc=%Rrc\n", rc);
- }
- else
- {
- uint32_t uProcFlags = 0;
- if (fFlags)
- {
- if (fFlags & EXECUTEPROCESSFLAG_HIDDEN)
- uProcFlags |= RTPROC_FLAGS_HIDDEN;
- if (fFlags & EXECUTEPROCESSFLAG_NO_PROFILE)
- uProcFlags |= RTPROC_FLAGS_NO_PROFILE;
- }
-
- /* If no user name specified run with current credentials (e.g.
- * full service/system rights). This is prohibited via official Main API!
- *
- * Otherwise use the RTPROC_FLAGS_SERVICE to use some special authentication
- * code (at least on Windows) for running processes as different users
- * started from our system service. */
- if (*pszAsUser)
- uProcFlags |= RTPROC_FLAGS_SERVICE;
-#ifdef DEBUG
- VBoxServiceVerbose(3, "Command: %s\n", szExecExp);
- for (size_t i = 0; papszArgsExp[i]; i++)
- VBoxServiceVerbose(3, "\targv[%ld]: %s\n", i, papszArgsExp[i]);
-#endif
- VBoxServiceVerbose(3, "Starting process \"%s\" ...\n", szExecExp);
-
- /* Do normal execution. */
- rc = RTProcCreateEx(szExecExp, papszArgsExp, hEnv, uProcFlags,
- phStdIn, phStdOut, phStdErr,
- *pszAsUser ? pszAsUser : NULL,
- *pszPassword ? pszPassword : NULL,
- phProcess);
-
- VBoxServiceVerbose(3, "Starting process \"%s\" returned rc=%Rrc\n",
- szExecExp, rc);
-
- VBoxServiceControlThreadFreeArgv(papszArgsExp);
- }
- }
- return rc;
-}
-
-/**
- * The actual worker routine (loop) for a started guest process.
- *
- * @return IPRT status code.
- * @param PVBOXSERVICECTRLTHREAD Thread data associated with a started process.
- */
-static int VBoxServiceControlThreadProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
-{
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- VBoxServiceVerbose(3, "Thread of process pThread=0x%p = \"%s\" started\n",
- pThread, pThread->pszCmd);
-
- int rc = VBoxServiceControlListSet(VBOXSERVICECTRLTHREADLIST_RUNNING, pThread);
- AssertRC(rc);
-
- rc = VbglR3GuestCtrlConnect(&pThread->uClientID);
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);
- RTThreadUserSignal(RTThreadSelf());
- return rc;
- }
- VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n",
- pThread->pszCmd, pThread->uClientID, pThread->uFlags);
-
- bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */
-
- /*
- * Create the environment.
- */
- RTENV hEnv;
- rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
- if (RT_SUCCESS(rc))
- {
- size_t i;
- for (i = 0; i < pThread->uNumEnvVars && pThread->papszEnv; i++)
- {
- rc = RTEnvPutEx(hEnv, pThread->papszEnv[i]);
- if (RT_FAILURE(rc))
- break;
- }
- if (RT_SUCCESS(rc))
- {
- /*
- * Setup the redirection of the standard stuff.
- */
- /** @todo consider supporting: gcc stuff.c >file 2>&1. */
- RTHANDLE hStdIn;
- PRTHANDLE phStdIn;
- rc = VBoxServiceControlThreadSetupPipe("|", 0 /*STDIN_FILENO*/,
- &hStdIn, &phStdIn, &pThread->pipeStdInW);
- if (RT_SUCCESS(rc))
- {
- RTHANDLE hStdOut;
- PRTHANDLE phStdOut;
- RTPIPE pipeStdOutR;
- rc = VBoxServiceControlThreadSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
- ? "|" : "/dev/null",
- 1 /*STDOUT_FILENO*/,
- &hStdOut, &phStdOut, &pipeStdOutR);
- if (RT_SUCCESS(rc))
- {
- RTHANDLE hStdErr;
- PRTHANDLE phStdErr;
- RTPIPE pipeStdErrR;
- rc = VBoxServiceControlThreadSetupPipe( (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
- ? "|" : "/dev/null",
- 2 /*STDERR_FILENO*/,
- &hStdErr, &phStdErr, &pipeStdErrR);
- if (RT_SUCCESS(rc))
- {
- /*
- * Create a poll set for the pipes and let the
- * transport layer add stuff to it as well.
- */
- RTPOLLSET hPollSet;
- rc = RTPollSetCreate(&hPollSet);
- if (RT_SUCCESS(rc))
- {
- uint32_t uFlags = RTPOLL_EVT_ERROR;
-#if 0
- /* Add reading event to pollset to get some more information. */
- uFlags |= RTPOLL_EVT_READ;
-#endif
- /* Stdin. */
- if (RT_SUCCESS(rc))
- rc = RTPollSetAddPipe(hPollSet, pThread->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN);
- /* Stdout. */
- if (RT_SUCCESS(rc))
- rc = RTPollSetAddPipe(hPollSet, pipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
- /* Stderr. */
- if (RT_SUCCESS(rc))
- rc = RTPollSetAddPipe(hPollSet, pipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
- /* IPC notification pipe. */
- if (RT_SUCCESS(rc))
- rc = RTPipeCreate(&pThread->hNotificationPipeR, &pThread->hNotificationPipeW, 0 /* Flags */);
- if (RT_SUCCESS(rc))
- rc = RTPollSetAddPipe(hPollSet, pThread->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);
-
- if (RT_SUCCESS(rc))
- {
- RTPROCESS hProcess;
- rc = VBoxServiceControlThreadCreateProcess(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,
- phStdIn, phStdOut, phStdErr,
- pThread->pszUser, pThread->pszPassword,
- &hProcess);
- if (RT_FAILURE(rc))
- VBoxServiceError("Error starting process, rc=%Rrc\n", rc);
- /*
- * Tell the control thread that it can continue
- * spawning services. This needs to be done after the new
- * process has been started because otherwise signal handling
- * on (Open) Solaris does not work correctly (see @bugref{5068}).
- */
- int rc2 = RTThreadUserSignal(RTThreadSelf());
- if (RT_SUCCESS(rc))
- rc = rc2;
- fSignalled = true;
-
- if (RT_SUCCESS(rc))
- {
- /*
- * Close the child ends of any pipes and redirected files.
- */
- rc2 = RTHandleClose(phStdIn); AssertRC(rc2);
- phStdIn = NULL;
- rc2 = RTHandleClose(phStdOut); AssertRC(rc2);
- phStdOut = NULL;
- rc2 = RTHandleClose(phStdErr); AssertRC(rc2);
- phStdErr = NULL;
-
- /* Enter the process loop. */
- rc = VBoxServiceControlThreadProcLoop(pThread,
- hProcess, pThread->uTimeLimitMS, hPollSet,
- &pThread->pipeStdInW, &pipeStdOutR, &pipeStdErrR);
-
- /*
- * The handles that are no longer in the set have
- * been closed by the above call in order to prevent
- * the guest from getting stuck accessing them.
- * So, NIL the handles to avoid closing them again.
- */
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL)))
- {
- pThread->hNotificationPipeR = NIL_RTPIPE;
- pThread->hNotificationPipeW = NIL_RTPIPE;
- }
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDERR, NULL)))
- pipeStdErrR = NIL_RTPIPE;
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDOUT, NULL)))
- pipeStdOutR = NIL_RTPIPE;
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDIN, NULL)))
- pThread->pipeStdInW = NIL_RTPIPE;
- }
- }
- RTPollSetDestroy(hPollSet);
-
- RTPipeClose(pThread->hNotificationPipeR);
- pThread->hNotificationPipeR = NIL_RTPIPE;
- RTPipeClose(pThread->hNotificationPipeW);
- pThread->hNotificationPipeW = NIL_RTPIPE;
- }
- RTPipeClose(pipeStdErrR);
- pipeStdErrR = NIL_RTPIPE;
- RTHandleClose(phStdErr);
- if (phStdErr)
- RTHandleClose(phStdErr);
- }
- RTPipeClose(pipeStdOutR);
- pipeStdOutR = NIL_RTPIPE;
- RTHandleClose(&hStdOut);
- if (phStdOut)
- RTHandleClose(phStdOut);
- }
- RTPipeClose(pThread->pipeStdInW);
- pThread->pipeStdInW = NIL_RTPIPE;
- RTHandleClose(phStdIn);
- }
- }
- RTEnvDestroy(hEnv);
- }
-
- /* Move thread to stopped thread list. */
- int rc2 = VBoxServiceControlListSet(VBOXSERVICECTRLTHREADLIST_STOPPED, pThread);
- AssertRC(rc2);
-
- if (pThread->uClientID)
- {
- if (RT_FAILURE(rc))
- {
- rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, pThread->uPID,
- PROC_STS_ERROR, rc,
- NULL /* pvData */, 0 /* cbData */);
- if (RT_FAILURE(rc2))
- VBoxServiceError("Could not report process failure error; rc=%Rrc (process error %Rrc)\n",
- rc2, rc);
- }
-
- VBoxServiceVerbose(3, "[PID %u]: Cancelling pending host requests (client ID=%u)\n",
- pThread->uPID, pThread->uClientID);
- rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID);
- if (RT_FAILURE(rc2))
- {
- VBoxServiceError("[PID %u]: Cancelling pending host requests failed; rc=%Rrc\n",
- pThread->uPID, rc2);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
-
- /* Disconnect from guest control service. */
- VBoxServiceVerbose(3, "[PID %u]: Disconnecting (client ID=%u) ...\n",
- pThread->uPID, pThread->uClientID);
- VbglR3GuestCtrlDisconnect(pThread->uClientID);
- pThread->uClientID = 0;
- }
-
- VBoxServiceVerbose(3, "[PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
- pThread->uPID, pThread->pszCmd, rc);
-
- /* Update started/stopped status. */
- ASMAtomicXchgBool(&pThread->fStopped, true);
- ASMAtomicXchgBool(&pThread->fStarted, false);
-
- /*
- * If something went wrong signal the user event so that others don't wait
- * forever on this thread.
- */
- if (RT_FAILURE(rc) && !fSignalled)
- RTThreadUserSignal(RTThreadSelf());
-
- return rc;
-}
-
-
-/**
- * Thread main routine for a started process.
- *
- * @return IPRT status code.
- * @param RTTHREAD Pointer to the thread's data.
- * @param void* User-supplied argument pointer.
- *
- */
-static DECLCALLBACK(int) VBoxServiceControlThread(RTTHREAD ThreadSelf, void *pvUser)
-{
- PVBOXSERVICECTRLTHREAD pThread = (VBOXSERVICECTRLTHREAD*)pvUser;
- AssertPtrReturn(pThread, VERR_INVALID_POINTER);
- return VBoxServiceControlThreadProcessWorker(pThread);
-}
-
-
-/**
- * Executes (starts) a process on the guest. This causes a new thread to be created
- * so that this function will not block the overall program execution.
- *
- * @return IPRT status code.
- * @param uContextID Context ID to associate the process to start with.
- * @param pProcess Process info.
- */
-int VBoxServiceControlThreadStart(uint32_t uContextID,
- PVBOXSERVICECTRLPROCESS pProcess)
-{
- AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
-
- /*
- * Allocate new thread data and assign it to our thread list.
- */
- PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
- if (!pThread)
- return VERR_NO_MEMORY;
-
- int rc = gstsvcCntlExecThreadInit(pThread, pProcess, uContextID);
- if (RT_SUCCESS(rc))
- {
- static uint32_t s_uCtrlExecThread = 0;
- if (s_uCtrlExecThread++ == UINT32_MAX)
- s_uCtrlExecThread = 0; /* Wrap around to not let IPRT freak out. */
- rc = RTThreadCreateF(&pThread->Thread, VBoxServiceControlThread,
- pThread /*pvUser*/, 0 /*cbStack*/,
- RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "gctl%u", s_uCtrlExecThread);
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
- rc, pThread);
- }
- else
- {
- VBoxServiceVerbose(4, "Waiting for thread to initialize ...\n");
-
- /* Wait for the thread to initialize. */
- rc = RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */);
- AssertRC(rc);
- if ( ASMAtomicReadBool(&pThread->fShutdown)
- || RT_FAILURE(rc))
- {
- VBoxServiceError("Thread for process \"%s\" failed to start, rc=%Rrc\n",
- pProcess->szCmd, rc);
- }
- else
- {
- ASMAtomicXchgBool(&pThread->fStarted, true);
- }
- }
- }
-
- if (RT_FAILURE(rc))
- RTMemFree(pThread);
-
- return rc;
-}
-
-
-/**
- * Performs a request to a specific (formerly started) guest process and waits
- * for its response.
- *
- * @return IPRT status code.
- * @param uPID PID of guest process to perform a request to.
- * @param pRequest Pointer to request to perform.
- */
-int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest)
-{
- AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
- AssertReturn(pRequest->enmType > VBOXSERVICECTRLREQUEST_UNKNOWN, VERR_INVALID_PARAMETER);
- /* Rest in pRequest is optional (based on the request type). */
-
- int rc = VINF_SUCCESS;
- PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlLockThread(uPID);
- if (pThread)
- {
- if (ASMAtomicReadBool(&pThread->fShutdown))
- {
- rc = VERR_CANCELLED;
- }
- else
- {
- /* Set request structure pointer. */
- pThread->pRequest = pRequest;
-
- /** @todo To speed up simultaneous guest process handling we could add a worker threads
- * or queue in order to wait for the request to happen. Later. */
- /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
- * that RTPoll unblocks (returns) and we then can do our requested operation. */
- Assert(pThread->hNotificationPipeW != NIL_RTPIPE);
- size_t cbWritten;
- if (RT_SUCCESS(rc))
- rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
-
- if ( RT_SUCCESS(rc)
- && cbWritten)
- {
- VBoxServiceVerbose(3, "[PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
- uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
-
- rc = VBoxServiceControlThreadRequestWait(pRequest);
- }
- }
-
- VBoxServiceControlUnlockThread(pThread);
- }
- else /* PID not found! */
- rc = VERR_NOT_FOUND;
-
- VBoxServiceVerbose(3, "[PID %u]: Performed enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
- uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
- return rc;
-}
-
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp
index 53dc1675..ba3a64cf 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -120,6 +120,18 @@ SYSFSCPUPATH g_aAcpiCpuPath[] =
/** Level 4 */
{ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl4, RT_ELEMENTS(g_aAcpiCpuPathLvl4), NULL, NULL},
};
+
+/**
+ * Possible directories to get to the topology directory for reading core and package id.
+ *
+ * @remark: This is not part of the path above because the eject file is not in one of the directories
+ * below and would make the hot unplug code fail.
+ */
+const char *g_apszTopologyPath[] =
+{
+ "sysdev",
+ "physical_node"
+};
#endif
#ifdef RT_OS_LINUX
@@ -277,10 +289,25 @@ static int VBoxServiceCpuHotPlugGetACPIDevicePath(char **ppszPath, uint32_t idCp
if (iLvlCurr == RT_ELEMENTS(g_aAcpiCpuPath) - 1)
{
/* Get the sysdev */
- uint32_t idCore = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/core_id",
- pszPathCurr);
- uint32_t idPackage = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/physical_package_id",
- pszPathCurr);
+ uint32_t idCore = 0;
+ uint32_t idPackage = 0;
+
+ for (unsigned i = 0; i < RT_ELEMENTS(g_apszTopologyPath); i++)
+ {
+ int64_t i64Core = RTLinuxSysFsReadIntFile(10, "%s/%s/topology/core_id",
+ pszPathCurr, g_apszTopologyPath[i]);
+ int64_t i64Package = RTLinuxSysFsReadIntFile(10, "%s/%s/topology/physical_package_id",
+ pszPathCurr, g_apszTopologyPath[i]);
+
+ if ( i64Core != -1
+ && i64Package != -1)
+ {
+ idCore = (uint32_t)i64Core;
+ idPackage = (uint32_t)i64Package;
+ break;
+ }
+ }
+
if ( idCore == idCpuCore
&& idPackage == idCpuPackage)
{
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h b/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
index 6a21cad9..a3f09fb6 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007-2012 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -107,213 +107,7 @@ typedef VBOXSERVICE const *PCVBOXSERVICE;
# define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif /* RT_OS_WINDOWS */
-#ifdef VBOX_WITH_GUEST_CONTROL
-/**
- * Pipe IDs for handling the guest process poll set.
- */
-typedef enum VBOXSERVICECTRLPIPEID
-{
- VBOXSERVICECTRLPIPEID_UNKNOWN = 0,
- VBOXSERVICECTRLPIPEID_STDIN = 10,
- VBOXSERVICECTRLPIPEID_STDIN_WRITABLE = 11,
- /** Pipe for reading from guest process' stdout. */
- VBOXSERVICECTRLPIPEID_STDOUT = 40,
- /** Pipe for reading from guest process' stderr. */
- VBOXSERVICECTRLPIPEID_STDERR = 50,
- /** Notification pipe for waking up the guest process
- * control thread. */
- VBOXSERVICECTRLPIPEID_IPC_NOTIFY = 100
-} VBOXSERVICECTRLPIPEID;
-
-/**
- * Request types to perform on a started guest process.
- */
-typedef enum VBOXSERVICECTRLREQUESTTYPE
-{
- /** Unknown request. */
- VBOXSERVICECTRLREQUEST_UNKNOWN = 0,
- /** Main control thread asked used to quit. */
- VBOXSERVICECTRLREQUEST_QUIT = 1,
- /** Performs reading from stdout. */
- VBOXSERVICECTRLREQUEST_STDOUT_READ = 50,
- /** Performs reading from stderr. */
- VBOXSERVICECTRLREQUEST_STDERR_READ = 60,
- /** Performs writing to stdin. */
- VBOXSERVICECTRLREQUEST_STDIN_WRITE = 70,
- /** Same as VBOXSERVICECTRLREQUEST_STDIN_WRITE, but
- * marks the end of input. */
- VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF = 71,
- /** Kill/terminate process.
- * @todo Implement this! */
- VBOXSERVICECTRLREQUEST_KILL = 90,
- /** Gently ask process to terminate.
- * @todo Implement this! */
- VBOXSERVICECTRLREQUEST_HANGUP = 91,
- /** Ask the process in which status it
- * currently is.
- * @todo Implement this! */
- VBOXSERVICECTRLREQUEST_STATUS = 100
-} VBOXSERVICECTRLREQUESTTYPE;
-
-/**
- * Thread list types.
- */
-typedef enum VBOXSERVICECTRLTHREADLISTTYPE
-{
- /** Unknown list -- uncool to use. */
- VBOXSERVICECTRLTHREADLIST_UNKNOWN = 0,
- /** Stopped list: Here all guest threads end up
- * when they reached the stopped state and can
- * be shut down / free'd safely. */
- VBOXSERVICECTRLTHREADLIST_STOPPED = 1,
- /**
- * Started list: Here all threads are registered
- * when they're up and running (that is, accepting
- * commands).
- */
- VBOXSERVICECTRLTHREADLIST_RUNNING = 2
-} VBOXSERVICECTRLTHREADLISTTYPE;
-
-/**
- * Structure to perform a request on a started guest
- * process. Needed for letting the main guest control thread
- * to communicate (and wait) for a certain operation which
- * will be done in context of the started guest process thread.
- */
-typedef struct VBOXSERVICECTRLREQUEST
-{
- /** Event semaphore to serialize access. */
- RTSEMEVENTMULTI Event;
- /** The request type to handle. */
- VBOXSERVICECTRLREQUESTTYPE enmType;
- /** Payload size; on input, this contains the (maximum) amount
- * of data the caller wants to write or to read. On output,
- * this show the actual amount of data read/written. */
- size_t cbData;
- /** Payload data; a pre-allocated data buffer for input/output. */
- void *pvData;
- /** The context ID which is required to complete the
- * request. Not used at the moment. */
- uint32_t uCID;
- /** The overall result of the operation. */
- int rc;
-} VBOXSERVICECTRLREQUEST;
-/** Pointer to request. */
-typedef VBOXSERVICECTRLREQUEST *PVBOXSERVICECTRLREQUEST;
-
-/**
- * Structure holding information for starting a guest
- * process.
- */
-typedef struct VBOXSERVICECTRLPROCESS
-{
- /** Full qualified path of process to start (without arguments). */
- char szCmd[GUESTPROCESS_MAX_CMD_LEN];
- /** Process execution flags. @sa */
- uint32_t uFlags;
- /** Command line arguments. */
- char szArgs[GUESTPROCESS_MAX_ARGS_LEN];
- /** Number of arguments specified in pszArgs. */
- uint32_t uNumArgs;
- /** String of environment variables ("FOO=BAR") to pass to the process
- * to start. */
- char szEnv[GUESTPROCESS_MAX_ENV_LEN];
- /** Size (in bytes) of environment variables block. */
- uint32_t cbEnv;
- /** Number of environment variables specified in pszEnv. */
- uint32_t uNumEnvVars;
- /** User name (account) to start the process under. */
- char szUser[GUESTPROCESS_MAX_USER_LEN];
- /** Password of specified user name (account). */
- char szPassword[GUESTPROCESS_MAX_PASSWORD_LEN];
- /** Time limit (in ms) of the process' life time. */
- uint32_t uTimeLimitMS;
-} VBOXSERVICECTRLPROCESS;
-/** Pointer to a guest process block. */
-typedef VBOXSERVICECTRLPROCESS *PVBOXSERVICECTRLPROCESS;
-
-/**
- * Structure for holding data for one (started) guest process.
- */
-typedef struct VBOXSERVICECTRLTHREAD
-{
- /** Pointer to list archor of following
- * list node.
- * @todo Would be nice to have a RTListGetAnchor(). */
- PRTLISTANCHOR pAnchor;
- /** Node. */
- RTLISTNODE Node;
- /** The worker thread. */
- RTTHREAD Thread;
- /** Shutdown indicator; will be set when the thread
- * needs (or is asked) to shutdown. */
- bool volatile fShutdown;
- /** Indicator set by the service thread exiting. */
- bool volatile fStopped;
- /** Whether the service was started or not. */
- bool fStarted;
- /** Client ID. */
- uint32_t uClientID;
- /** Context ID. */
- uint32_t uContextID;
- /** Critical section for thread-safe use. */
- RTCRITSECT CritSect;
- /** @todo Document me! */
- uint32_t uPID;
- char *pszCmd;
- uint32_t uFlags;
- char **papszArgs;
- uint32_t uNumArgs;
- char **papszEnv;
- uint32_t uNumEnvVars;
- /** Name of specified user account to run the
- * guest process under. */
- char *pszUser;
- /** Password of specified user account. */
- char *pszPassword;
- /** Overall time limit (in ms) that the guest process
- * is allowed to run. 0 for indefinite time. */
- uint32_t uTimeLimitMS;
- /** Pointer to the current IPC request being
- * processed. */
- PVBOXSERVICECTRLREQUEST pRequest;
- /** StdIn pipe for addressing writes to the
- * guest process' stdin.*/
- RTPIPE pipeStdInW;
- /** The notification pipe associated with this guest process.
- * This is NIL_RTPIPE for output pipes. */
- RTPIPE hNotificationPipeW;
- /** The other end of hNotificationPipeW. */
- RTPIPE hNotificationPipeR;
-} VBOXSERVICECTRLTHREAD;
-/** Pointer to thread data. */
-typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD;
-
-/**
- * Structure for one (opened) guest file.
- */
-typedef struct VBOXSERVICECTRLFILE
-{
- /** Pointer to list archor of following
- * list node.
- * @todo Would be nice to have a RTListGetAnchor(). */
- PRTLISTANCHOR pAnchor;
- /** Node. */
- RTLISTNODE Node;
- /** The file name. */
- char szName[RTPATH_MAX];
- /** The file handle on the guest. */
- RTFILE hFile;
- /** File handle to identify this file. */
- uint32_t uHandle;
- /** Context ID. */
- uint32_t uContextID;
-} VBOXSERVICECTRLFILE;
-/** Pointer to thread data. */
-typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE;
-#endif /* VBOX_WITH_GUEST_CONTROL */
#ifdef VBOX_WITH_GUEST_PROPS
-
/**
* A guest property cache.
*/
@@ -358,6 +152,7 @@ RT_C_DECLS_BEGIN
extern char *g_pszProgName;
extern int g_cVerbosity;
+extern char g_szLogFile[RTPATH_MAX + 128];
extern uint32_t g_DefaultInterval;
extern VBOXSERVICE g_TimeSync;
extern VBOXSERVICE g_Clipboard;
@@ -368,7 +163,7 @@ extern VBOXSERVICE g_CpuHotPlug;
extern VBOXSERVICE g_MemBalloon;
extern VBOXSERVICE g_VMStatistics;
#endif
-#ifdef VBOX_WITH_PAGE_SHARING
+#ifdef VBOXSERVICE_PAGE_SHARING
extern VBOXSERVICE g_PageSharing;
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
@@ -378,64 +173,37 @@ extern VBOXSERVICE g_AutoMount;
extern RTCRITSECT g_csLog; /* For guest process stdout dumping. */
#endif
-extern RTEXITCODE VBoxServiceSyntax(const char *pszFormat, ...);
-extern RTEXITCODE VBoxServiceError(const char *pszFormat, ...);
-extern void VBoxServiceVerbose(int iLevel, const char *pszFormat, ...);
-extern int VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32,
- uint32_t u32Min, uint32_t u32Max);
-extern int VBoxServiceStartServices(void);
-extern int VBoxServiceStopServices(void);
-extern void VBoxServiceMainWait(void);
-extern int VBoxServiceReportStatus(VBoxGuestFacilityStatus enmStatus);
+extern RTEXITCODE VBoxServiceSyntax(const char *pszFormat, ...);
+extern RTEXITCODE VBoxServiceError(const char *pszFormat, ...);
+extern void VBoxServiceVerbose(int iLevel, const char *pszFormat, ...);
+extern int VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32,
+ uint32_t u32Min, uint32_t u32Max);
+extern int VBoxServiceStartServices(void);
+extern int VBoxServiceStopServices(void);
+extern void VBoxServiceMainWait(void);
+extern int VBoxServiceReportStatus(VBoxGuestFacilityStatus enmStatus);
#ifdef RT_OS_WINDOWS
-extern RTEXITCODE VBoxServiceWinInstall(void);
-extern RTEXITCODE VBoxServiceWinUninstall(void);
-extern RTEXITCODE VBoxServiceWinEnterCtrlDispatcher(void);
-extern void VBoxServiceWinSetStopPendingStatus(uint32_t uCheckPoint);
+extern RTEXITCODE VBoxServiceWinInstall(void);
+extern RTEXITCODE VBoxServiceWinUninstall(void);
+extern RTEXITCODE VBoxServiceWinEnterCtrlDispatcher(void);
+extern void VBoxServiceWinSetStopPendingStatus(uint32_t uCheckPoint);
#endif
#ifdef VBOXSERVICE_TOOLBOX
-extern bool VBoxServiceToolboxMain(int argc, char **argv, RTEXITCODE *prcExit);
+extern bool VBoxServiceToolboxMain(int argc, char **argv, RTEXITCODE *prcExit);
#endif
#ifdef RT_OS_WINDOWS
# ifdef VBOX_WITH_GUEST_PROPS
-extern int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList);
-extern int VBoxServiceWinGetComponentVersions(uint32_t uiClientID);
+extern int VBoxServiceVMInfoWinWriteUsers(PVBOXSERVICEVEPROPCACHE pCache, char **ppszUserList, uint32_t *pcUsersInList);
+extern int VBoxServiceWinGetComponentVersions(uint32_t uiClientID);
# endif /* VBOX_WITH_GUEST_PROPS */
#endif /* RT_OS_WINDOWS */
-#ifdef VBOX_WITH_GUEST_CONTROL
-/* Guest control main thread functions. */
-extern int VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID);
-extern int VBoxServiceControlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList,
- PVBOXSERVICECTRLTHREAD pThread);
-extern PVBOXSERVICECTRLTHREAD VBoxServiceControlLockThread(uint32_t uPID);
-extern void VBoxServiceControlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread);
-extern int VBoxServiceControlSetInactive(PVBOXSERVICECTRLTHREAD pThread);
-/* Per-thread guest process functions. */
-extern int VBoxServiceControlThreadStart(uint32_t uContext,
- PVBOXSERVICECTRLPROCESS pProcess);
-extern int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
-extern int VBoxServiceControlThreadStop(const PVBOXSERVICECTRLTHREAD pThread);
-extern int VBoxServiceControlThreadWait(const PVBOXSERVICECTRLTHREAD pThread,
- RTMSINTERVAL msTimeout, int *prc);
-extern int VBoxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread);
-/* Request handling. */
-extern int VBoxServiceControlThreadRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq,
- VBOXSERVICECTRLREQUESTTYPE enmType);
-extern int VBoxServiceControlThreadRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq,
- VBOXSERVICECTRLREQUESTTYPE enmType,
- void* pbData,
- size_t cbData,
- uint32_t uCID);
-extern void VBoxServiceControlThreadRequestFree(PVBOXSERVICECTRLREQUEST pReq);
-#endif /* VBOX_WITH_GUEST_CONTROL */
-
#ifdef VBOXSERVICE_MANAGEMENT
extern uint32_t VBoxServiceBalloonQueryPages(uint32_t cbPage);
#endif
-#if defined(VBOX_WITH_PAGE_SHARING) && defined(RT_OS_WINDOWS)
+#if defined(VBOXSERVICE_PAGE_SHARING)
extern RTEXITCODE VBoxServicePageSharingInitFork(void);
#endif
extern int VBoxServiceVMInfoSignal(void);
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp b/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
index 39c9912d..c954d5c9 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,6 +23,7 @@
#include <iprt/avl.h>
#include <iprt/asm.h>
#include <iprt/mem.h>
+#include <iprt/ldr.h>
#include <iprt/process.h>
#include <iprt/env.h>
#include <iprt/stream.h>
@@ -80,8 +81,7 @@ typedef struct _RTL_PROCESS_MODULES
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
typedef NTSTATUS (WINAPI *PFNZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
-static PFNZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
-static HMODULE hNtdll = 0;
+static PFNZWQUERYSYSTEMINFORMATION g_pfnZwQuerySystemInformation = NULL;
static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *pvUser);
@@ -365,13 +365,13 @@ void VBoxServicePageSharingInspectGuest()
CloseHandle(hSnapshot);
/* Check all loaded kernel modules. */
- if (ZwQuerySystemInformation)
+ if (g_pfnZwQuerySystemInformation)
{
ULONG cbBuffer = 0;
PVOID pBuffer = NULL;
PRTL_PROCESS_MODULES pSystemModules;
- NTSTATUS ret = ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
+ NTSTATUS ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
if (!cbBuffer)
{
VBoxServiceVerbose(1, "ZwQuerySystemInformation returned length 0\n");
@@ -382,7 +382,7 @@ void VBoxServicePageSharingInspectGuest()
if (!pBuffer)
goto skipkernelmodules;
- ret = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
+ ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
if (ret != STATUS_SUCCESS)
{
VBoxServiceVerbose(1, "ZwQuerySystemInformation returned %x (1)\n", ret);
@@ -552,12 +552,9 @@ static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
AssertRCReturn(rc, rc);
#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
- hNtdll = LoadLibrary("ntdll.dll");
+ g_pfnZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)RTLdrGetSystemSymbol("ntdll.dll", "ZwQuerySystemInformation");
- if (hNtdll)
- ZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
-
- rc = VbglR3GetSessionId(&g_idSession);
+ rc = VbglR3GetSessionId(&g_idSession);
if (RT_FAILURE(rc))
{
if (rc == VERR_IO_GEN_FAILURE)
@@ -695,7 +692,7 @@ DECLCALLBACK(int) VBoxServicePageSharingWorkerProcess(bool volatile *pfShutdown)
{
char const *papszArgs[3];
papszArgs[0] = pszExeName;
- papszArgs[1] = "--pagefusionfork";
+ papszArgs[1] = "pagefusion";
papszArgs[2] = NULL;
rc = RTProcCreate(pszExeName, papszArgs, RTENV_DEFAULT, 0 /* normal child */, &hProcess);
if (RT_FAILURE(rc))
@@ -737,12 +734,6 @@ DECLCALLBACK(int) VBoxServicePageSharingWorkerProcess(bool volatile *pfShutdown)
static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
{
VBoxServiceVerbose(3, "VBoxServicePageSharingTerm\n");
-
-#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
- if (hNtdll)
- FreeLibrary(hNtdll);
-#endif
- return;
}
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp b/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp
index 347faa95..1e691c95 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -38,8 +38,9 @@ PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheInsertEntryInternal(PVBOXSERVIC
/** @todo Docs */
PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheFindInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t uFlags)
{
- AssertPtr(pCache);
- AssertPtr(pszName);
+ AssertPtrReturn(pCache, NULL);
+ AssertPtrReturn(pszName, NULL);
+
/** @todo This is a O(n) lookup, maybe improve this later to O(1) using a
* map.
* r=bird: Use a string space (RTstrSpace*). That is O(log n) in its current
@@ -65,11 +66,18 @@ PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheFindInternal(PVBOXSERVICEVEPROP
/** @todo Docs */
PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheInsertEntryInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName)
{
- AssertPtr(pszName);
+ AssertPtrReturn(pCache, NULL);
+ AssertPtrReturn(pszName, NULL);
+
PVBOXSERVICEVEPROPCACHEENTRY pNode = (PVBOXSERVICEVEPROPCACHEENTRY)RTMemAlloc(sizeof(VBOXSERVICEVEPROPCACHEENTRY));
if (pNode)
{
pNode->pszName = RTStrDup(pszName);
+ if (!pNode->pszName)
+ {
+ RTMemFree(pNode);
+ return NULL;
+ }
pNode->pszValue = NULL;
pNode->fFlags = 0;
pNode->pszValueReset = NULL;
@@ -88,7 +96,8 @@ PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheInsertEntryInternal(PVBOXSERVIC
/** @todo Docs */
int vboxServicePropCacheWritePropF(uint32_t u32ClientId, const char *pszName, uint32_t fFlags, const char *pszValueFormat, ...)
{
- AssertPtr(pszName);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+
int rc;
if (pszValueFormat != NULL)
{
@@ -141,7 +150,7 @@ int vboxServicePropCacheWritePropF(uint32_t u32ClientId, const char *pszName, ui
*/
int VBoxServicePropCacheCreate(PVBOXSERVICEVEPROPCACHE pCache, uint32_t uClientId)
{
- AssertPtr(pCache);
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
/** @todo Prevent init the cache twice!
* r=bird: Use a magic. */
RTListInit(&pCache->NodeHead);
@@ -164,8 +173,8 @@ int VBoxServicePropCacheCreate(PVBOXSERVICEVEPROPCACHE pCache, uint32_t uClientI
int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
const char *pszName, uint32_t fFlags, const char *pszValueReset)
{
- AssertPtr(pCache);
- AssertPtr(pszName);
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
PVBOXSERVICEVEPROPCACHEENTRY pNode = vboxServicePropCacheFindInternal(pCache, pszName, 0);
if (pNode == NULL)
pNode = vboxServicePropCacheInsertEntryInternal(pCache, pszName);
@@ -182,6 +191,7 @@ int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
if (pNode->pszValueReset)
RTStrFree(pNode->pszValueReset);
pNode->pszValueReset = RTStrDup(pszValueReset);
+ AssertPtr(pNode->pszValueReset);
}
rc = RTCritSectLeave(&pCache->CritSect);
}
@@ -205,9 +215,10 @@ int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
*/
int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, const char *pszValueFormat, ...)
{
- AssertPtr(pCache);
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+
Assert(pCache->uClientID);
- AssertPtr(pszName);
/*
* Format the value first.
@@ -250,8 +261,15 @@ int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszNa
{
/* Write the update. */
rc = vboxServicePropCacheWritePropF(pCache->uClientID, pNode->pszName, pNode->fFlags, pszValue);
- RTStrFree(pNode->pszValue);
- pNode->pszValue = RTStrDup(pszValue);
+ VBoxServiceVerbose(4, "[PropCache %p]: Written \"%s\"=\"%s\" (flags: %x), rc=%Rrc\n",
+ pCache, pNode->pszName, pszValue, pNode->fFlags, rc);
+ if (RT_SUCCESS(rc)) /* Only update the node's value on successful write. */
+ {
+ RTStrFree(pNode->pszValue);
+ pNode->pszValue = RTStrDup(pszValue);
+ if (!pNode->pszValue)
+ rc = VERR_NO_MEMORY;
+ }
}
else
rc = VINF_NO_CHANGE; /* No update needed. */
@@ -261,11 +279,16 @@ int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszNa
/* No value specified. Deletion (or no action required). */
if (pNode->pszValue) /* Did we have a value before? Then the value needs to be deleted. */
{
- /* Delete property (but do not remove from cache) if not deleted yet. */
- RTStrFree(pNode->pszValue);
- pNode->pszValue = NULL;
rc = vboxServicePropCacheWritePropF(pCache->uClientID, pNode->pszName,
0, /* Flags */ NULL /* Value */);
+ VBoxServiceVerbose(4, "[PropCache %p]: Deleted \"%s\"=\"%s\" (flags: %x), rc=%Rrc\n",
+ pCache, pNode->pszName, pNode->pszValue, pNode->fFlags, rc);
+ if (RT_SUCCESS(rc)) /* Only delete property value on successful Vbgl deletion. */
+ {
+ /* Delete property (but do not remove from cache) if not deleted yet. */
+ RTStrFree(pNode->pszValue);
+ pNode->pszValue = NULL;
+ }
}
else
rc = VINF_NO_CHANGE; /* No update needed. */
@@ -275,6 +298,9 @@ int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszNa
RTCritSectLeave(&pCache->CritSect);
}
+ VBoxServiceVerbose(4, "[PropCache %p]: Updating \"%s\" resulted in rc=%Rrc\n",
+ pCache, pszName, rc);
+
/* Delete temp stuff. */
RTStrFree(pszValue);
return rc;
@@ -295,8 +321,9 @@ int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszNa
*/
int VBoxServicePropCacheUpdateByPath(PVBOXSERVICEVEPROPCACHE pCache, const char *pszValue, uint32_t fFlags, const char *pszPathFormat, ...)
{
- AssertPtr(pCache);
- AssertPtr(pszPathFormat);
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPathFormat, VERR_INVALID_POINTER);
+
int rc = VERR_NOT_FOUND;
PVBOXSERVICEVEPROPCACHEENTRY pNodeIt = NULL;
if (RT_SUCCESS(RTCritSectEnter(&pCache->CritSect)))
@@ -341,7 +368,8 @@ int VBoxServicePropCacheUpdateByPath(PVBOXSERVICEVEPROPCACHE pCache, const char
*/
int VBoxServicePropCacheFlush(PVBOXSERVICEVEPROPCACHE pCache)
{
- AssertPtr(pCache);
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+
int rc = VINF_SUCCESS;
PVBOXSERVICEVEPROPCACHEENTRY pNodeIt = NULL;
if (RT_SUCCESS(RTCritSectEnter(&pCache->CritSect)))
@@ -366,7 +394,7 @@ int VBoxServicePropCacheFlush(PVBOXSERVICEVEPROPCACHE pCache)
*/
void VBoxServicePropCacheDestroy(PVBOXSERVICEVEPROPCACHE pCache)
{
- AssertPtr(pCache);
+ AssertPtrReturnVoid(pCache);
Assert(pCache->uClientID);
/* Lock the cache. */
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.h b/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.h
index 430f9a7d..eb3ac648 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.h
+++ b/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceResource-win.h b/src/VBox/Additions/common/VBoxService/VBoxServiceResource-win.h
index cf932cbe..60296c55 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceResource-win.h
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceResource-win.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp
index c7c259ae..8083e84a 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -43,6 +43,7 @@
#include <iprt/assert.h>
#include <iprt/mem.h>
+#include <iprt/ldr.h>
#include <VBox/param.h>
#include <iprt/semaphore.h>
#include <iprt/string.h>
@@ -123,45 +124,32 @@ static DECLCALLBACK(int) VBoxServiceVMStatsInit(void)
VBoxServiceVerbose(3, "VBoxStatsInit: DeviceIoControl failed with %d\n", rc);
#ifdef RT_OS_WINDOWS
- /** @todo Use RTLdr instead of LoadLibrary/GetProcAddress here! */
-
- /* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation */
- HMODULE hMod = LoadLibrary("NTDLL.DLL");
- if (hMod)
+ /* NtQuerySystemInformation might be dropped in future releases, so load
+ it dynamically as per Microsoft's recommendation. */
+ *(void **)&gCtx.pfnNtQuerySystemInformation = RTLdrGetSystemSymbol("ntdll.dll", "NtQuerySystemInformation");
+ if (gCtx.pfnNtQuerySystemInformation)
+ VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation);
+ else
{
- *(uintptr_t *)&gCtx.pfnNtQuerySystemInformation = (uintptr_t)GetProcAddress(hMod, "NtQuerySystemInformation");
- if (gCtx.pfnNtQuerySystemInformation)
- VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation);
- else
- {
- VBoxServiceVerbose(3, "VBoxStatsInit: NTDLL.NtQuerySystemInformation not found!\n");
- return VERR_SERVICE_DISABLED;
- }
+ VBoxServiceVerbose(3, "VBoxStatsInit: ntdll.NtQuerySystemInformation not found!\n");
+ return VERR_SERVICE_DISABLED;
}
/* GlobalMemoryStatus is win2k and up, so load it dynamically */
- hMod = LoadLibrary("KERNEL32.DLL");
- if (hMod)
+ *(void **)&gCtx.pfnGlobalMemoryStatusEx = RTLdrGetSystemSymbol("kernel32.dll", "GlobalMemoryStatusEx");
+ if (gCtx.pfnGlobalMemoryStatusEx)
+ VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx);
+ else
{
- *(uintptr_t *)&gCtx.pfnGlobalMemoryStatusEx = (uintptr_t)GetProcAddress(hMod, "GlobalMemoryStatusEx");
- if (gCtx.pfnGlobalMemoryStatusEx)
- VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx);
- else
- {
- /** @todo Now fails in NT4; do we care? */
- VBoxServiceVerbose(3, "VBoxStatsInit: KERNEL32.GlobalMemoryStatusEx not found!\n");
- return VERR_SERVICE_DISABLED;
- }
+ /** @todo Now fails in NT4; do we care? */
+ VBoxServiceVerbose(3, "VBoxStatsInit: kernel32.GlobalMemoryStatusEx not found!\n");
+ return VERR_SERVICE_DISABLED;
}
+
/* GetPerformanceInfo is xp and up, so load it dynamically */
- hMod = LoadLibrary("PSAPI.DLL");
- if (hMod)
- {
- *(uintptr_t *)&gCtx.pfnGetPerformanceInfo = (uintptr_t)GetProcAddress(hMod, "GetPerformanceInfo");
- if (gCtx.pfnGetPerformanceInfo)
- VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo);
- /* failure is not fatal */
- }
+ *(void **)&gCtx.pfnGetPerformanceInfo = RTLdrGetSystemSymbol("psapi.dll", "GetPerformanceInfo");
+ if (gCtx.pfnGetPerformanceInfo)
+ VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo);
#endif /* RT_OS_WINDOWS */
return VINF_SUCCESS;
@@ -354,6 +342,7 @@ static void VBoxServiceVMStatsReport(void)
req.guestStats.u32PageSize = getpagesize();
req.guestStats.u32StatCaps = VBOX_GUEST_STAT_PHYS_MEM_TOTAL
| VBOX_GUEST_STAT_PHYS_MEM_AVAIL
+ | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE
| VBOX_GUEST_STAT_PAGE_FILE_SIZE;
#ifdef VBOX_WITH_MEMBALLOON
req.guestStats.u32PhysMemBalloon = VBoxServiceBalloonQueryPages(_4K);
@@ -464,30 +453,30 @@ static void VBoxServiceVMStatsReport(void)
*/
uint64_t u64Total = 0, u64Free = 0, u64Buffers = 0, u64Cached = 0, u64PagedTotal = 0;
int rc = -1;
- kstat_t *pStatPages = kstat_lookup(pStatKern, "unix", 0 /* instance */, "system_pages");
+ kstat_t *pStatPages = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"system_pages");
if (pStatPages)
{
rc = kstat_read(pStatKern, pStatPages, NULL /* optional-copy-buf */);
if (rc != -1)
{
kstat_named_t *pStat = NULL;
- pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, "pagestotal");
+ pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, (char *)"pagestotal");
if (pStat)
u64Total = pStat->value.ul;
- pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, "freemem");
+ pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, (char *)"freemem");
if (pStat)
u64Free = pStat->value.ul;
}
}
- kstat_t *pStatZFS = kstat_lookup(pStatKern, "zfs", 0 /* instance */, "arcstats");
+ kstat_t *pStatZFS = kstat_lookup(pStatKern, (char *)"zfs", 0 /* instance */, (char *)"arcstats");
if (pStatZFS)
{
rc = kstat_read(pStatKern, pStatZFS, NULL /* optional-copy-buf */);
if (rc != -1)
{
- kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(pStatZFS, "size");
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(pStatZFS, (char *)"size");
if (pStat)
u64Cached = pStat->value.ul;
}
@@ -497,14 +486,14 @@ static void VBoxServiceVMStatsReport(void)
* The vminfo are accumulative counters updated every "N" ticks. Let's get the
* number of stat updates so far and use that to divide the swap counter.
*/
- kstat_t *pStatInfo = kstat_lookup(pStatKern, "unix", 0 /* instance */, "sysinfo");
+ kstat_t *pStatInfo = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"sysinfo");
if (pStatInfo)
{
sysinfo_t SysInfo;
rc = kstat_read(pStatKern, pStatInfo, &SysInfo);
if (rc != -1)
{
- kstat_t *pStatVMInfo = kstat_lookup(pStatKern, "unix", 0 /* instance */, "vminfo");
+ kstat_t *pStatVMInfo = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"vminfo");
if (pStatVMInfo)
{
vminfo_t VMInfo;
@@ -534,6 +523,7 @@ static void VBoxServiceVMStatsReport(void)
req.guestStats.u32StatCaps = VBOX_GUEST_STAT_PHYS_MEM_TOTAL
| VBOX_GUEST_STAT_PHYS_MEM_AVAIL
+ | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE
| VBOX_GUEST_STAT_PAGE_FILE_SIZE;
#ifdef VBOX_WITH_MEMBALLOON
req.guestStats.u32PhysMemBalloon = VBoxServiceBalloonQueryPages(_4K);
@@ -726,3 +716,4 @@ VBOXSERVICE g_VMStatistics =
VBoxServiceVMStatsStop,
VBoxServiceVMStatsTerm
};
+
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
index 3371cb2f..5c9ba83e 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceTimeSync.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2007 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -410,7 +410,7 @@ static bool VBoxServiceTimeSyncAdjust(PCRTTIMESPEC pDrift)
else if (g_cTimeSyncErrors++ < 10)
VBoxServiceError("VBoxServiceTimeSyncAdjust: GetSystemTimeAdjustment failed, error=%ld\n", GetLastError());
-#elif defined(RT_OS_OS2)
+#elif defined(RT_OS_OS2) || defined(RT_OS_HAIKU)
/* No API for doing gradual time adjustments. */
#else /* PORTME */
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp
index 0110dea3..6dbb74bd 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp
@@ -632,10 +632,10 @@ static int VBoxServiceToolboxPrintFsInfo(const char *pszName, uint16_t cbName,
pObjInfo->Attr.u.Unix.gid,
pObjInfo->cbObject,
pObjInfo->cbAllocated,
- pObjInfo->BirthTime,
- pObjInfo->ChangeTime,
- pObjInfo->ModificationTime,
- pObjInfo->AccessTime);
+ RTTimeSpecGetNano(&pObjInfo->BirthTime), /** @todo really ns? */
+ RTTimeSpecGetNano(&pObjInfo->ChangeTime), /** @todo really ns? */
+ RTTimeSpecGetNano(&pObjInfo->ModificationTime), /** @todo really ns? */
+ RTTimeSpecGetNano(&pObjInfo->AccessTime)); /** @todo really ns? */
RTPrintf(" %2d %s\n", cbName, pszName);
}
}
@@ -1525,7 +1525,7 @@ static RTEXITCODE VBoxServiceToolboxStat(int argc, char **argv)
RTListInit(&fileList);
while ( (ch = RTGetOpt(&GetState, &ValueUnion))
- && RT_SUCCESS(rc))
+ && RT_SUCCESS(rc))
{
/* For options that require an argument, ValueUnion has received the value. */
switch (ch)
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp
index 6dcff3a8..9302a843 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -47,8 +47,12 @@
* @param puTimestamp Where to return the timestamp. This is only set
* on success. Optional.
*/
-int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
+int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName,
+ char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
{
+ AssertPtrReturn(pszPropName, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszValue, VERR_INVALID_POINTER);
+
uint32_t cbBuf = _1K;
void *pvBuf = NULL;
int rc;
@@ -106,7 +110,8 @@ int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName, char **pp
break; /* done */
}
- RTMemFree(pvBuf);
+ if (pvBuf)
+ RTMemFree(pvBuf);
return rc;
}
@@ -121,14 +126,14 @@ int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName, char **pp
* @param pu32 Where to store the 32-bit value.
*
*/
-int VBoxServiceReadPropUInt32(uint32_t u32ClientId, const char *pszPropName, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
+int VBoxServiceReadPropUInt32(uint32_t u32ClientId, const char *pszPropName,
+ uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
{
char *pszValue;
int rc = VBoxServiceReadProp(u32ClientId, pszPropName, &pszValue,
- NULL /* ppszFlags */, NULL /* puTimestamp */);
+ NULL /* ppszFlags */, NULL /* puTimestamp */);
if (RT_SUCCESS(rc))
{
- AssertPtr(pu32);
char *pszNext;
rc = RTStrToUInt32Ex(pszValue, &pszNext, 0, pu32);
if ( RT_SUCCESS(rc)
@@ -144,6 +149,63 @@ int VBoxServiceReadPropUInt32(uint32_t u32ClientId, const char *pszPropName, uin
/**
+ * Reads a guest property from the host side.
+ *
+ * @returns IPRT status code, fully bitched.
+ * @param u32ClientId The HGCM client ID for the guest property session.
+ * @param pszPropName The property name.
+ * @param fReadOnly Whether or not this property needs to be read only
+ * by the guest side. Otherwise VERR_ACCESS_DENIED will
+ * be returned.
+ * @param ppszValue Where to return the value. This is always set
+ * to NULL. Free it using RTStrFree().
+ * @param ppszFlags Where to return the value flags. Free it
+ * using RTStrFree(). Optional.
+ * @param puTimestamp Where to return the timestamp. This is only set
+ * on success. Optional.
+ */
+int VBoxServiceReadHostProp(uint32_t u32ClientId, const char *pszPropName, bool fReadOnly,
+ char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
+{
+ AssertPtrReturn(ppszValue, VERR_INVALID_PARAMETER);
+
+ char *pszValue = NULL;
+ char *pszFlags = NULL;
+ int rc = VBoxServiceReadProp(u32ClientId, pszPropName, &pszValue, &pszFlags, puTimestamp);
+ if (RT_SUCCESS(rc))
+ {
+ /* Check security bits. */
+ if ( fReadOnly /* Do we except a guest read-only property */
+ && !RTStrStr(pszFlags, "RDONLYGUEST"))
+ {
+ /* If we want a property which is read-only on the guest
+ * and it is *not* marked as such, deny access! */
+ rc = VERR_ACCESS_DENIED;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ *ppszValue = pszValue;
+
+ if (ppszFlags)
+ *ppszFlags = pszFlags;
+ else if (pszFlags)
+ RTStrFree(pszFlags);
+ }
+ else
+ {
+ if (pszValue)
+ RTStrFree(pszValue);
+ if (pszFlags)
+ RTStrFree(pszFlags);
+ }
+ }
+
+ return rc;
+}
+
+
+/**
* Wrapper around VbglR3GuestPropWriteValue that does value formatting and
* logging.
*
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.h b/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.h
index 7cd6dfc9..69ea9a9f 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.h
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,6 +23,7 @@
#ifdef VBOX_WITH_GUEST_PROPS
int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp);
int VBoxServiceReadPropUInt32(uint32_t u32ClientId, const char *pszPropName, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max);
+int VBoxServiceReadHostProp(uint32_t u32ClientId, const char *pszPropName, bool fReadOnly, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp);
int VBoxServiceWritePropF(uint32_t u32ClientId, const char *pszName, const char *pszValueFormat, ...);
#endif
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
index a23128a5..e9191a10 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,12 +24,13 @@
# define _WIN32_WINNT 0x0502 /* CachedRemoteInteractive in recent SDKs. */
#endif
#include <Windows.h>
-#include <wtsapi32.h> /* For WTS* calls. */
-#include <psapi.h> /* EnumProcesses. */
-#include <Ntsecapi.h> /* Needed for process security information. */
+#include <wtsapi32.h> /* For WTS* calls. */
+#include <psapi.h> /* EnumProcesses. */
+#include <Ntsecapi.h> /* Needed for process security information. */
#include <iprt/assert.h>
#include <iprt/ldr.h>
+#include <iprt/localipc.h>
#include <iprt/mem.h>
#include <iprt/thread.h>
#include <iprt/string.h>
@@ -39,38 +40,47 @@
#include <VBox/VBoxGuestLib.h>
#include "VBoxServiceInternal.h"
#include "VBoxServiceUtils.h"
+#include "VBoxServiceVMInfo.h"
+#include "../../WINNT/VBoxTray/VBoxTrayMsg.h" /* For IPC. */
+static uint32_t s_uDebugGuestPropClientID = 0;
+static uint32_t s_uDebugIter = 0;
+/** Whether to skip the logged-in user detection over RDP or not.
+ * See notes in this section why we might want to skip this. */
+static bool s_fSkipRDPDetection = false;
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** Structure for storing the looked up user information. */
-typedef struct
+typedef struct VBOXSERVICEVMINFOUSER
{
WCHAR wszUser[_MAX_PATH];
WCHAR wszAuthenticationPackage[_MAX_PATH];
WCHAR wszLogonDomain[_MAX_PATH];
/** Number of assigned user processes. */
ULONG ulNumProcs;
- /** Last (highest) session number. This
+ /** Last (highest) session ID. This
* is needed for distinguishing old session
* process counts from new (current) session
* ones. */
- ULONG ulSession;
+ ULONG ulLastSession;
} VBOXSERVICEVMINFOUSER, *PVBOXSERVICEVMINFOUSER;
/** Structure for the file information lookup. */
-typedef struct
+typedef struct VBOXSERVICEVMINFOFILE
{
char *pszFilePath;
char *pszFileName;
} VBOXSERVICEVMINFOFILE, *PVBOXSERVICEVMINFOFILE;
/** Structure for process information lookup. */
-typedef struct
+typedef struct VBOXSERVICEVMINFOPROC
{
/** The PID. */
DWORD id;
+ /** The SID. */
+ PSID pSid;
/** The LUID. */
LUID luid;
/** Interactive process. */
@@ -84,7 +94,8 @@ typedef struct
uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession, PVBOXSERVICEVMINFOPROC const paProcs, DWORD cProcs);
bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo, PLUID a_pSession);
int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount);
-void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC paProcs);
+void VBoxServiceVMInfoWinProcessesFree(DWORD cProcs, PVBOXSERVICEVMINFOPROC paProcs);
+int vboxServiceVMInfoWinWriteLastInput(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain);
typedef BOOL WINAPI FNQUERYFULLPROCESSIMAGENAME(HANDLE, DWORD, LPTSTR, PDWORD);
typedef FNQUERYFULLPROCESSIMAGENAME *PFNQUERYFULLPROCESSIMAGENAME;
@@ -92,6 +103,28 @@ typedef FNQUERYFULLPROCESSIMAGENAME *PFNQUERYFULLPROCESSIMAGENAME;
#ifndef TARGET_NT4
+static bool vboxServiceVMInfoSession0Separation(void)
+{
+ /** @todo Only do this once. Later. */
+ OSVERSIONINFOEX OSInfoEx;
+ RT_ZERO(OSInfoEx);
+ OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if ( !GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
+ || OSInfoEx.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ {
+ /* Platform other than NT (e.g. Win9x) not supported. */
+ return false;
+ }
+
+ if ( OSInfoEx.dwMajorVersion >= 6
+ && OSInfoEx.dwMinorVersion >= 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
/**
* Retrieves the module name of a given process.
*
@@ -107,6 +140,7 @@ static int VBoxServiceVMInfoWinProcessesGetModuleName(PVBOXSERVICEVMINFOPROC con
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
AssertReturn(cbName, VERR_INVALID_PARAMETER);
+ /** @todo Only do this once. Later. */
OSVERSIONINFOEX OSInfoEx;
RT_ZERO(OSInfoEx);
OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
@@ -142,20 +176,19 @@ static int VBoxServiceVMInfoWinProcessesGetModuleName(PVBOXSERVICEVMINFOPROC con
{
/* Loading the module and getting the symbol for each and every process is expensive
* -- since this function (at the moment) only is used for debugging purposes it's okay. */
- RTLDRMOD hMod;
- rc = RTLdrLoad("kernel32.dll", &hMod);
- if (RT_SUCCESS(rc))
+ PFNQUERYFULLPROCESSIMAGENAME pfnQueryFullProcessImageName;
+ pfnQueryFullProcessImageName = (PFNQUERYFULLPROCESSIMAGENAME)
+ RTLdrGetSystemSymbol("kernel32.dll", "QueryFullProcessImageNameA");
+ /** @todo r=bird: WTF don't we query the UNICODE name? */
+ if (pfnQueryFullProcessImageName)
{
- PFNQUERYFULLPROCESSIMAGENAME pfnQueryFullProcessImageName;
- rc = RTLdrGetSymbol(hMod, "QueryFullProcessImageNameA", (void **)&pfnQueryFullProcessImageName);
- if (RT_SUCCESS(rc))
- {
- DWORD dwLen = cbName / sizeof(TCHAR);
- if (!pfnQueryFullProcessImageName(h, 0 /*PROCESS_NAME_NATIVE*/, pszName, &dwLen))
- rc = VERR_ACCESS_DENIED;
- }
-
- RTLdrClose(hMod);
+ /** @todo r=bird: Completely bogus use of TCHAR.
+ * !!ALL USE OF TCHAR IS HEREWITH BANNED IN ALL VBOX SOURCES!!
+ * We use WCHAR when talking to windows, everything else is WRONG. (We don't
+ * want Chinese MBCS being treated as UTF-8.) */
+ DWORD dwLen = cbName / sizeof(TCHAR);
+ if (!pfnQueryFullProcessImageName(h, 0 /*PROCESS_NAME_NATIVE*/, pszName, &dwLen))
+ rc = VERR_ACCESS_DENIED;
}
}
else
@@ -211,10 +244,13 @@ static int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pPro
case TokenGroups:
dwTokenInfoSize = 0;
- /* Allocating will follow in a second step. */
+ /* Allocation will follow in a second step. */
break;
- /** @todo Implement more token classes here. */
+ case TokenUser:
+ dwTokenInfoSize = 0;
+ /* Allocation will follow in a second step. */
+ break;
default:
VBoxServiceError("Token class not implemented: %ld", tkClass);
@@ -242,6 +278,14 @@ static int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pPro
dwTokenInfoSize = dwRetLength;
break;
+ case TokenUser:
+ pvTokenInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, dwRetLength);
+ if (!pvTokenInfo)
+ dwErr = GetLastError();
+ dwTokenInfoSize = dwRetLength;
+ break;
+
default:
AssertMsgFailed(("Re-allocating of token information for token class not implemented\n"));
break;
@@ -264,6 +308,7 @@ static int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pPro
case TokenStatistics:
{
PTOKEN_STATISTICS pStats = (PTOKEN_STATISTICS)pvTokenInfo;
+ AssertPtr(pStats);
memcpy(&pProc->luid, &pStats->AuthenticationId, sizeof(LUID));
/** @todo Add more information of TOKEN_STATISTICS as needed. */
break;
@@ -309,6 +354,42 @@ static int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pPro
break;
}
+ case TokenUser:
+ {
+ PTOKEN_USER pUser = (PTOKEN_USER)pvTokenInfo;
+ AssertPtr(pUser);
+
+ DWORD dwLength = GetLengthSid(pUser->User.Sid);
+ Assert(dwLength);
+ if (dwLength)
+ {
+ pProc->pSid = (PSID)HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, dwLength);
+ AssertPtr(pProc->pSid);
+ if (CopySid(dwLength, pProc->pSid, pUser->User.Sid))
+ {
+ if (!IsValidSid(pProc->pSid))
+ dwErr = ERROR_INVALID_NAME;
+ }
+ else
+ dwErr = GetLastError();
+ }
+ else
+ dwErr = ERROR_NO_DATA;
+
+ if (dwErr != ERROR_SUCCESS)
+ {
+ VBoxServiceError("Error retrieving SID of process PID=%ld: %ld\n",
+ pProc->id, dwErr);
+ if (pProc->pSid)
+ {
+ HeapFree(GetProcessHeap(), 0 /* Flags */, pProc->pSid);
+ pProc->pSid = NULL;
+ }
+ }
+ break;
+ }
+
default:
AssertMsgFailed(("Unhandled token information class\n"));
break;
@@ -383,6 +464,7 @@ int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppaProcs, PDW
break;
}
} while (cProcesses <= _32K); /* Should be enough; see: http://blogs.technet.com/markrussinovich/archive/2009/07/08/3261309.aspx */
+
if (RT_SUCCESS(rc))
{
/*
@@ -396,23 +478,22 @@ int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppaProcs, PDW
for (DWORD i = 0; i < cProcesses; i++)
{
paProcs[i].id = paPID[i];
- rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenGroups);
- if (RT_FAILURE(rc))
- {
- /* Because some processes cannot be opened/parsed on
- Windows, we should not consider to be this an error here. */
- rc = VINF_SUCCESS;
- }
- else
- {
- rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenStatistics);
- if (RT_FAILURE(rc))
- {
- /* Because some processes cannot be opened/parsed on
- Windows, we should not consider to be this an error here. */
- rc = VINF_SUCCESS;
- }
- }
+ paProcs[i].pSid = NULL;
+
+ int rc2 = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenUser);
+ if (RT_FAILURE(rc2) && g_cVerbosity)
+ VBoxServiceError("Get token class \"user\" for process %ld failed, rc=%Rrc\n",
+ paProcs[i].id, rc2);
+
+ rc2 = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenGroups);
+ if (RT_FAILURE(rc2) && g_cVerbosity)
+ VBoxServiceError("Get token class \"groups\" for process %ld failed, rc=%Rrc\n",
+ paProcs[i].id, rc2);
+
+ rc2 = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenStatistics);
+ if (RT_FAILURE(rc2) && g_cVerbosity)
+ VBoxServiceError("Get token class \"statistics\" for process %ld failed, rc=%Rrc\n",
+ paProcs[i].id, rc2);
}
/* Save number of processes */
@@ -422,7 +503,7 @@ int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppaProcs, PDW
*ppaProcs = paProcs;
}
else
- RTMemFree(paProcs);
+ VBoxServiceVMInfoWinProcessesFree(cProcesses, paProcs);
}
else
rc = VERR_NO_MEMORY;
@@ -438,8 +519,17 @@ int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppaProcs, PDW
*
* @param paProcs What
*/
-void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC paProcs)
+void VBoxServiceVMInfoWinProcessesFree(DWORD cProcs, PVBOXSERVICEVMINFOPROC paProcs)
{
+ for (DWORD i = 0; i < cProcs; i++)
+ {
+ if (paProcs[i].pSid)
+ {
+ HeapFree(GetProcessHeap(), 0 /* Flags */, paProcs[i].pSid);
+ paProcs[i].pSid = NULL;
+ }
+
+ }
RTMemFree(paProcs);
}
@@ -447,14 +537,14 @@ void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC paProcs)
* Determines whether the specified session has processes on the system.
*
* @returns Number of processes found for a specified session.
- * @param pSession The session.
+ * @param pSession The current user's SID.
* @param paProcs The process snapshot.
* @param cProcs The number of processes in the snaphot.
* @param puSession Looked up session number. Optional.
*/
uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession,
PVBOXSERVICEVMINFOPROC const paProcs, DWORD cProcs,
- PULONG puSession)
+ PULONG puTerminalSession)
{
if (!pSession)
{
@@ -466,10 +556,20 @@ uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession,
NTSTATUS rcNt = LsaGetLogonSessionData(pSession, &pSessionData);
if (rcNt != STATUS_SUCCESS)
{
- VBoxServiceError("Could not get logon session data! rcNt=%#x", rcNt);
+ VBoxServiceError("Could not get logon session data! rcNt=%#x\n", rcNt);
return 0;
}
+ if (!IsValidSid(pSessionData->Sid))
+ {
+ VBoxServiceError("User SID=%p is not valid\n", pSessionData->Sid);
+ if (pSessionData)
+ LsaFreeReturnBuffer(pSessionData);
+ return 0;
+ }
+
+ int rc = VINF_SUCCESS;
+
/*
* Even if a user seems to be logged in, it could be a stale/orphaned logon
* session. So check if we have some processes bound to it by comparing the
@@ -478,40 +578,35 @@ uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession,
uint32_t cNumProcs = 0;
for (DWORD i = 0; i < cProcs; i++)
{
- VBoxServiceVerbose(4, "PID=%ld: (Interactive: %RTbool) %ld:%ld <-> %ld:%ld\n",
- paProcs[i].id, paProcs[i].fInteractive,
- paProcs[i].luid.HighPart, paProcs[i].luid.LowPart,
- pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);
if (g_cVerbosity)
{
TCHAR szModule[_1K];
- int rc2 = VBoxServiceVMInfoWinProcessesGetModuleName(&paProcs[i], szModule, sizeof(szModule));
- if (RT_SUCCESS(rc2))
+ rc = VBoxServiceVMInfoWinProcessesGetModuleName(&paProcs[i], szModule, sizeof(szModule));
+ if (RT_SUCCESS(rc))
VBoxServiceVerbose(4, "PID=%ld: %s\n",
paProcs[i].id, szModule);
}
- if ( paProcs[i].fInteractive
- && ( paProcs[i].luid.HighPart == pSessionData->LogonId.HighPart
- && paProcs[i].luid.LowPart == pSessionData->LogonId.LowPart))
+ PSID pProcSID = paProcs[i].pSid;
+ if ( RT_SUCCESS(rc)
+ && pProcSID
+ && IsValidSid(pProcSID))
{
- cNumProcs++;
- if (!g_cVerbosity) /* We want a bit more info on higher verbosity. */
- break;
+ if ( EqualSid(pSessionData->Sid, paProcs[i].pSid)
+ && paProcs[i].fInteractive)
+ {
+ cNumProcs++;
+ if (!g_cVerbosity) /* We want a bit more info on higher verbosity. */
+ break;
+ }
}
}
- if (g_cVerbosity)
- VBoxServiceVerbose(3, "Session %u has %u processes total\n",
- pSessionData->Session, cNumProcs);
- else
- VBoxServiceVerbose(3, "Session %u has at least one process\n",
- pSessionData->Session);
-
- if (puSession)
- *puSession = pSessionData->Session;
+ if (puTerminalSession)
+ *puTerminalSession = pSessionData->Session;
LsaFreeReturnBuffer(pSessionData);
+
return cNumProcs;
}
@@ -586,12 +681,25 @@ bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER pUserInfo, PLUID pSes
return false;
}
- VBoxServiceVerbose(3, "Session data: Name=%ls, Session=%u, LogonID=%ld,%ld, LogonType=%ld\n",
+ VBoxServiceVerbose(3, "Session data: Name=%ls, SessionID=%RU32, LogonID=%ld,%ld, LogonType=%ld\n",
pSessionData->UserName.Buffer,
pSessionData->Session,
pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart,
pSessionData->LogonType);
+ if (vboxServiceVMInfoSession0Separation())
+ {
+ /* Starting at Windows Vista user sessions begin with session 1, so
+ * ignore (stale) session 0 users. */
+ if ( pSessionData->Session == 0
+ /* Also check the logon time. */
+ || pSessionData->LogonTime.QuadPart == 0)
+ {
+ LsaFreeReturnBuffer(pSessionData);
+ return false;
+ }
+ }
+
/*
* Only handle users which can login interactively or logged in
* remotely over native RDP.
@@ -651,55 +759,90 @@ bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER pUserInfo, PLUID pSes
pSessionData->LogonId.LowPart, pUserInfo->wszAuthenticationPackage,
pUserInfo->wszLogonDomain);
- /* Detect RDP sessions as well. */
- LPTSTR pBuffer = NULL;
- DWORD cbRet = 0;
- int iState = -1;
- if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
- pSessionData->Session,
- WTSConnectState,
- &pBuffer,
- &cbRet))
+ /**
+ * Note: On certain Windows OSes WTSQuerySessionInformation leaks memory when used
+ * under a heavy stress situation. There are hotfixes available from Microsoft.
+ *
+ * See: http://support.microsoft.com/kb/970910
+ */
+ if (!s_fSkipRDPDetection)
{
- if (cbRet)
- iState = *pBuffer;
- VBoxServiceVerbose(3, "Account User=%ls, WTSConnectState=%d (%ld)\n",
- pUserInfo->wszUser, iState, cbRet);
- if ( iState == WTSActive /* User logged on to WinStation. */
- || iState == WTSShadow /* Shadowing another WinStation. */
- || iState == WTSDisconnected) /* WinStation logged on without client. */
+ /** @todo Only do this once. Later. */
+ OSVERSIONINFOEX OSInfoEx;
+ RT_ZERO(OSInfoEx);
+ OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ /* Skip RDP detection on non-NT systems. */
+ if ( !GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
+ || OSInfoEx.dwPlatformId != VER_PLATFORM_WIN32_NT)
{
- /** @todo On Vista and W2K, always "old" user name are still
- * there. Filter out the old one! */
- VBoxServiceVerbose(3, "Account User=%ls using TCS/RDP, state=%d \n",
- pUserInfo->wszUser, iState);
- fFoundUser = true;
+ s_fSkipRDPDetection = true;
}
- if (pBuffer)
- WTSFreeMemory(pBuffer);
+ /* Skip RDP detection on Windows 2000.
+ * For Windows 2000 however we don't have any hotfixes, so just skip the
+ * RDP detection in any case. */
+ if ( OSInfoEx.dwMajorVersion == 5
+ && OSInfoEx.dwMinorVersion == 0)
+ {
+ s_fSkipRDPDetection = true;
+ }
+
+ if (s_fSkipRDPDetection)
+ VBoxServiceVerbose(0, "Detection of logged-in users via RDP is disabled\n");
}
- else
+
+ if (!s_fSkipRDPDetection)
{
- DWORD dwLastErr = GetLastError();
- switch (dwLastErr)
+ /* Detect RDP sessions as well. */
+ LPTSTR pBuffer = NULL;
+ DWORD cbRet = 0;
+ int iState = -1;
+ if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
+ pSessionData->Session,
+ WTSConnectState,
+ &pBuffer,
+ &cbRet))
{
- /*
- * Terminal services don't run (for example in W2K,
- * nothing to worry about ...). ... or is on the Vista
- * fast user switching page!
- */
- case ERROR_CTX_WINSTATION_NOT_FOUND:
- VBoxServiceVerbose(3, "No WinStation found for user=%ls\n",
- pUserInfo->wszUser);
- break;
-
- default:
- VBoxServiceVerbose(3, "Cannot query WTS connection state for user=%ls, error=%ld\n",
- pUserInfo->wszUser, dwLastErr);
- break;
+ if (cbRet)
+ iState = *pBuffer;
+ VBoxServiceVerbose(3, "Account User=%ls, WTSConnectState=%d (%ld)\n",
+ pUserInfo->wszUser, iState, cbRet);
+ if ( iState == WTSActive /* User logged on to WinStation. */
+ || iState == WTSShadow /* Shadowing another WinStation. */
+ || iState == WTSDisconnected) /* WinStation logged on without client. */
+ {
+ /** @todo On Vista and W2K, always "old" user name are still
+ * there. Filter out the old one! */
+ VBoxServiceVerbose(3, "Account User=%ls using TCS/RDP, state=%d \n",
+ pUserInfo->wszUser, iState);
+ fFoundUser = true;
+ }
+ if (pBuffer)
+ WTSFreeMemory(pBuffer);
}
+ else
+ {
+ DWORD dwLastErr = GetLastError();
+ switch (dwLastErr)
+ {
+ /*
+ * Terminal services don't run (for example in W2K,
+ * nothing to worry about ...). ... or is on the Vista
+ * fast user switching page!
+ */
+ case ERROR_CTX_WINSTATION_NOT_FOUND:
+ VBoxServiceVerbose(3, "No WinStation found for user=%ls\n",
+ pUserInfo->wszUser);
+ break;
+
+ default:
+ VBoxServiceVerbose(3, "Cannot query WTS connection state for user=%ls, error=%ld\n",
+ pUserInfo->wszUser, dwLastErr);
+ break;
+ }
- fFoundUser = true;
+ fFoundUser = true;
+ }
}
}
else
@@ -711,27 +854,163 @@ bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER pUserInfo, PLUID pSes
pUserInfo->wszUser, fFoundUser ? "is" : "is not");
}
+ if (fFoundUser)
+ pUserInfo->ulLastSession = pSessionData->Session;
+
LsaFreeReturnBuffer(pSessionData);
return fFoundUser;
}
+static int vboxServiceVMInfoWinWriteLastInput(PVBOXSERVICEVEPROPCACHE pCache,
+ const char *pszUser, const char *pszDomain)
+{
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ /* pszDomain is optional. */
+
+ int rc = VINF_SUCCESS;
+
+ char szPipeName[255];
+ if (RTStrPrintf(szPipeName, sizeof(szPipeName), "%s%s",
+ VBOXTRAY_IPC_PIPE_PREFIX, pszUser))
+ {
+ bool fReportToHost = false;
+ VBoxGuestUserState userState = VBoxGuestUserState_Unknown;
+
+ RTLOCALIPCSESSION hSession;
+ rc = RTLocalIpcSessionConnect(&hSession, szPipeName, 0 /* Flags */);
+ if (RT_SUCCESS(rc))
+ {
+ VBOXTRAYIPCHEADER ipcHdr = { VBOXTRAY_IPC_HDR_MAGIC, 0 /* Header version */,
+ VBOXTRAYIPCMSGTYPE_USERLASTINPUT, 0 /* No msg */ };
+
+ rc = RTLocalIpcSessionWrite(hSession, &ipcHdr, sizeof(ipcHdr));
+
+ VBOXTRAYIPCRES_USERLASTINPUT ipcRes;
+ if (RT_SUCCESS(rc))
+ rc = RTLocalIpcSessionRead(hSession, &ipcRes, sizeof(ipcRes),
+ NULL /* Exact read */);
+ if ( RT_SUCCESS(rc)
+ /* If uLastInput is set to UINT32_MAX VBoxTray was not able to retrieve the
+ * user's last input time. This might happen when running on Windows NT4 or older. */
+ && ipcRes.uLastInput != UINT32_MAX)
+ {
+ userState = (ipcRes.uLastInput * 1000) < g_uVMInfoUserIdleThresholdMS
+ ? VBoxGuestUserState_InUse
+ : VBoxGuestUserState_Idle;
+
+ rc = vboxServiceUserUpdateF(pCache, pszUser, pszDomain, "UsageState",
+ userState == VBoxGuestUserState_InUse
+ ? "InUse" : "Idle");
+
+ /*
+ * Note: vboxServiceUserUpdateF can return VINF_NO_CHANGE in case there wasn't anything
+ * to update. So only report the user's status to host when we really got something
+ * new.
+ */
+ fReportToHost = rc == VINF_SUCCESS;
+ VBoxServiceVerbose(4, "User \"%s\" (domain \"%s\") is idle for %RU32, fReportToHost=%RTbool\n",
+ pszUser, pszDomain ? pszDomain : "<None>", ipcRes.uLastInput, fReportToHost);
+
+#if 0 /* Do we want to write the idle time as well? */
+ /* Also write the user's current idle time, if there is any. */
+ if (userState == VBoxGuestUserState_Idle)
+ rc = vboxServiceUserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs",
+ "%RU32", ipcRes.uLastInputMs);
+ else
+ rc = vboxServiceUserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs",
+ NULL /* Delete property */);
+
+ if (RT_SUCCESS(rc))
+#endif
+ }
+#ifdef DEBUG
+ else if (ipcRes.uLastInput == UINT32_MAX)
+ VBoxServiceVerbose(4, "Last input for user \"%s\" is not supported, skipping\n",
+ pszUser, rc);
+
+ VBoxServiceVerbose(4, "Getting last input for user \"%s\" ended with rc=%Rrc\n",
+ pszUser, rc);
+#endif
+ int rc2 = RTLocalIpcSessionClose(hSession);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ else
+ {
+ switch (rc)
+ {
+ case VERR_FILE_NOT_FOUND:
+ {
+ /* No VBoxTray (or too old version which does not support IPC) running
+ for the given user. Not much we can do then. */
+ VBoxServiceVerbose(4, "VBoxTray for user \"%s\" not running (anymore), no last input available\n",
+ pszUser);
+
+ /* Overwrite rc from above. */
+ rc = vboxServiceUserUpdateF(pCache, pszUser, pszDomain,
+ "UsageState", "Idle");
+
+ fReportToHost = rc == VINF_SUCCESS;
+ if (fReportToHost)
+ userState = VBoxGuestUserState_Idle;
+ break;
+ }
+
+ default:
+ VBoxServiceError("Error querying last input for user \"%s\", rc=%Rrc\n",
+ pszUser, rc);
+ break;
+ }
+ }
+
+ if (fReportToHost)
+ {
+ Assert(userState != VBoxGuestUserState_Unknown);
+ int rc2 = VbglR3GuestUserReportState(pszUser, pszDomain, userState,
+ NULL /* No details */, 0);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Error reporting usage state %ld for user \"%s\" to host, rc=%Rrc\n",
+ userState, pszUser, rc2);
+
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+
+ return rc;
+}
+
+
/**
* Retrieves the currently logged in users and stores their names along with the
* user count.
*
* @returns VBox status code.
+ * @param pCachce Property cache to use for storing some of the lookup
+ * data in between calls.
* @param ppszUserList Where to store the user list (separated by commas).
* Must be freed with RTStrFree().
* @param pcUsersInList Where to store the number of users in the list.
*/
-int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList)
+int VBoxServiceVMInfoWinWriteUsers(PVBOXSERVICEVEPROPCACHE pCache,
+ char **ppszUserList, uint32_t *pcUsersInList)
{
- PLUID paSessions = NULL;
- ULONG cSessions = 0;
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszUserList, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcUsersInList, VERR_INVALID_POINTER);
+
+ int rc2 = VbglR3GuestPropConnect(&s_uDebugGuestPropClientID);
+ AssertRC(rc2);
+
+ char *pszUserList = NULL;
+ uint32_t cUsersInList = 0;
/* This function can report stale or orphaned interactive logon sessions
of already logged off users (especially in Windows 2000). */
+ PLUID paSessions = NULL;
+ ULONG cSessions = 0;
NTSTATUS rcNt = LsaEnumerateLogonSessions(&cSessions, &paSessions);
if (rcNt != STATUS_SUCCESS)
{
@@ -750,10 +1029,13 @@ int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList)
break;
default:
- VBoxServiceError("LsaEnumerate failed with error %u\n", ulError);
+ VBoxServiceError("LsaEnumerate failed with error %RU32\n", ulError);
break;
}
+ if (paSessions)
+ LsaFreeReturnBuffer(paSessions);
+
return RTErrConvertFromWin32(ulError);
}
VBoxServiceVerbose(3, "Found %ld sessions\n", cSessions);
@@ -777,56 +1059,73 @@ int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList)
else
{
ULONG cUniqueUsers = 0;
+
+ /**
+ * Note: The cSessions loop variable does *not* correlate with
+ * the Windows session ID!
+ */
for (ULONG i = 0; i < cSessions; i++)
{
- VBoxServiceVerbose(3, "Handling session %u\n", i);
+ VBoxServiceVerbose(3, "Handling session %RU32 (of %RU32)\n", i + 1, cSessions);
- VBOXSERVICEVMINFOUSER UserInfo;
- if (VBoxServiceVMInfoWinIsLoggedIn(&UserInfo, &paSessions[i]))
+ VBOXSERVICEVMINFOUSER userSession;
+ if (VBoxServiceVMInfoWinIsLoggedIn(&userSession, &paSessions[i]))
{
- VBoxServiceVerbose(4, "Handling user=%ls, domain=%ls, package=%ls\n",
- UserInfo.wszUser, UserInfo.wszLogonDomain, UserInfo.wszAuthenticationPackage);
+ VBoxServiceVerbose(4, "Handling user=%ls, domain=%ls, package=%ls, session=%RU32\n",
+ userSession.wszUser, userSession.wszLogonDomain, userSession.wszAuthenticationPackage,
+ userSession.ulLastSession);
/* Retrieve assigned processes of current session. */
- ULONG ulSession;
- uint32_t cSessionProcs = VBoxServiceVMInfoWinSessionHasProcesses(&paSessions[i], paProcs, cProcs, &ulSession);
+ uint32_t cCurSessionProcs = VBoxServiceVMInfoWinSessionHasProcesses(&paSessions[i], paProcs, cProcs,
+ NULL /* Terminal session ID */);
/* Don't return here when current session does not have assigned processes
* anymore -- in that case we have to search through the unique users list below
* and see if got a stale user/session entry. */
+ if (g_cVerbosity > 3)
+ {
+ char szDebugSessionPath[255]; RTStrPrintf(szDebugSessionPath, sizeof(szDebugSessionPath), "/VirtualBox/GuestInfo/Debug/LSA/Session/%RU32",
+ userSession.ulLastSession);
+ VBoxServiceWritePropF(s_uDebugGuestPropClientID, szDebugSessionPath,
+ "#%RU32: cSessionProcs=%RU32 (of %RU32 procs total)", s_uDebugIter, cCurSessionProcs, cProcs);
+ }
+
bool fFoundUser = false;
- for (ULONG i = 0; i < cUniqueUsers; i++)
+ for (ULONG a = 0; a < cUniqueUsers; a++)
{
- if ( !wcscmp(UserInfo.wszUser, pUserInfo[i].wszUser)
- && !wcscmp(UserInfo.wszLogonDomain, pUserInfo[i].wszLogonDomain)
- && !wcscmp(UserInfo.wszAuthenticationPackage, pUserInfo[i].wszAuthenticationPackage)
- && cSessionProcs)
+ PVBOXSERVICEVMINFOUSER pCurUser = &pUserInfo[a];
+ AssertPtr(pCurUser);
+
+ if ( !wcscmp(userSession.wszUser, pCurUser->wszUser)
+ && !wcscmp(userSession.wszLogonDomain, pCurUser->wszLogonDomain)
+ && !wcscmp(userSession.wszAuthenticationPackage, pCurUser->wszAuthenticationPackage))
{
/*
* Only respect the highest session for the current user.
*/
- if (ulSession > pUserInfo[i].ulSession)
+ if (userSession.ulLastSession > pCurUser->ulLastSession)
{
- VBoxServiceVerbose(4, "Updating user=%ls to %u processes (last session: %u)\n",
- UserInfo.wszUser, cSessionProcs, ulSession);
+ VBoxServiceVerbose(4, "Updating user=%ls to %u processes (last used session: %RU32)\n",
+ pCurUser->wszUser, cCurSessionProcs, userSession.ulLastSession);
- pUserInfo[i].ulNumProcs = cSessionProcs;
- pUserInfo[i].ulSession = ulSession;
+ if (!cCurSessionProcs)
+ VBoxServiceVerbose(3, "Stale session for user=%ls detected! Processes: %RU32 -> %RU32, Session: %RU32 -> %RU32\n",
+ pCurUser->wszUser,
+ pCurUser->ulNumProcs, cCurSessionProcs,
+ pCurUser->ulLastSession, userSession.ulLastSession);
- if (!cSessionProcs)
- VBoxServiceVerbose(3, "Stale session for user=%ls detected! Old processes: %u, new: %u\n",
- pUserInfo[i].wszUser, pUserInfo[i].ulNumProcs, cSessionProcs);
+ pCurUser->ulNumProcs = cCurSessionProcs;
+ pCurUser->ulLastSession = userSession.ulLastSession;
}
/* There can be multiple session objects using the same session ID for the
* current user -- so when we got the same session again just add the found
* processes to it. */
- else if (pUserInfo[i].ulSession == ulSession)
+ else if (pCurUser->ulLastSession == userSession.ulLastSession)
{
- VBoxServiceVerbose(4, "Adding %u processes to user=%ls (session %u)\n",
- cSessionProcs, UserInfo.wszUser, ulSession);
+ VBoxServiceVerbose(4, "Updating processes for user=%ls (old procs=%RU32, new procs=%RU32, session=%RU32)\n",
+ pCurUser->wszUser, pCurUser->ulNumProcs, cCurSessionProcs, pCurUser->ulLastSession);
- pUserInfo[i].ulNumProcs += cSessionProcs;
- pUserInfo[i].ulSession = ulSession;
+ pCurUser->ulNumProcs = cCurSessionProcs;
}
fFoundUser = true;
@@ -836,55 +1135,93 @@ int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList)
if (!fFoundUser)
{
- VBoxServiceVerbose(4, "Adding new user=%ls (session %u) with %u processes\n",
- UserInfo.wszUser, ulSession, cSessionProcs);
+ VBoxServiceVerbose(4, "Adding new user=%ls (session=%RU32) with %RU32 processes\n",
+ userSession.wszUser, userSession.ulLastSession, cCurSessionProcs);
- memcpy(&pUserInfo[cUniqueUsers], &UserInfo, sizeof(VBOXSERVICEVMINFOUSER));
- pUserInfo[cUniqueUsers].ulNumProcs = cSessionProcs;
- pUserInfo[cUniqueUsers].ulSession = ulSession;
+ memcpy(&pUserInfo[cUniqueUsers], &userSession, sizeof(VBOXSERVICEVMINFOUSER));
+ pUserInfo[cUniqueUsers].ulNumProcs = cCurSessionProcs;
cUniqueUsers++;
Assert(cUniqueUsers <= cSessions);
}
}
}
+ if (g_cVerbosity > 3)
+ VBoxServiceWritePropF(s_uDebugGuestPropClientID, "/VirtualBox/GuestInfo/Debug/LSA",
+ "#%RU32: cSessions=%RU32, cProcs=%RU32, cUniqueUsers=%RU32",
+ s_uDebugIter, cSessions, cProcs, cUniqueUsers);
+
VBoxServiceVerbose(3, "Found %u unique logged-in user(s)\n",
cUniqueUsers);
- *pcUsersInList = 0;
for (ULONG i = 0; i < cUniqueUsers; i++)
{
+ if (g_cVerbosity > 3)
+ {
+ char szDebugUserPath[255]; RTStrPrintf(szDebugUserPath, sizeof(szDebugUserPath), "/VirtualBox/GuestInfo/Debug/LSA/User/%RU32", i);
+ VBoxServiceWritePropF(s_uDebugGuestPropClientID, szDebugUserPath,
+ "#%RU32: szName=%ls, sessionID=%RU32, cProcs=%RU32",
+ s_uDebugIter, pUserInfo[i].wszUser, pUserInfo[i].ulLastSession, pUserInfo[i].ulNumProcs);
+ }
+
+ bool fAddUser = false;
if (pUserInfo[i].ulNumProcs)
+ fAddUser = true;
+
+ if (fAddUser)
{
- VBoxServiceVerbose(3, "User %ls has %ld processes (session %u)\n",
- pUserInfo[i].wszUser, pUserInfo[i].ulNumProcs, pUserInfo[i].ulSession);
+ VBoxServiceVerbose(3, "User \"%ls\" has %RU32 interactive processes (session=%RU32)\n",
+ pUserInfo[i].wszUser, pUserInfo[i].ulNumProcs, pUserInfo[i].ulLastSession);
- if (*pcUsersInList > 0)
+ if (cUsersInList > 0)
{
- rc = RTStrAAppend(ppszUserList, ",");
- AssertRCBreakStmt(rc, RTStrFree(*ppszUserList));
+ rc = RTStrAAppend(&pszUserList, ",");
+ AssertRCBreakStmt(rc, RTStrFree(pszUserList));
}
- *pcUsersInList += 1;
+ cUsersInList += 1;
- char *pszTemp;
- int rc2 = RTUtf16ToUtf8(pUserInfo[i].wszUser, &pszTemp);
- if (RT_SUCCESS(rc2))
+ char *pszUser = NULL;
+ char *pszDomain = NULL;
+ rc = RTUtf16ToUtf8(pUserInfo[i].wszUser, &pszUser);
+ if ( RT_SUCCESS(rc)
+ && pUserInfo[i].wszLogonDomain)
+ rc = RTUtf16ToUtf8(pUserInfo[i].wszLogonDomain, &pszDomain);
+ if (RT_SUCCESS(rc))
{
- rc = RTStrAAppend(ppszUserList, pszTemp);
- RTMemFree(pszTemp);
+ /* Append user to users list. */
+ rc = RTStrAAppend(&pszUserList, pszUser);
+
+ /* Do idle detection. */
+ if (RT_SUCCESS(rc))
+ rc = vboxServiceVMInfoWinWriteLastInput(pCache, pszUser, pszDomain);
}
else
- rc = RTStrAAppend(ppszUserList, "<string-conversion-error>");
- AssertRCBreakStmt(rc, RTStrFree(*ppszUserList));
+ rc = RTStrAAppend(&pszUserList, "<string-conversion-error>");
+
+ RTStrFree(pszUser);
+ RTStrFree(pszDomain);
+
+ AssertRCBreakStmt(rc, RTStrFree(pszUserList));
}
}
RTMemFree(pUserInfo);
}
- VBoxServiceVMInfoWinProcessesFree(paProcs);
+ VBoxServiceVMInfoWinProcessesFree(cProcs, paProcs);
}
- LsaFreeReturnBuffer(paSessions);
+ if (paSessions)
+ LsaFreeReturnBuffer(paSessions);
+
+ if (RT_SUCCESS(rc))
+ {
+ *ppszUserList = pszUserList;
+ *pcUsersInList = cUsersInList;
+ }
+
+ s_uDebugIter++;
+ VbglR3GuestPropDisconnect(s_uDebugGuestPropClientID);
+
return rc;
}
@@ -918,10 +1255,16 @@ int VBoxServiceWinGetComponentVersions(uint32_t uClientID)
{ szSysDir, "VBoxTray.exe" },
{ szSysDir, "VBoxGINA.dll" },
{ szSysDir, "VBoxCredProv.dll" },
+# ifdef VBOX_WITH_MMR
+ { szSysDir, "VBoxMMR.exe" },
+# endif /* VBOX_WITH_MMR */
/* On 64-bit we don't yet have the OpenGL DLLs in native format.
So just enumerate the 32-bit files in the SYSWOW directory. */
# ifdef RT_ARCH_AMD64
+# ifdef VBOX_WITH_MMR
+ { szSysWowDir, "VBoxMMRHook.dll" },
+# endif /* VBOX_WITH_MMR */
{ szSysWowDir, "VBoxOGLarrayspu.dll" },
{ szSysWowDir, "VBoxOGLcrutil.dll" },
{ szSysWowDir, "VBoxOGLerrorspu.dll" },
@@ -930,6 +1273,9 @@ int VBoxServiceWinGetComponentVersions(uint32_t uClientID)
{ szSysWowDir, "VBoxOGLfeedbackspu.dll" },
{ szSysWowDir, "VBoxOGL.dll" },
# else /* !RT_ARCH_AMD64 */
+# ifdef VBOX_WITH_MMR
+ { szSysDir, "VBoxMMRHook.dll" },
+# endif /* VBOX_WITH_MMR */
{ szSysDir, "VBoxOGLarrayspu.dll" },
{ szSysDir, "VBoxOGLcrutil.dll" },
{ szSysDir, "VBoxOGLerrorspu.dll" },
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
index 25fc36c3..d8dbe7c0 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -38,21 +38,23 @@
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <net/if.h>
+# include <pwd.h> /* getpwuid */
# include <unistd.h>
-# ifndef RT_OS_OS2
-# ifndef RT_OS_FREEBSD
-# include <utmpx.h> /* @todo FreeBSD 9 should have this. */
-# endif
+# if !defined(RT_OS_OS2) && !defined(RT_OS_FREEBSD) && !defined(RT_OS_HAIKU)
+# include <utmpx.h> /* @todo FreeBSD 9 should have this. */
# endif
# ifdef RT_OS_SOLARIS
# include <sys/sockio.h>
# include <net/if_arp.h>
# endif
-# ifdef RT_OS_FREEBSD
+# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
# include <ifaddrs.h> /* getifaddrs, freeifaddrs */
# include <net/if_dl.h> /* LLADDR */
# include <netdb.h> /* getnameinfo */
# endif
+# ifdef VBOX_WITH_DBUS
+# include <VBox/dbus.h>
+# endif
#endif
#include <iprt/mem.h>
@@ -69,6 +71,20 @@
#include "VBoxServicePropCache.h"
+/** Structure containing information about a location awarness
+ * client provided by the host. */
+/** @todo Move this (and functions) into VbglR3. */
+typedef struct VBOXSERVICELACLIENTINFO
+{
+ uint32_t uID;
+ char *pszName;
+ char *pszLocation;
+ char *pszDomain;
+ bool fAttached;
+ uint64_t uAttachedTS;
+} VBOXSERVICELACLIENTINFO, *PVBOXSERVICELACLIENTINFO;
+
+
/*******************************************************************************
* Global Variables *
*******************************************************************************/
@@ -78,12 +94,43 @@ static uint32_t g_cMsVMInfoInterval = 0;
static RTSEMEVENTMULTI g_hVMInfoEvent = NIL_RTSEMEVENTMULTI;
/** The guest property service client ID. */
static uint32_t g_uVMInfoGuestPropSvcClientID = 0;
-/** Number of logged in users in OS. */
-static uint32_t g_cVMInfoLoggedInUsers = UINT32_MAX;
+/** Number of currently logged in users in OS. */
+static uint32_t g_cVMInfoLoggedInUsers = 0;
/** The guest property cache. */
static VBOXSERVICEVEPROPCACHE g_VMInfoPropCache;
+static const char *g_pszPropCacheValLoggedInUsersList = "/VirtualBox/GuestInfo/OS/LoggedInUsersList";
+static const char *g_pszPropCacheValLoggedInUsers = "/VirtualBox/GuestInfo/OS/LoggedInUsers";
+static const char *g_pszPropCacheValNoLoggedInUsers = "/VirtualBox/GuestInfo/OS/NoLoggedInUsers";
+static const char *g_pszPropCacheValNetCount = "/VirtualBox/GuestInfo/Net/Count";
+/** A guest user's guest property root key. */
+static const char *g_pszPropCacheValUser = "/VirtualBox/GuestInfo/User/";
/** The VM session ID. Changes whenever the VM is restored or reset. */
static uint64_t g_idVMInfoSession;
+/** The last attached locartion awareness (LA) client timestamp. */
+static uint64_t g_LAClientAttachedTS = 0;
+/** The current LA client info. */
+static VBOXSERVICELACLIENTINFO g_LAClientInfo;
+/** User idle threshold (in ms). This specifies the minimum time a user is considered
+ * as being idle and then will be reported to the host. Default is 5s. */
+uint32_t g_uVMInfoUserIdleThresholdMS = 5 * 1000;
+
+
+/*******************************************************************************
+* Defines *
+*******************************************************************************/
+static const char *g_pszLAActiveClient = "/VirtualBox/HostInfo/VRDP/ActiveClient";
+
+#ifdef VBOX_WITH_DBUS
+/** ConsoleKit defines (taken from 0.4.5). */
+#define CK_NAME "org.freedesktop.ConsoleKit"
+#define CK_PATH "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE "org.freedesktop.ConsoleKit"
+
+#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+#endif
@@ -114,12 +161,17 @@ static DECLCALLBACK(int) VBoxServiceVMInfoPreInit(void)
/** @copydoc VBOXSERVICE::pfnOption */
static DECLCALLBACK(int) VBoxServiceVMInfoOption(const char **ppszShort, int argc, char **argv, int *pi)
{
+ /** @todo Use RTGetOpt here. */
+
int rc = -1;
if (ppszShort)
/* no short options */;
else if (!strcmp(argv[*pi], "--vminfo-interval"))
rc = VBoxServiceArgUInt32(argc, argv, "", pi,
&g_cMsVMInfoInterval, 1, UINT32_MAX - 1);
+ else if (!strcmp(argv[*pi], "--vminfo-user-idle-threshold"))
+ rc = VBoxServiceArgUInt32(argc, argv, "", pi,
+ &g_uVMInfoUserIdleThresholdMS, 1, UINT32_MAX - 1);
return rc;
}
@@ -134,7 +186,10 @@ static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
if (!g_cMsVMInfoInterval)
g_cMsVMInfoInterval = g_DefaultInterval * 1000;
if (!g_cMsVMInfoInterval)
- g_cMsVMInfoInterval = 10 * 1000;
+ {
+ /* Set it to 5s by default for location awareness checks. */
+ g_cMsVMInfoInterval = 5 * 1000;
+ }
int rc = RTSemEventMultiCreate(&g_hVMInfoEvent);
AssertRCReturn(rc, rc);
@@ -142,20 +197,23 @@ static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
VbglR3GetSessionId(&g_idVMInfoSession);
/* The status code is ignored as this information is not available with VBox < 3.2.10. */
+ /* Initialize the LA client object. */
+ RT_ZERO(g_LAClientInfo);
+
rc = VbglR3GuestPropConnect(&g_uVMInfoGuestPropSvcClientID);
if (RT_SUCCESS(rc))
- VBoxServiceVerbose(3, "VMInfo: Property Service Client ID: %#x\n", g_uVMInfoGuestPropSvcClientID);
+ VBoxServiceVerbose(3, "Property Service Client ID: %#x\n", g_uVMInfoGuestPropSvcClientID);
else
{
/* If the service was not found, we disable this service without
causing VBoxService to fail. */
if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
{
- VBoxServiceVerbose(0, "VMInfo: Guest property service is not available, disabling the service\n");
+ VBoxServiceVerbose(0, "Guest property service is not available, disabling the service\n");
rc = VERR_SERVICE_DISABLED;
}
else
- VBoxServiceError("VMInfo: Failed to connect to the guest property service! Error: %Rrc\n", rc);
+ VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
RTSemEventMultiDestroy(g_hVMInfoEvent);
g_hVMInfoEvent = NIL_RTSEMEVENTMULTI;
}
@@ -167,15 +225,204 @@ static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
/*
* Declare some guest properties with flags and reset values.
*/
- VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList",
- VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, NULL /* Delete on exit */);
- VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers",
- VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "0");
- VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers",
- VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "true");
- VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count",
- VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE, NULL /* Delete on exit */);
+ int rc2 = VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, g_pszPropCacheValLoggedInUsersList,
+ VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, NULL /* Delete on exit */);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to init property cache value \"%s\", rc=%Rrc\n", g_pszPropCacheValLoggedInUsersList, rc2);
+
+ rc2 = VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, g_pszPropCacheValLoggedInUsers,
+ VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "0");
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to init property cache value \"%s\", rc=%Rrc\n", g_pszPropCacheValLoggedInUsers, rc2);
+
+ rc2 = VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, g_pszPropCacheValNoLoggedInUsers,
+ VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "true");
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to init property cache value \"%s\", rc=%Rrc\n", g_pszPropCacheValNoLoggedInUsers, rc2);
+
+ rc2 = VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, g_pszPropCacheValNetCount,
+ VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE, NULL /* Delete on exit */);
+ if (RT_FAILURE(rc2))
+ VBoxServiceError("Failed to init property cache value \"%s\", rc=%Rrc\n", g_pszPropCacheValNetCount, rc2);
+
+ /*
+ * Get configuration guest properties from the host.
+ * Note: All properties should have sensible defaults in case the lookup here fails.
+ */
+ char *pszValue;
+ rc2 = VBoxServiceReadHostProp(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--vminfo-user-idle-threshold", true /* Read only */,
+ &pszValue, NULL /* Flags */, NULL /* Timestamp */);
+ if (RT_SUCCESS(rc2))
+ {
+ AssertPtr(pszValue);
+ g_uVMInfoUserIdleThresholdMS = RT_CLAMP(RTStrToUInt32(pszValue), 1000, UINT32_MAX - 1);
+ RTStrFree(pszValue);
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * Retrieves a specifiy client LA property.
+ *
+ * @return IPRT status code.
+ * @param uClientID LA client ID to retrieve property for.
+ * @param pszProperty Property (without path) to retrieve.
+ * @param ppszValue Where to store value of property.
+ * @param puTimestamp Timestamp of property to retrieve. Optional.
+ */
+static int vboxServiceGetLAClientValue(uint32_t uClientID, const char *pszProperty,
+ char **ppszValue, uint64_t *puTimestamp)
+{
+ AssertReturn(uClientID, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszProperty, VERR_INVALID_POINTER);
+
+ int rc;
+
+ char pszClientPath[255];
+ if (RTStrPrintf(pszClientPath, sizeof(pszClientPath),
+ "/VirtualBox/HostInfo/VRDP/Client/%RU32/%s", uClientID, pszProperty))
+ {
+ rc = VBoxServiceReadHostProp(g_uVMInfoGuestPropSvcClientID, pszClientPath, true /* Read only */,
+ ppszValue, NULL /* Flags */, puTimestamp);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ return rc;
+}
+
+
+/**
+ * Retrieves LA client information. On success the returned structure will have allocated
+ * objects which need to be free'd with vboxServiceFreeLAClientInfo.
+ *
+ * @return IPRT status code.
+ * @param uClientID Client ID to retrieve information for.
+ * @param pClient Pointer where to store the client information.
+ */
+static int vboxServiceGetLAClientInfo(uint32_t uClientID, PVBOXSERVICELACLIENTINFO pClient)
+{
+ AssertReturn(uClientID, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pClient, VERR_INVALID_POINTER);
+
+ int rc = vboxServiceGetLAClientValue(uClientID, "Name", &pClient->pszName,
+ NULL /* Timestamp */);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszAttach;
+ rc = vboxServiceGetLAClientValue(uClientID, "Attach", &pszAttach,
+ &pClient->uAttachedTS);
+ if (RT_SUCCESS(rc))
+ {
+ AssertPtr(pszAttach);
+ pClient->fAttached = !RTStrICmp(pszAttach, "1") ? true : false;
+
+ RTStrFree(pszAttach);
+ }
+ }
+ if (RT_SUCCESS(rc))
+ rc = vboxServiceGetLAClientValue(uClientID, "Location", &pClient->pszLocation,
+ NULL /* Timestamp */);
+ if (RT_SUCCESS(rc))
+ rc = vboxServiceGetLAClientValue(uClientID, "Domain", &pClient->pszDomain,
+ NULL /* Timestamp */);
+ if (RT_SUCCESS(rc))
+ pClient->uID = uClientID;
+
+ return rc;
+}
+
+
+/**
+ * Frees all allocated LA client information of a structure.
+ *
+ * @param pClient Pointer to client information structure to free.
+ */
+static void vboxServiceFreeLAClientInfo(PVBOXSERVICELACLIENTINFO pClient)
+{
+ if (pClient)
+ {
+ if (pClient->pszName)
+ {
+ RTStrFree(pClient->pszName);
+ pClient->pszName = NULL;
+ }
+ if (pClient->pszLocation)
+ {
+ RTStrFree(pClient->pszLocation);
+ pClient->pszLocation = NULL;
+ }
+ if (pClient->pszDomain)
+ {
+ RTStrFree(pClient->pszDomain);
+ pClient->pszDomain = NULL;
+ }
+ }
+}
+
+
+/**
+ * Updates a per-guest user guest property inside the given property cache.
+ *
+ * @return IPRT status code.
+ * @param pCache Pointer to guest property cache to update user in.
+ * @param pszUser Name of guest user to update.
+ * @param pszDomain Domain of guest user to update. Optional.
+ * @param pszKey Key name of guest property to update.
+ * @param pszValueFormat Guest property value to set. Pass NULL for deleting
+ * the property.
+ */
+int vboxServiceUserUpdateF(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain,
+ const char *pszKey, const char *pszValueFormat, ...)
+{
+ AssertPtrReturn(pCache, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ /* pszDomain is optional. */
+ AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
+ /* pszValueFormat is optional. */
+
+ int rc = VINF_SUCCESS;
+
+ char *pszName;
+ if (pszDomain)
+ {
+ if (!RTStrAPrintf(&pszName, "%s%s@%s/%s", g_pszPropCacheValUser, pszUser, pszDomain, pszKey))
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ {
+ if (!RTStrAPrintf(&pszName, "%s%s/%s", g_pszPropCacheValUser, pszUser, pszKey))
+ rc = VERR_NO_MEMORY;
+ }
+
+ char *pszValue = NULL;
+ if ( RT_SUCCESS(rc)
+ && pszValueFormat)
+ {
+ va_list va;
+ va_start(va, pszValueFormat);
+ if (RTStrAPrintfV(&pszValue, pszValueFormat, va) < 0)
+ rc = VERR_NO_MEMORY;
+ va_end(va);
+ if ( RT_SUCCESS(rc)
+ && !pszValue)
+ rc = VERR_NO_STR_MEMORY;
}
+
+ if (RT_SUCCESS(rc))
+ rc = VBoxServicePropCacheUpdate(pCache, pszName, pszValue);
+ if (rc == VINF_SUCCESS) /* VBoxServicePropCacheUpdate will also return VINF_NO_CHANGE. */
+ {
+ /** @todo Combine updating flags w/ updating the actual value. */
+ rc = VBoxServicePropCacheUpdateEntry(pCache, pszName,
+ VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT,
+ NULL /* Delete on exit */);
+ }
+
+ RTStrFree(pszValue);
+ RTStrFree(pszName);
return rc;
}
@@ -242,6 +489,23 @@ static void vboxserviceVMInfoWriteFixedProperties(void)
#endif
}
+#if defined(VBOX_WITH_DBUS) && defined(RT_OS_LINUX) /* Not yet for Solaris/FreeBSB. */
+/*
+ * Simple wrapper to work around compiler-specific va_list madness.
+ */
+static dbus_bool_t vboxService_dbus_message_get_args(DBusMessage *message,
+ DBusError *error,
+ int first_arg_type,
+ ...)
+{
+ va_list va;
+ va_start(va, first_arg_type);
+ dbus_bool_t ret = dbus_message_get_args_valist(message, error,
+ first_arg_type, va);
+ va_end(va);
+ return ret;
+}
+#endif
/**
* Provide information about active users.
@@ -254,7 +518,8 @@ static int vboxserviceVMInfoWriteUsers(void)
#ifdef RT_OS_WINDOWS
# ifndef TARGET_NT4
- rc = VBoxServiceVMInfoWinWriteUsers(&pszUserList, &cUsersInList);
+ rc = VBoxServiceVMInfoWinWriteUsers(&g_VMInfoPropCache,
+ &pszUserList, &cUsersInList);
# else
rc = VERR_NOT_IMPLEMENTED;
# endif
@@ -265,6 +530,10 @@ static int vboxserviceVMInfoWriteUsers(void)
* block below (?). */
rc = VERR_NOT_IMPLEMENTED;
+#elif defined(RT_OS_HAIKU)
+ /** @todo Haiku: Port logged on user info retrieval. */
+ rc = VERR_NOT_IMPLEMENTED;
+
#elif defined(RT_OS_OS2)
/** @todo OS/2: Port logged on (LAN/local/whatever) user info retrieval. */
rc = VERR_NOT_IMPLEMENTED;
@@ -279,12 +548,18 @@ static int vboxserviceVMInfoWriteUsers(void)
if (papszUsers == NULL)
rc = VERR_NO_MEMORY;
- /* Process all entries in the utmp file. */
+ /* Process all entries in the utmp file.
+ * Note: This only handles */
while ( (ut_user = getutxent())
&& RT_SUCCESS(rc))
{
- VBoxServiceVerbose(4, "Found logged in user \"%s\" (type: %d)\n",
- ut_user->ut_user, ut_user->ut_type);
+#ifdef RT_OS_DARWIN /* No ut_user->ut_session on Darwin */
+ VBoxServiceVerbose(4, "Found entry \"%s\" (type: %d, PID: %RU32)\n",
+ ut_user->ut_user, ut_user->ut_type, ut_user->ut_pid);
+#else
+ VBoxServiceVerbose(4, "Found entry \"%s\" (type: %d, PID: %RU32, session: %RU32)\n",
+ ut_user->ut_user, ut_user->ut_type, ut_user->ut_pid, ut_user->ut_session);
+#endif
if (cUsersInList > cListSize)
{
cListSize += 32;
@@ -294,8 +569,8 @@ static int vboxserviceVMInfoWriteUsers(void)
}
/* Make sure we don't add user names which are not
- * part of type USER_PROCESS. */
- if (ut_user->ut_type == USER_PROCESS)
+ * part of type USER_PROCES. */
+ if (ut_user->ut_type == USER_PROCESS) /* Regular user process. */
{
bool fFound = false;
for (uint32_t i = 0; i < cUsersInList && !fFound; i++)
@@ -314,25 +589,230 @@ static int vboxserviceVMInfoWriteUsers(void)
}
}
+#ifdef VBOX_WITH_DBUS
+# if defined(RT_OS_LINUX) /* Not yet for Solaris/FreeBSB. */
+ DBusError dbErr;
+ DBusConnection *pConnection = NULL;
+ int rc2 = RTDBusLoadLib();
+ if (RT_SUCCESS(rc2))
+ {
+ /* Handle desktop sessions using ConsoleKit. */
+ VBoxServiceVerbose(4, "Checking ConsoleKit sessions ...\n");
+
+ dbus_error_init(&dbErr);
+ pConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbErr);
+ }
+
+ if ( pConnection
+ && !dbus_error_is_set(&dbErr))
+ {
+ /* Get all available sessions. */
+ DBusMessage *pMsgSessions = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ "GetSessions");
+ if ( pMsgSessions
+ && (dbus_message_get_type(pMsgSessions) == DBUS_MESSAGE_TYPE_METHOD_CALL))
+ {
+ DBusMessage *pReplySessions = dbus_connection_send_with_reply_and_block(pConnection,
+ pMsgSessions, 30 * 1000 /* 30s timeout */,
+ &dbErr);
+ if ( pReplySessions
+ && !dbus_error_is_set(&dbErr))
+ {
+ char **ppszSessions; int cSessions;
+ if ( (dbus_message_get_type(pMsgSessions) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ && vboxService_dbus_message_get_args(pReplySessions, &dbErr, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH, &ppszSessions, &cSessions,
+ DBUS_TYPE_INVALID /* Termination */))
+ {
+ VBoxServiceVerbose(4, "ConsoleKit: retrieved %RU16 session(s)\n", cSessions);
+
+ char **ppszCurSession = ppszSessions;
+ for (ppszCurSession;
+ ppszCurSession && *ppszCurSession; ppszCurSession++)
+ {
+ VBoxServiceVerbose(4, "ConsoleKit: processing session '%s' ...\n", *ppszCurSession);
+
+ /* Only respect active sessions .*/
+ bool fActive = false;
+ DBusMessage *pMsgSessionActive = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ *ppszCurSession,
+ "org.freedesktop.ConsoleKit.Session",
+ "IsActive");
+ if ( pMsgSessionActive
+ && dbus_message_get_type(pMsgSessionActive) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ DBusMessage *pReplySessionActive = dbus_connection_send_with_reply_and_block(pConnection,
+ pMsgSessionActive, 30 * 1000 /* 30s timeout */,
+ &dbErr);
+ if ( pReplySessionActive
+ && !dbus_error_is_set(&dbErr))
+ {
+ DBusMessageIter itMsg;
+ if ( dbus_message_iter_init(pReplySessionActive, &itMsg)
+ && dbus_message_iter_get_arg_type(&itMsg) == DBUS_TYPE_BOOLEAN)
+ {
+ /* Get uid from message. */
+ int val;
+ dbus_message_iter_get_basic(&itMsg, &val);
+ fActive = val >= 1;
+ }
+
+ if (pReplySessionActive)
+ dbus_message_unref(pReplySessionActive);
+ }
+
+ if (pMsgSessionActive)
+ dbus_message_unref(pMsgSessionActive);
+ }
+
+ VBoxServiceVerbose(4, "ConsoleKit: session '%s' is %s\n",
+ *ppszCurSession, fActive ? "active" : "not active");
+
+ /* *ppszCurSession now contains the object path
+ * (e.g. "/org/freedesktop/ConsoleKit/Session1"). */
+ DBusMessage *pMsgUnixUser = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
+ *ppszCurSession,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetUnixUser");
+ if ( fActive
+ && pMsgUnixUser
+ && dbus_message_get_type(pMsgUnixUser) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ DBusMessage *pReplyUnixUser = dbus_connection_send_with_reply_and_block(pConnection,
+ pMsgUnixUser, 30 * 1000 /* 30s timeout */,
+ &dbErr);
+ if ( pReplyUnixUser
+ && !dbus_error_is_set(&dbErr))
+ {
+ DBusMessageIter itMsg;
+ if ( dbus_message_iter_init(pReplyUnixUser, &itMsg)
+ && dbus_message_iter_get_arg_type(&itMsg) == DBUS_TYPE_UINT32)
+ {
+ /* Get uid from message. */
+ uint32_t uid;
+ dbus_message_iter_get_basic(&itMsg, &uid);
+
+ /** @todo Add support for getting UID_MIN (/etc/login.defs on
+ * Debian). */
+ uint32_t uid_min = 1000;
+
+ /* Look up user name (realname) from uid. */
+ setpwent();
+ struct passwd *ppwEntry = getpwuid(uid);
+ if ( ppwEntry
+ && ppwEntry->pw_uid >= uid_min /* Only respect users, not daemons etc. */
+ && ppwEntry->pw_name)
+ {
+ VBoxServiceVerbose(4, "ConsoleKit: session '%s' -> %s (uid: %RU32)\n",
+ *ppszCurSession, ppwEntry->pw_name, uid);
+
+ bool fFound = false;
+ for (uint32_t i = 0; i < cUsersInList && !fFound; i++)
+ fFound = strcmp(papszUsers[i], ppwEntry->pw_name) == 0;
+
+ if (!fFound)
+ {
+ VBoxServiceVerbose(4, "ConsoleKit: adding user \"%s\" to list\n",
+ ppwEntry->pw_name);
+
+ rc = RTStrDupEx(&papszUsers[cUsersInList], (const char *)ppwEntry->pw_name);
+ if (RT_FAILURE(rc))
+ break;
+ cUsersInList++;
+ }
+ }
+ else
+ VBoxServiceError("ConsoleKit: unable to lookup user name for uid=%RU32\n", uid);
+ }
+ else
+ AssertMsgFailed(("ConsoleKit: GetUnixUser returned a wrong argument type\n"));
+ }
+
+ if (pReplyUnixUser)
+ dbus_message_unref(pReplyUnixUser);
+ }
+ else
+ VBoxServiceError("ConsoleKit: unable to retrieve user for session '%s' (msg type=%d): %s",
+ *ppszCurSession, dbus_message_get_type(pMsgUnixUser),
+ dbus_error_is_set(&dbErr) ? dbErr.message : "No error information available");
+
+ if (pMsgUnixUser)
+ dbus_message_unref(pMsgUnixUser);
+ }
+
+ dbus_free_string_array(ppszSessions);
+ }
+ else
+ {
+ VBoxServiceError("ConsoleKit: unable to retrieve session parameters (msg type=%d): %s",
+ dbus_message_get_type(pMsgSessions),
+ dbus_error_is_set(&dbErr) ? dbErr.message : "No error information available");
+ }
+ dbus_message_unref(pReplySessions);
+ }
+
+ if (pMsgSessions)
+ {
+ dbus_message_unref(pMsgSessions);
+ pMsgSessions = NULL;
+ }
+ }
+ else
+ {
+ static int s_iBitchedAboutConsoleKit = 0;
+ if (s_iBitchedAboutConsoleKit++ < 3)
+ VBoxServiceError("Unable to invoke ConsoleKit (%d/3) -- maybe not installed / used? Error: %s\n",
+ s_iBitchedAboutConsoleKit,
+ dbus_error_is_set(&dbErr) ? dbErr.message : "No error information available");
+ }
+
+ if (pMsgSessions)
+ dbus_message_unref(pMsgSessions);
+ }
+ else
+ {
+ static int s_iBitchedAboutDBus = 0;
+ if (s_iBitchedAboutDBus++ < 3)
+ VBoxServiceError("Unable to connect to system D-Bus (%d/3): %s\n", s_iBitchedAboutDBus,
+ pConnection && dbus_error_is_set(&dbErr) ? dbErr.message : "D-Bus not installed");
+ }
+
+ if ( pConnection
+ && dbus_error_is_set(&dbErr))
+ dbus_error_free(&dbErr);
+# endif /* RT_OS_LINUX */
+#endif /* VBOX_WITH_DBUS */
+
+ /** @todo Fedora/others: Handle systemd-loginctl. */
+
/* Calc the string length. */
size_t cchUserList = 0;
- for (uint32_t i = 0; i < cUsersInList; i++)
- cchUserList += (i != 0) + strlen(papszUsers[i]);
-
- /* Build the user list. */
- rc = RTStrAllocEx(&pszUserList, cchUserList + 1);
if (RT_SUCCESS(rc))
{
- char *psz = pszUserList;
for (uint32_t i = 0; i < cUsersInList; i++)
+ cchUserList += (i != 0) + strlen(papszUsers[i]);
+ }
+
+ /* Build the user list. */
+ if (cchUserList > 0)
+ {
+ if (RT_SUCCESS(rc))
+ rc = RTStrAllocEx(&pszUserList, cchUserList + 1);
+ if (RT_SUCCESS(rc))
{
- if (i != 0)
- *psz++ = ',';
- size_t cch = strlen(papszUsers[i]);
- memcpy(psz, papszUsers[i], cch);
- psz += cch;
+ char *psz = pszUserList;
+ for (uint32_t i = 0; i < cUsersInList; i++)
+ {
+ if (i != 0)
+ *psz++ = ',';
+ size_t cch = strlen(papszUsers[i]);
+ memcpy(psz, papszUsers[i], cch);
+ psz += cch;
+ }
+ *psz = '\0';
}
- *psz = '\0';
}
/* Cleanup. */
@@ -354,30 +834,42 @@ static int vboxserviceVMInfoWriteUsers(void)
{
static int s_iVMInfoBitchedOOM = 0;
if (s_iVMInfoBitchedOOM++ < 3)
- VBoxServiceVerbose(0, "Warning: Not enough memory available to enumerate users! Keeping old value (%u)\n",
+ VBoxServiceVerbose(0, "Warning: Not enough memory available to enumerate users! Keeping old value (%RU32)\n",
g_cVMInfoLoggedInUsers);
cUsersInList = g_cVMInfoLoggedInUsers;
}
else
cUsersInList = 0;
}
+ else /* Preserve logged in users count. */
+ g_cVMInfoLoggedInUsers = cUsersInList;
VBoxServiceVerbose(4, "cUsersInList=%RU32, pszUserList=%s, rc=%Rrc\n",
cUsersInList, pszUserList ? pszUserList : "<NULL>", rc);
- if (pszUserList && cUsersInList > 0)
- VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", "%s", pszUserList);
- else
- VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL);
- VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%u", cUsersInList);
- if (g_cVMInfoLoggedInUsers != cUsersInList)
+ if (pszUserList)
{
- VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers",
- cUsersInList == 0 ? "true" : "false");
- g_cVMInfoLoggedInUsers = cUsersInList;
+ AssertMsg(cUsersInList, ("pszUserList contains users whereas cUsersInList is 0\n"));
+ rc = VBoxServicePropCacheUpdate(&g_VMInfoPropCache, g_pszPropCacheValLoggedInUsersList, "%s", pszUserList);
}
- if (RT_SUCCESS(rc) && pszUserList)
+ else
+ rc = VBoxServicePropCacheUpdate(&g_VMInfoPropCache, g_pszPropCacheValLoggedInUsersList, NULL);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error writing logged in users list, rc=%Rrc\n", rc);
+
+ rc = VBoxServicePropCacheUpdate(&g_VMInfoPropCache, g_pszPropCacheValLoggedInUsers, "%RU32", cUsersInList);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error writing logged in users count, rc=%Rrc\n", rc);
+
+ rc = VBoxServicePropCacheUpdate(&g_VMInfoPropCache, g_pszPropCacheValNoLoggedInUsers,
+ cUsersInList == 0 ? "true" : "false");
+ if (RT_FAILURE(rc))
+ VBoxServiceError("Error writing no logged in users beacon, rc=%Rrc\n", rc);
+
+ if (pszUserList)
RTStrFree(pszUserList);
+
+ VBoxServiceVerbose(4, "Writing users returned with rc=%Rrc\n", rc);
return rc;
}
@@ -479,18 +971,18 @@ static int vboxserviceVMInfoWriteNetwork(void)
Assert(pAddress);
char szIp[32];
RTStrPrintf(szIp, sizeof(szIp), "%s", inet_ntoa(pAddress->sin_addr));
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/IP", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szIp);
pAddress = (sockaddr_in *) & (InterfaceList[i].iiBroadcastAddress);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Broadcast", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
pAddress = (sockaddr_in *)&(InterfaceList[i].iiNetmask);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Netmask", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/Status", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, nFlags & IFF_UP ? "Up" : "Down");
# ifndef TARGET_NT4
@@ -499,7 +991,7 @@ static int vboxserviceVMInfoWriteNetwork(void)
if (!strcmp(pAdp->IpAddressList.IpAddress.String, szIp))
break;
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/MAC", cIfacesReport);
if (pAdp)
{
char szMac[32];
@@ -519,7 +1011,11 @@ static int vboxserviceVMInfoWriteNetwork(void)
if (sd >= 0)
closesocket(sd);
-#elif defined(RT_OS_FREEBSD)
+#elif defined(RT_OS_HAIKU)
+ /** @todo Haiku: implement network info. retreival */
+ return VERR_NOT_IMPLEMENTED;
+
+#elif defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
struct ifaddrs *pIfHead = NULL;
/* Get all available interfaces */
@@ -546,19 +1042,19 @@ static int vboxserviceVMInfoWriteNetwork(void)
memset(szInetAddr, 0, NI_MAXHOST);
getnameinfo(pIfCurr->ifa_addr, sizeof(struct sockaddr_in),
szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/IP", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr);
memset(szInetAddr, 0, NI_MAXHOST);
getnameinfo(pIfCurr->ifa_broadaddr, sizeof(struct sockaddr_in),
szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Broadcast", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr);
memset(szInetAddr, 0, NI_MAXHOST);
getnameinfo(pIfCurr->ifa_netmask, sizeof(struct sockaddr_in),
szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Netmask", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr);
/* Search for the AF_LINK interface of the current AF_INET one and get the mac. */
@@ -575,13 +1071,13 @@ static int vboxserviceVMInfoWriteNetwork(void)
pu8Mac = (uint8_t *)LLADDR(pLinkAddress);
RTStrPrintf(szMac, sizeof(szMac), "%02X%02X%02X%02X%02X%02X",
pu8Mac[0], pu8Mac[1], pu8Mac[2], pu8Mac[3], pu8Mac[4], pu8Mac[5]);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/MAC", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac);
break;
}
}
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/Status", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, pIfCurr->ifa_flags & IFF_UP ? "Up" : "Down");
cIfacesReport++;
@@ -630,7 +1126,7 @@ static int vboxserviceVMInfoWriteNetwork(void)
bool fIfUp = !!(ifrequest[i].ifr_flags & IFF_UP);
pAddress = ((sockaddr_in *)&ifrequest[i].ifr_addr);
Assert(pAddress);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/IP", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
if (ioctl(sd, SIOCGIFBRDADDR, &ifrequest[i]) < 0)
@@ -640,7 +1136,7 @@ static int vboxserviceVMInfoWriteNetwork(void)
break;
}
pAddress = (sockaddr_in *)&ifrequest[i].ifr_broadaddr;
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Broadcast", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
if (ioctl(sd, SIOCGIFNETMASK, &ifrequest[i]) < 0)
@@ -655,7 +1151,7 @@ static int vboxserviceVMInfoWriteNetwork(void)
pAddress = (sockaddr_in *)&ifrequest[i].ifr_netmask;
# endif
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Netmask", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
# if defined(RT_OS_SOLARIS)
@@ -712,18 +1208,18 @@ static int vboxserviceVMInfoWriteNetwork(void)
# endif
RTStrPrintf(szMac, sizeof(szMac), "%02X%02X%02X%02X%02X%02X",
pu8Mac[0], pu8Mac[1], pu8Mac[2], pu8Mac[3], pu8Mac[4], pu8Mac[5]);
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/MAC", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac);
# endif /* !OS/2*/
- RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport);
+ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/Status", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, fIfUp ? "Up" : "Down");
cIfacesReport++;
} /* For all interfaces */
close(sd);
if (RT_FAILURE(rc))
- VBoxServiceError("VMInfo/Network: Network enumeration for interface %u failed with error %Rrc\n", cIfacesReport, rc);
+ VBoxServiceError("VMInfo/Network: Network enumeration for interface %RU32 failed with error %Rrc\n", cIfacesReport, rc);
#endif /* !RT_OS_WINDOWS */
@@ -735,19 +1231,19 @@ static int vboxserviceVMInfoWriteNetwork(void)
/* Get former count. */
uint32_t cIfacesReportOld;
- rc = VBoxServiceReadPropUInt32(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/Net/Count", &cIfacesReportOld,
+ rc = VBoxServiceReadPropUInt32(g_uVMInfoGuestPropSvcClientID, g_pszPropCacheValNetCount, &cIfacesReportOld,
0 /* Min */, UINT32_MAX /* Max */);
if ( RT_SUCCESS(rc)
&& cIfacesReportOld > cIfacesReport) /* Are some ifaces not around anymore? */
{
- VBoxServiceVerbose(3, "VMInfo/Network: Stale interface data detected (%u old vs. %u current)\n",
+ VBoxServiceVerbose(3, "VMInfo/Network: Stale interface data detected (%RU32 old vs. %RU32 current)\n",
cIfacesReportOld, cIfacesReport);
uint32_t uIfaceDeleteIdx = cIfacesReport;
do
{
VBoxServiceVerbose(3, "VMInfo/Network: Deleting stale data of interface %d ...\n", uIfaceDeleteIdx);
- rc = VBoxServicePropCacheUpdateByPath(&g_VMInfoPropCache, NULL /* Value, delete */, 0 /* Flags */, "/VirtualBox/GuestInfo/Net/%u", uIfaceDeleteIdx++);
+ rc = VBoxServicePropCacheUpdateByPath(&g_VMInfoPropCache, NULL /* Value, delete */, 0 /* Flags */, "/VirtualBox/GuestInfo/Net/%RU32", uIfaceDeleteIdx++);
} while (RT_SUCCESS(rc));
}
else if ( RT_FAILURE(rc)
@@ -762,7 +1258,7 @@ static int vboxserviceVMInfoWriteNetwork(void)
* does not change. If this property is missing, the host assumes that all other GuestInfo
* properties are no longer valid.
*/
- VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count", "%d",
+ VBoxServicePropCacheUpdate(&g_VMInfoPropCache, g_pszPropCacheValNetCount, "%RU32",
cIfacesReport);
/* Don't fail here; just report everything we got. */
@@ -806,6 +1302,83 @@ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
if (RT_FAILURE(rc))
break;
+ /* Whether to wait for event semaphore or not. */
+ bool fWait = true;
+
+ /* Check for location awareness. This most likely only
+ * works with VBox (latest) 4.1 and up. */
+
+ /* Check for new connection. */
+ char *pszLAClientID = NULL;
+ int rc2 = VBoxServiceReadHostProp(g_uVMInfoGuestPropSvcClientID, g_pszLAActiveClient, true /* Read only */,
+ &pszLAClientID, NULL /* Flags */, NULL /* Timestamp */);
+ if (RT_SUCCESS(rc2))
+ {
+ AssertPtr(pszLAClientID);
+ if (RTStrICmp(pszLAClientID, "0")) /* Is a client connected? */
+ {
+ uint32_t uLAClientID = RTStrToInt32(pszLAClientID);
+ uint64_t uLAClientAttachedTS;
+
+ /* Peek at "Attach" value to figure out if hotdesking happened. */
+ char *pszAttach = NULL;
+ rc2 = vboxServiceGetLAClientValue(uLAClientID, "Attach", &pszAttach,
+ &uLAClientAttachedTS);
+
+ if ( RT_SUCCESS(rc2)
+ && ( !g_LAClientAttachedTS
+ || (g_LAClientAttachedTS != uLAClientAttachedTS)))
+ {
+ vboxServiceFreeLAClientInfo(&g_LAClientInfo);
+
+ /* Note: There is a race between setting the guest properties by the host and getting them by
+ * the guest. */
+ rc2 = vboxServiceGetLAClientInfo(uLAClientID, &g_LAClientInfo);
+ if (RT_SUCCESS(rc2))
+ {
+ VBoxServiceVerbose(1, "VRDP: Hotdesk client %s with ID=%RU32, Name=%s, Domain=%s\n",
+ /* If g_LAClientAttachedTS is 0 this means there already was an active
+ * hotdesk session when VBoxService started. */
+ !g_LAClientAttachedTS ? "already active" : g_LAClientInfo.fAttached ? "connected" : "disconnected",
+ uLAClientID, g_LAClientInfo.pszName, g_LAClientInfo.pszDomain);
+
+ g_LAClientAttachedTS = g_LAClientInfo.uAttachedTS;
+
+ /* Don't wait for event semaphore below anymore because we now know that the client
+ * changed. This means we need to iterate all VM information again immediately. */
+ fWait = false;
+ }
+ else
+ {
+ static int s_iBitchedAboutLAClientInfo = 0;
+ if (s_iBitchedAboutLAClientInfo++ < 10)
+ VBoxServiceError("Error getting active location awareness client info, rc=%Rrc\n", rc2);
+ }
+ }
+ else if (RT_FAILURE(rc2))
+ VBoxServiceError("Error getting attached value of location awareness client %RU32, rc=%Rrc\n",
+ uLAClientID, rc2);
+ if (pszAttach)
+ RTStrFree(pszAttach);
+ }
+ else
+ {
+ VBoxServiceVerbose(1, "VRDP: UTTSC disconnected from VRDP server\n");
+ vboxServiceFreeLAClientInfo(&g_LAClientInfo);
+ }
+
+ RTStrFree(pszLAClientID);
+ }
+ else
+ {
+ static int s_iBitchedAboutLAClient = 0;
+ if ( (rc2 != VERR_NOT_FOUND) /* No location awareness installed, skip. */
+ && s_iBitchedAboutLAClient++ < 3)
+ VBoxServiceError("VRDP: Querying connected location awareness client failed with rc=%Rrc\n", rc2);
+ }
+
+ VBoxServiceVerbose(3, "VRDP: Handling location awareness done\n");
+
/*
* Flush all properties if we were restored.
*/
@@ -813,7 +1386,7 @@ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
VbglR3GetSessionId(&idNewSession);
if (idNewSession != g_idVMInfoSession)
{
- VBoxServiceVerbose(3, "VMInfo: The VM session ID changed, flushing all properties\n");
+ VBoxServiceVerbose(3, "The VM session ID changed, flushing all properties\n");
vboxserviceVMInfoWriteFixedProperties();
VBoxServicePropCacheFlush(&g_VMInfoPropCache);
g_idVMInfoSession = idNewSession;
@@ -827,12 +1400,13 @@ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
*/
if (*pfShutdown)
break;
- int rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval);
+ if (fWait)
+ rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval);
if (*pfShutdown)
break;
if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
{
- VBoxServiceError("VMInfo: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
+ VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
rc = rc2;
break;
}
@@ -841,7 +1415,7 @@ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
/* Reset event semaphore if it got triggered. */
rc2 = RTSemEventMultiReset(g_hVMInfoEvent);
if (RT_FAILURE(rc2))
- rc2 = VBoxServiceError("VMInfo: RTSemEventMultiReset failed; rc2=%Rrc\n", rc2);
+ rc2 = VBoxServiceError("RTSemEventMultiReset failed; rc2=%Rrc\n", rc2);
}
}
@@ -880,13 +1454,16 @@ static DECLCALLBACK(void) VBoxServiceVMInfoTerm(void)
const char *apszPat[1] = { "/VirtualBox/GuestInfo/Net/*" };
int rc = VbglR3GuestPropDelSet(g_uVMInfoGuestPropSvcClientID, &apszPat[0], RT_ELEMENTS(apszPat));
+ /* Destroy LA client info. */
+ vboxServiceFreeLAClientInfo(&g_LAClientInfo);
+
/* Destroy property cache. */
VBoxServicePropCacheDestroy(&g_VMInfoPropCache);
/* Disconnect from guest properties service. */
rc = VbglR3GuestPropDisconnect(g_uVMInfoGuestPropSvcClientID);
if (RT_FAILURE(rc))
- VBoxServiceError("VMInfo: Failed to disconnect from guest property service! Error: %Rrc\n", rc);
+ VBoxServiceError("Failed to disconnect from guest property service! Error: %Rrc\n", rc);
g_uVMInfoGuestPropSvcClientID = 0;
RTSemEventMultiDestroy(g_hVMInfoEvent);
@@ -905,11 +1482,15 @@ VBOXSERVICE g_VMInfo =
/* pszDescription. */
"Virtual Machine Information",
/* pszUsage. */
- " [--vminfo-interval <ms>]"
+ " [--vminfo-interval <ms>] [--vminfo-user-idle-threshold <ms>]"
,
/* pszOptions. */
" --vminfo-interval Specifies the interval at which to retrieve the\n"
" VM information. The default is 10000 ms.\n"
+ " --vminfo-user-idle-threshold <ms>\n"
+ " Specifies the user idle threshold (in ms) for\n"
+ " considering a guest user as being idle. The default\n"
+ " is 5000 (5 seconds).\n"
,
/* methods */
VBoxServiceVMInfoPreInit,
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.h b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.h
new file mode 100644
index 00000000..38984fa6
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.h
@@ -0,0 +1,31 @@
+/* $Id: VBoxServiceVMInfo.h $ */
+/** @file
+ * VBoxServiceVMInfo.h - Internal VM info definitions.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___VBoxServiceVMInfo_h
+#define ___VBoxServiceVMInfo_h
+
+//RT_C_DECLS_BEGIN
+
+extern int vboxServiceUserUpdateF(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain,
+ const char *pszKey, const char *pszValueFormat, ...);
+
+//RT_C_DECLS_END
+
+extern uint32_t g_uVMInfoUserIdleThresholdMS;
+
+#endif /* ___VBoxServiceVMInfo_h */
+
diff --git a/src/VBox/Additions/common/VBoxService/testcase/tstUserInfo.cpp b/src/VBox/Additions/common/VBoxService/testcase/tstUserInfo.cpp
index 84b18dfa..29f2ff88 100644
--- a/src/VBox/Additions/common/VBoxService/testcase/tstUserInfo.cpp
+++ b/src/VBox/Additions/common/VBoxService/testcase/tstUserInfo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp b/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp
index 0e5fa467..72b7ed1b 100644
--- a/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp
+++ b/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp b/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp
index 5f481049..f0411760 100644
--- a/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp
+++ b/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -301,7 +301,7 @@ static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
pRecord = pCtx->pRecord;
Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
- LogFunc(("%d\n", cb));
+ // LogFunc(("%d\n", cb));
cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
diff --git a/src/VBox/Additions/common/crOpenGL/Linux_i386_glxapi_exports.py b/src/VBox/Additions/common/crOpenGL/Linux_i386_glxapi_exports.py
index c47f990a..65c4660d 100755
--- a/src/VBox/Additions/common/crOpenGL/Linux_i386_glxapi_exports.py
+++ b/src/VBox/Additions/common/crOpenGL/Linux_i386_glxapi_exports.py
@@ -1,5 +1,5 @@
"""
-Copyright (C) 2009 Oracle Corporation
+Copyright (C) 2009-2012 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/Makefile.kmk b/src/VBox/Additions/common/crOpenGL/Makefile.kmk
index 4f3b9257..9d21e1a2 100644
--- a/src/VBox/Additions/common/crOpenGL/Makefile.kmk
+++ b/src/VBox/Additions/common/crOpenGL/Makefile.kmk
@@ -40,9 +40,20 @@ DLLS += \
VBoxOGLfeedbackspu
endif
+VBOX_OGL_X86_GUEST_DLLS = \
+ VBoxOGL-x86 \
+ VBoxOGLarrayspu-x86 \
+ VBoxOGLpassthroughspu-x86 \
+ VBoxOGLpackspu-x86 \
+ VBoxOGLfeedbackspu-x86
+
+ifdef VBOX_WITH_WDDM
+ DLLS.win.amd64 += $(VBOX_OGL_X86_GUEST_DLLS)
+endif
+
if1of ($(KBUILD_TARGET), linux solaris freebsd)
#VBoxOGL_DRI = 1
- ifn1of ($(KBUILD_TARGET),solaris freebsd) # No DRI on Solaris yet
+ ifn1of ($(KBUILD_TARGET),solaris) # No DRI on Solaris yet
VBoxOGL_FAKEDRI = 1
endif
@@ -209,8 +220,13 @@ if1of ($(KBUILD_TARGET), linux solaris freebsd)
$(PATH_STAGE_LIB)/libXfixes.so \
$(PATH_STAGE_LIB)/libXext.so
ifdef VBoxOGL_FAKEDRI
- VBoxOGL_LIBS += \
+ ifeq ($(KBUILD_TARGET), freebsd)
+ VBoxOGL_LIBS += \
+ elf
+ else
+ VBoxOGL_LIBS += \
dl
+ endif
endif
endif
ifdef VBOX_WITH_CRHGSMI
@@ -224,7 +240,6 @@ ifdef VBOX_WITH_WDDM
#
# VBoxOGL-x86 - x86 VBoxOGL version built for amd64 build
#
-DLLS.win.amd64 += VBoxOGL-x86
VBoxOGL-x86_EXTENDS = VBoxOGL
VBoxOGL-x86_BLD_TRG_ARCH = x86
VBoxOGL-x86_LIBS = $(VBOX_LIB_IPRT_GUEST_R3_SHARED_X86) \
@@ -242,14 +257,18 @@ endif
$(VBOX_PATH_CROGL_GENFILES)/NULLfuncs.c: $(PATH_SUB_CURRENT)/NULLfuncs.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
$(VBOX_PATH_CROGL_GENFILES)/tsfuncs.c: $(PATH_SUB_CURRENT)/tsfuncs.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
ifeq ($(KBUILD_TARGET),win)
+ # Windows
$(VBOX_PATH_CROGL_GENFILES)/getprocaddress.c: $(PATH_SUB_CURRENT)/windows_getprocaddress.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
ifeq ($(KBUILD_TARGET_ARCH),amd64)
$(VBOX_PATH_CROGL_GENFILES)/cropengl.def: $(PATH_SUB_CURRENT)/defs64.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
@@ -259,15 +278,18 @@ $(VBOX_PATH_CROGL_GENFILES)/cropengl.def: $(PATH_SUB_CURRENT)/defs.py $(VBOX_CRO
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
endif
+
$(VBOX_PATH_CROGL_GENFILES)/cr_gl.h: $(PATH_SUB_CURRENT)/cr_gl.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
$(VBOX_PATH_CROGL_GENFILES)/windows_exports.asm: \
$(PATH_SUB_CURRENT)/windows_i386_exports.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
ifdef VBOX_WITH_WDDM
ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),win.amd64)
$(VBOX_PATH_CROGL_GENFILES)/cropengl-x86.def: $(PATH_SUB_CURRENT)/defs.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
@@ -275,71 +297,85 @@ $(VBOX_PATH_CROGL_GENFILES)/cropengl-x86.def: $(PATH_SUB_CURRENT)/defs.py $(VBOX
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
endif #ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),win.amd64)
endif #ifdef VBOX_WITH_WDDM
-else if1of ($(KBUILD_TARGET), linux solaris freebsd)
+
+
+else if1of ($(KBUILD_TARGET), freebsd linux solaris)
+ # FreeBSD, Linux, Solaris
$(VBOX_PATH_CROGL_GENFILES)/getprocaddress.c: $(PATH_SUB_CURRENT)/getprocaddress.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
-if !defined(VBoxOGL_DRI) && !defined(VBoxOGL_FAKEDRI)
- ifeq ($(KBUILD_TARGET),solaris)
+
+ if !defined(VBoxOGL_DRI) && !defined(VBoxOGL_FAKEDRI)
+ ifeq ($(KBUILD_TARGET),solaris)
$(VBOX_PATH_CROGL_GENFILES)/solaris_exports.c: \
$(PATH_SUB_CURRENT)/SunOS_exports.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- else ifeq ($(KBUILD_TARGET),freebsd)
+
+ else ifeq ($(KBUILD_TARGET),freebsd)
$(VBOX_PATH_CROGL_GENFILES)/freebsd_exports.c: \
$(PATH_SUB_CURRENT)/FreeBSD_exports.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- else
+
+ else
$(VBOX_PATH_CROGL_GENFILES)/linux_exports.asm: \
$(PATH_SUB_CURRENT)/Linux_i386_exports.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- endif
-else ifdef VBoxOGL_DRI
+ endif
+
+ else ifdef VBoxOGL_DRI
$(VBOX_PATH_CROGL_GENFILES)/cr_gl.h: $(PATH_SUB_CURRENT)/cr_gl.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
$(VBOX_PATH_CROGL_GENFILES)/DD_gl.h: $(PATH_SUB_CURRENT)/DD_glh.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
$(VBOX_PATH_CROGL_GENFILES)/DD_gl.c: $(PATH_SUB_CURRENT)/DD_glc.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- ifeq ($(KBUILD_TARGET),solaris)
+
+ ifeq ($(KBUILD_TARGET),solaris)
$(VBOX_PATH_CROGL_GENFILES)/solaris_exports_dri.asm: \
$(PATH_SUB_CURRENT)/SunOS_i386_exports_dri.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- else ifeq ($(KBUILD_TARGET),freebsd)
+
+ else ifeq ($(KBUILD_TARGET),freebsd)
$(VBOX_PATH_CROGL_GENFILES)/freebsd_exports_dri.asm: \
$(PATH_SUB_CURRENT)/FreeBSD_i386_exports_dri.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- else
+
+ else
$(VBOX_PATH_CROGL_GENFILES)/linux_exports_dri.asm: \
$(PATH_SUB_CURRENT)/Linux_i386_exports_dri.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- endif
-else ifdef VBoxOGL_FAKEDRI
+ endif
+
+ else ifdef VBoxOGL_FAKEDRI
$(VBOX_PATH_CROGL_GENFILES)/cr_gl.h: $(PATH_SUB_CURRENT)/cr_gl.py $(VBOX_CROGL_API_FILES) | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- ifndef VBOX_OGL_GLX_USE_CSTUBS
- ifeq ($(KBUILD_TARGET),solaris)
+
+ ifndef VBOX_OGL_GLX_USE_CSTUBS
+ ifeq ($(KBUILD_TARGET),solaris)
$(VBOX_PATH_CROGL_GENFILES)/solaris_exports_dri.asm: \
$(PATH_SUB_CURRENT)/SunOS_i386_exports_dri.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
@@ -349,7 +385,8 @@ $(VBOX_PATH_CROGL_GENFILES)/solaris_exports_dri.asm: \
$(VBOX_PATH_CROGL_GENFILES)/solaris_glxapi_exports.asm: $(PATH_SUB_CURRENT)/SunOS_i386_glxapi_exports.py | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $<
- else
+
+ else
$(VBOX_PATH_CROGL_GENFILES)/linux_exports_dri.asm: \
$(PATH_SUB_CURRENT)/Linux_i386_exports_dri.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
@@ -359,15 +396,24 @@ $(VBOX_PATH_CROGL_GENFILES)/linux_exports_dri.asm: \
$(VBOX_PATH_CROGL_GENFILES)/linux_glxapi_exports.asm: $(PATH_SUB_CURRENT)/Linux_i386_glxapi_exports.py | $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $<
- endif
- else
- ifeq ($(KBUILD_TARGET),solaris)
+ endif
+
+ else
+ ifeq ($(KBUILD_TARGET),solaris)
$(VBOX_PATH_CROGL_GENFILES)/solaris_exports.c: \
$(PATH_SUB_CURRENT)/SunOS_exports.py \
$(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
+
+ else ifeq ($(KBUILD_TARGET),freebsd)
+$(VBOX_PATH_CROGL_GENFILES)/freebsd_exports.c: \
+ $(PATH_SUB_CURRENT)/FreeBSD_exports.py \
+ $(VBOX_CROGL_API_FILES) $(PATH_SUB_CURRENT)/entrypoints.py \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
else
$(VBOX_PATH_CROGL_GENFILES)/linux_exports.c: \
$(PATH_SUB_CURRENT)/Linux_exports.py \
@@ -375,9 +421,10 @@ $(VBOX_PATH_CROGL_GENFILES)/linux_exports.c: \
| $$(dir $$@)
$(call MSG_GENERATE,python,$@,$<)
$(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI)
- endif
- endif # VBOX_OGL_GLX_USE_CSTUBS
-endif
+ endif
+
+ endif # VBOX_OGL_GLX_USE_CSTUBS
+ endif
endif
#
@@ -420,7 +467,6 @@ ifdef VBOX_WITH_WDDM
#
# VBoxOGLarrayspu-x86 - x86 version of VBoxOGLarrayspu built for amd64 build
#
-DLLS.win.amd64 += VBoxOGLarrayspu-x86
VBoxOGLarrayspu-x86_EXTENDS = VBoxOGLarrayspu
VBoxOGLarrayspu-x86_BLD_TRG_ARCH = x86
VBoxOGLarrayspu-x86_LIBS = $(VBOX_LIB_OGL_CRUTIL_X86) \
@@ -464,7 +510,6 @@ ifdef VBOX_WITH_WDDM
#
# VBoxOGLpassthroughspu-x86 - x86 version of VBoxOGLpassthroughspu built for amd64 build
#
-DLLS.win.amd64 += VBoxOGLpassthroughspu-x86
VBoxOGLpassthroughspu-x86_EXTENDS = VBoxOGLpassthroughspu
VBoxOGLpassthroughspu-x86_BLD_TRG_ARCH = x86
VBoxOGLpassthroughspu-x86_LIBS = $(VBOX_LIB_OGL_CRUTIL_X86)
@@ -532,6 +577,12 @@ VBoxOGLpackspu_LIBS = \
ifdef VBOX_WITH_CRHGSMI
VBoxOGLpackspu_DEFS.win += VBOX_WITH_CRHGSMI
endif
+ifdef VBOX_WITH_CRDUMPER
+VBoxOGLpackspu_DEFS += VBOX_WITH_CRDUMPER
+endif
+ifdef VBOX_WITH_CRPACKSPU_DUMPER
+VBoxOGLpackspu_DEFS += VBOX_WITH_CRPACKSPU_DUMPER
+endif
ifdef VBOX_WITH_WDDM
VBoxOGLpackspu_DEFS.win += VBOX_WITH_WDDM
endif
@@ -540,7 +591,6 @@ ifdef VBOX_WITH_WDDM
#
# VBoxOGLpackspu-x86 - x86 version of VBoxOGLpackspu built for amd64 build
#
-DLLS.win.amd64 += VBoxOGLpackspu-x86
VBoxOGLpackspu-x86_EXTENDS = VBoxOGLpackspu
VBoxOGLpackspu-x86_BLD_TRG_ARCH = x86
VBoxOGLpackspu-x86_LIBS = $(VBOX_LIB_OGL_CRUTIL_X86) \
@@ -617,7 +667,6 @@ ifdef VBOX_WITH_WDDM
#
# VBoxOGLfeedbackspu-x86 - x86 version of VBoxOGLfeedbackspu built for amd64 build
#
-DLLS.win.amd64 += VBoxOGLfeedbackspu-x86
VBoxOGLfeedbackspu-x86_EXTENDS = VBoxOGLfeedbackspu
VBoxOGLfeedbackspu-x86_BLD_TRG_ARCH = x86
VBoxOGLfeedbackspu-x86_LIBS = $(VBOX_LIB_OGL_CRUTIL_X86) \
diff --git a/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports.py b/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports.py
index b7fe6b9f..7fc6cddb 100755
--- a/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports.py
+++ b/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports.py
@@ -1,5 +1,5 @@
"""
-Copyright (C) 2009 Oracle Corporation
+Copyright (C) 2009-2012 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports_dri.py b/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports_dri.py
index 7d9378e6..26903439 100755
--- a/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports_dri.py
+++ b/src/VBox/Additions/common/crOpenGL/SunOS_i386_exports_dri.py
@@ -1,5 +1,5 @@
"""
-Copyright (C) 2009 Oracle Corporation
+Copyright (C) 2009-2012 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/SunOS_i386_glxapi_exports.py b/src/VBox/Additions/common/crOpenGL/SunOS_i386_glxapi_exports.py
index d395732d..e835ecb2 100755
--- a/src/VBox/Additions/common/crOpenGL/SunOS_i386_glxapi_exports.py
+++ b/src/VBox/Additions/common/crOpenGL/SunOS_i386_glxapi_exports.py
@@ -1,5 +1,5 @@
"""
-Copyright (C) 2009 Oracle Corporation
+Copyright (C) 2009-2012 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/VBoxICDList.h b/src/VBox/Additions/common/crOpenGL/VBoxICDList.h
index 54c7e452..cc43c1c6 100644
--- a/src/VBox/Additions/common/crOpenGL/VBoxICDList.h
+++ b/src/VBox/Additions/common/crOpenGL/VBoxICDList.h
@@ -2,7 +2,7 @@
*
* VirtualBox Windows NT/2000/XP guest OpenGL ICD
*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/context.c b/src/VBox/Additions/common/crOpenGL/context.c
index 4a077a5d..6c6e4b97 100644
--- a/src/VBox/Additions/common/crOpenGL/context.c
+++ b/src/VBox/Additions/common/crOpenGL/context.c
@@ -107,6 +107,22 @@ void stubForcedFlush(GLint con)
#endif
}
+void stubConChromiumParameteriCR(GLint con, GLenum param, GLint value)
+{
+ if (con)
+ stub.spu->dispatch_table.VBoxConChromiumParameteriCR(con, param, value);
+ else
+ crError("VBoxConChromiumParameteriCR called with null connection");
+}
+
+void stubConFlush(GLint con)
+{
+ if (con)
+ stub.spu->dispatch_table.VBoxConFlush(con);
+ else
+ crError("stubConFlush called with null connection");
+}
+
static void stubWindowCleanupForContextsCB(unsigned long key, void *data1, void *data2)
{
ContextInfo *context = (ContextInfo *) data1;
@@ -144,6 +160,7 @@ void stubDestroyWindow( GLint con, GLint window )
}
# endif
#endif
+
stubForcedFlush(con);
crHashtableWalk(stub.contextTable, stubWindowCleanupForContextsCB, winInfo);
@@ -189,7 +206,7 @@ stubNewWindow( const char *dpyName, GLint visBits )
#ifdef VBOX_WITH_WDDM
if (stub.bRunningUnderWDDM)
{
- crError("Should not be here: WindowCreate/Destroy & VBoxPackGetInjectID recuire connection id!");
+ crError("Should not be here: WindowCreate/Destroy & VBoxPackGetInjectID require connection id!");
winInfo->mapped = 0;
}
else
@@ -433,10 +450,6 @@ stubDestroyContextLocked( ContextInfo *context )
#ifdef GLX
crFreeHashtable(context->pGLXPixmapsHash, crFree);
- if (context->damageDpy)
- {
- XCloseDisplay(context->damageDpy);
- }
#endif
crHashtableDelete(stub.contextTable, contextId, NULL);
@@ -535,8 +548,7 @@ stubNewContext( const char *dpyName, GLint visBits, ContextType type,
#ifdef GLX
context->pGLXPixmapsHash = crAllocHashtable();
- context->damageInitFailed = GL_FALSE;
- context->damageDpy = NULL;
+ context->damageQueryFailed = GL_FALSE;
context->damageEventsBase = 0;
#endif
@@ -1089,6 +1101,50 @@ static void stubWindowCheckOwnerCB(unsigned long key, void *data1, void *data2)
}
}
+GLboolean stubCtxCreate(ContextInfo *context)
+{
+ /*
+ * Create a Chromium context.
+ */
+#if defined(GLX) || defined(DARWIN)
+ GLint spuShareCtx = context->share ? context->share->spuContext : 0;
+#else
+ GLint spuShareCtx = 0;
+#endif
+ GLint spuConnection = 0;
+ CRASSERT(stub.spu);
+ CRASSERT(stub.spu->dispatch_table.CreateContext);
+ context->type = CHROMIUM;
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ if (context->pHgsmi)
+ {
+ spuConnection = stub.spu->dispatch_table.VBoxConCreate(context->pHgsmi);
+ if (!spuConnection)
+ {
+ crWarning("VBoxConCreate failed");
+ return GL_FALSE;
+ }
+ context->spuConnection = spuConnection;
+ }
+#endif
+
+ context->spuContext
+ = stub.spu->dispatch_table.VBoxCreateContext(spuConnection, context->dpyName,
+ context->visBits,
+ spuShareCtx);
+
+ return GL_TRUE;
+}
+
+GLboolean stubCtxCheckCreate(ContextInfo *context)
+{
+ if (context->type == UNDECIDED)
+ return stubCtxCreate(context);
+ return CHROMIUM == context->type;
+}
+
+
GLboolean
stubMakeCurrent( WindowInfo *window, ContextInfo *context )
{
@@ -1119,42 +1175,22 @@ stubMakeCurrent( WindowInfo *window, ContextInfo *context )
#endif
if (stubCheckUseChromium(window)) {
- /*
- * Create a Chromium context.
- */
-#if defined(GLX) || defined(DARWIN)
- GLint spuShareCtx = context->share ? context->share->spuContext : 0;
-#else
- GLint spuShareCtx = 0;
-#endif
GLint spuConnection = 0;
- CRASSERT(stub.spu);
- CRASSERT(stub.spu->dispatch_table.CreateContext);
- context->type = CHROMIUM;
-#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
- if (context->pHgsmi)
+ if (!stubCtxCreate(context))
{
- spuConnection = stub.spu->dispatch_table.VBoxConCreate(context->pHgsmi);
- if (!spuConnection)
- {
- crWarning("VBoxConCreate failed");
- return GL_FALSE;
- }
- context->spuConnection = spuConnection;
+ crWarning("stubCtxCreate failed");
+ return GL_FALSE;
}
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ spuConnection = context->spuConnection;
#endif
- context->spuContext
- = stub.spu->dispatch_table.VBoxCreateContext(spuConnection, context->dpyName,
- context->visBits,
- spuShareCtx);
if (window->spuWindow == -1)
{
/*crDebug("(1)stubMakeCurrent ctx=%p(%i) window=%p(%i)", context, context->spuContext, window, window->spuWindow);*/
- window->spuWindow = stub.spu->dispatch_table.VBoxWindowCreate(
- spuConnection,
- window->dpyName, context->visBits );
+ window->spuWindow = stub.spu->dispatch_table.VBoxWindowCreate(spuConnection, window->dpyName, context->visBits );
#ifdef CR_NEWWINTRACK
window->u32ClientID = stub.spu->dispatch_table.VBoxPackGetInjectID(spuConnection);
#endif
@@ -1311,7 +1347,8 @@ stubMakeCurrent( WindowInfo *window, ContextInfo *context )
stub.spu->dispatch_table.Viewport( 0, 0, winW, winH );
}
#ifdef VBOX_WITH_WDDM
- stub.spu->dispatch_table.WindowVisibleRegion(window->spuWindow, 0, NULL);
+ if (stub.trackWindowVisibleRgn)
+ stub.spu->dispatch_table.WindowVisibleRegion(window->spuWindow, 0, NULL);
#endif
}
diff --git a/src/VBox/Additions/common/crOpenGL/defs.py b/src/VBox/Additions/common/crOpenGL/defs.py
index 5129f0db..de0d031e 100644
--- a/src/VBox/Additions/common/crOpenGL/defs.py
+++ b/src/VBox/Additions/common/crOpenGL/defs.py
@@ -9,8 +9,9 @@ import apiutil
apiutil.CopyrightDef()
-print "LIBRARY VBoxOGL"
-print "DESCRIPTION \"\""
+# NOTE: if we need a LIBRARY statement, we would need to create a defs-x86.py to generate a .def file for VBoxOGL-x86 library
+#print "LIBRARY VBoxOGL"
+#print "DESCRIPTION \"\"" - warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
print "EXPORTS"
# XXX can't these values be automatically computed by analyzing parameters?
@@ -454,7 +455,7 @@ for func_name in ( "wglChoosePixelFormat",
"wglGetPixelFormatAttribivEXT",
"wglGetPixelFormatAttribfvEXT",
"wglGetExtensionsStringEXT"):
- print "%s@%d = %s_prox" % (func_name,stack_sizes[func_name],func_name)
+ print "%s = %s_prox" % (func_name,func_name)
"""
for func_name in ( "CopyContext",
@@ -495,5 +496,9 @@ print """crCreateContext
crMakeCurrent
crSwapBuffers
crGetProcAddress
-VBoxCreateContext"""
+VBoxCreateContext
+VBoxCtxChromiumParameteriCR
+VBoxGetWindowId
+VBoxGetContextId
+VBoxFlushToHost"""
#print "DllMain"
diff --git a/src/VBox/Additions/common/crOpenGL/defs64.py b/src/VBox/Additions/common/crOpenGL/defs64.py
index e98bb89b..68b3fd21 100644
--- a/src/VBox/Additions/common/crOpenGL/defs64.py
+++ b/src/VBox/Additions/common/crOpenGL/defs64.py
@@ -9,8 +9,8 @@ import apiutil
apiutil.CopyrightDef()
-print "LIBRARY VBoxOGL"
-print "DESCRIPTION \"\""
+#print "LIBRARY VBoxOGL"
+#print "DESCRIPTION \"\"" - warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
print "EXPORTS"
# XXX can't these values be automatically computed by analyzing parameters?
@@ -476,5 +476,9 @@ print """crCreateContext
crMakeCurrent
crSwapBuffers
crGetProcAddress
-VBoxCreateContext"""
+VBoxCreateContext
+VBoxCtxChromiumParameteriCR
+VBoxGetWindowId
+VBoxGetContextId
+VBoxFlushToHost"""
#print "DllMain"
diff --git a/src/VBox/Additions/common/crOpenGL/dri_drv.c b/src/VBox/Additions/common/crOpenGL/dri_drv.c
index d19b99b1..37f501e9 100644
--- a/src/VBox/Additions/common/crOpenGL/dri_drv.c
+++ b/src/VBox/Additions/common/crOpenGL/dri_drv.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/dri_drv.h b/src/VBox/Additions/common/crOpenGL/dri_drv.h
index 9ee57766..7c5807d2 100644
--- a/src/VBox/Additions/common/crOpenGL/dri_drv.h
+++ b/src/VBox/Additions/common/crOpenGL/dri_drv.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/dri_glx.h b/src/VBox/Additions/common/crOpenGL/dri_glx.h
index a2a38970..5ff29561 100644
--- a/src/VBox/Additions/common/crOpenGL/dri_glx.h
+++ b/src/VBox/Additions/common/crOpenGL/dri_glx.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/fakedri_drv.c b/src/VBox/Additions/common/crOpenGL/fakedri_drv.c
index 8e7b6ba5..f6793dab 100644
--- a/src/VBox/Additions/common/crOpenGL/fakedri_drv.c
+++ b/src/VBox/Additions/common/crOpenGL/fakedri_drv.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -29,6 +29,15 @@
#include <dlfcn.h>
#include <elf.h>
#include <unistd.h>
+
+#if defined(RT_OS_FREEBSD)
+#include <sys/param.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <string.h>
+#endif
+
/** X server message type definitions. */
typedef enum {
X_PROBED, /* Value was probed */
@@ -50,11 +59,21 @@ typedef enum {
//@todo this could be different...
#ifdef RT_ARCH_AMD64
-# define DRI_DEFAULT_DRIVER_DIR "/usr/lib64/dri:/usr/lib/dri:/usr/lib/x86_64-linux-gnu/dri"
-# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
+# ifdef RT_OS_FREEBSD
+# define DRI_DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
+# define DRI_XORG_DRV_DIR "/usr/local/lib/xorg/modules/drivers/"
+# else
+# define DRI_DEFAULT_DRIVER_DIR "/usr/lib64/dri:/usr/lib/dri:/usr/lib/x86_64-linux-gnu/dri:/usr/lib/xorg/modules/dri"
+# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
+# endif
#else
-# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri:/usr/lib/i386-linux-gnu/dri"
-# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
+# ifdef RT_OS_FREEBSD
+# define DRI_DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
+# define DRI_XORG_DRV_DIR "/usr/local/lib/xorg/modules/drivers/"
+# else
+# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri:/usr/lib/i386-linux-gnu/dri:/usr/lib/xorg/modules/dri"
+# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
+# endif
#endif
#ifdef DEBUG_DRI_CALLS
@@ -209,6 +228,85 @@ vboxApplyPatch(const char* psFuncName, void *pDst, const void *pSrc, unsigned lo
#define FAKEDRI_JMP64_PATCH_SIZE 13
+#if defined(RT_OS_FREEBSD)
+/* Provide basic dladdr1 flags */
+enum {
+ RTLD_DL_SYMENT = 1
+};
+
+/* Provide a minimal local version of dladdr1 */
+static int
+dladdr1(const void *address, Dl_info *dlip, void **info, int flags)
+{
+ static DRI_ELFSYM desym;
+ GElf_Sym sym;
+ GElf_Shdr shdr;
+ Elf *elf;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ int ret, fd, count, i;
+
+ /* Initialize variables */
+ fd = -1;
+ elf = NULL;
+
+ /* Call dladdr first */
+ ret = dladdr(address, dlip);
+ if (ret == 0) goto err_exit;
+
+ /* Check for supported flags */
+ if (flags != RTLD_DL_SYMENT) return 1;
+
+ /* Open shared library's ELF file */
+ if (elf_version(EV_CURRENT) == EV_NONE) goto err_exit;
+ fd = open(dlip->dli_fname, O_RDONLY);
+ if (fd < 0) goto err_exit;
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == NULL) goto err_exit;
+
+ /* Find the '.dynsym' section */
+ scn = elf_nextscn(elf, NULL);
+ while (scn != NULL) {
+ if (gelf_getshdr(scn, &shdr) == NULL) goto err_exit;
+ if (shdr.sh_type == SHT_DYNSYM) break;
+ scn = elf_nextscn(elf, scn);
+ }
+ if (scn == NULL) goto err_exit;
+
+ /* Search for the requested symbol by name and offset */
+ data = elf_getdata(scn, NULL);
+ count = shdr.sh_size / shdr.sh_entsize;
+ for (i = 0; i < count; i++) {
+ gelf_getsym(data, i, &sym);
+ if ((strcmp(dlip->dli_sname,
+ elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) &&
+ (sym.st_value == (dlip->dli_saddr - dlip->dli_fbase))) {
+ break;
+ }
+ }
+
+ /* Close ELF file */
+ elf_end(elf);
+ close(fd);
+
+ /* Return symbol entry in native format */
+ desym.st_name = sym.st_name;
+ desym.st_info = sym.st_info;
+ desym.st_other = sym.st_other;
+ desym.st_shndx = sym.st_shndx;
+ desym.st_value = sym.st_value;
+ desym.st_size = sym.st_size;
+ *info = &desym;
+ return 1;
+
+ /* Error handler */
+err_exit:
+ if (elf != NULL) elf_end(elf);
+ if (fd >= 0) close(fd);
+ return 0;
+}
+#endif
+
static void
vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
{
@@ -262,7 +360,7 @@ vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
- crDebug("Vbox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
+ crDebug("VBox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
#endif
#ifndef VBOX_OGL_GLX_USE_CSTUBS
diff --git a/src/VBox/Additions/common/crOpenGL/fakedri_drv.h b/src/VBox/Additions/common/crOpenGL/fakedri_drv.h
index 0d94e1c3..acbc7116 100644
--- a/src/VBox/Additions/common/crOpenGL/fakedri_drv.h
+++ b/src/VBox/Additions/common/crOpenGL/fakedri_drv.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/fakedri_glfuncsList.h b/src/VBox/Additions/common/crOpenGL/fakedri_glfuncsList.h
index ce5510f5..a8551de6 100644
--- a/src/VBox/Additions/common/crOpenGL/fakedri_glfuncsList.h
+++ b/src/VBox/Additions/common/crOpenGL/fakedri_glfuncsList.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/fakedri_glxfuncsList.h b/src/VBox/Additions/common/crOpenGL/fakedri_glxfuncsList.h
index c1592cdf..6c449f85 100644
--- a/src/VBox/Additions/common/crOpenGL/fakedri_glxfuncsList.h
+++ b/src/VBox/Additions/common/crOpenGL/fakedri_glxfuncsList.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/feedback/feedback_context.c b/src/VBox/Additions/common/crOpenGL/feedback/feedback_context.c
index 232a7c67..2dc757ae 100644
--- a/src/VBox/Additions/common/crOpenGL/feedback/feedback_context.c
+++ b/src/VBox/Additions/common/crOpenGL/feedback/feedback_context.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/glx.c b/src/VBox/Additions/common/crOpenGL/glx.c
index cdb43590..328ed208 100644
--- a/src/VBox/Additions/common/crOpenGL/glx.c
+++ b/src/VBox/Additions/common/crOpenGL/glx.c
@@ -57,7 +57,7 @@ struct VisualInfo {
static struct VisualInfo *VisualInfoList = NULL;
static void stubXshmUpdateImageRect(Display *dpy, GLXDrawable draw, GLX_Pixmap_t *pGlxPixmap, XRectangle *pRect);
-static void stubInitXDamageExtension(ContextInfo *pContext);
+static void stubQueryXDamageExtension(Display *dpy, ContextInfo *pContext);
static void
AddVisualInfo(Display *dpy, int screen, VisualID visualid, int visBits)
@@ -624,9 +624,7 @@ VBOXGLXTAG(glXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext share, B
context->visual = vis;
context->direct = direct;
- /* This means that clients can't hold a server grab during
- * glXCreateContext! */
- stubInitXDamageExtension(context);
+ stubQueryXDamageExtension(dpy, context);
return (GLXContext) context->id;
}
@@ -830,7 +828,7 @@ DECLEXPORT(int) VBOXGLXTAG(glXGetConfig)( Display *dpy, XVisualInfo *vis, int at
case GLX_DEPTH_SIZE:
visBits |= CR_DEPTH_BIT;
- *value = 16;
+ *value = 24;
break;
case GLX_STENCIL_SIZE:
@@ -969,7 +967,7 @@ DECLEXPORT(int) VBOXGLXTAG(glXGetConfig)( Display *dpy, XVisualInfo *vis, int at
break;
case GLX_DEPTH_SIZE:
- *value = 16;
+ *value = 24;
break;
case GLX_STENCIL_SIZE:
@@ -1501,7 +1499,7 @@ VBOXGLXTAG(glXChooseFBConfig)(Display *dpy, int screen, ATTRIB_TYPE *attrib_list
break;
case GLX_DEPTH_SIZE:
- if (attrib[1] > 16)
+ if (attrib[1] > 24)
goto err_exit;
attrib++;
break;
@@ -1533,7 +1531,8 @@ VBOXGLXTAG(glXChooseFBConfig)(Display *dpy, int screen, ATTRIB_TYPE *attrib_list
break;
case GLX_DRAWABLE_TYPE:
- if (attrib[1]!=GLX_WINDOW_BIT)
+ if ( !(attrib[1] & GLX_WINDOW_BIT)
+ && !(attrib[1] & GLX_PIXMAP_BIT))
goto err_exit;
attrib++;
break;
@@ -1782,7 +1781,7 @@ DECLEXPORT(void) VBOXGLXTAG(glXDestroyPixmap)(Display *dpy, GLXPixmap pixmap)
if (parms.pGlxPixmap->hDamage>0)
{
//crDebug("Destroy: Damage for drawable 0x%x, handle 0x%x", (unsigned int) pixmap, (unsigned int) parms.pGlxPixmap->damage);
- XDamageDestroy(parms.pCtx->damageDpy, parms.pGlxPixmap->hDamage);
+ XDamageDestroy(dpy, parms.pGlxPixmap->hDamage);
}
if (parms.pGlxPixmap->pDamageRegion)
@@ -1822,7 +1821,7 @@ DECLEXPORT(int) VBOXGLXTAG(glXGetFBConfigAttrib)(Display *dpy, GLXFBConfig confi
switch (attribute)
{
case GLX_DRAWABLE_TYPE:
- *value = GLX_PIXMAP_BIT;
+ *value = GLX_PIXMAP_BIT | GLX_WINDOW_BIT;
break;
case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
*value = GLX_TEXTURE_2D_BIT_EXT;
@@ -1860,7 +1859,7 @@ DECLEXPORT(int) VBOXGLXTAG(glXGetFBConfigAttrib)(Display *dpy, GLXFBConfig confi
*value = 8;
break;
case GLX_DEPTH_SIZE:
- *value = 16;
+ *value = 24;
//crDebug("attribute=GLX_DEPTH_SIZE");
break;
case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
@@ -2172,69 +2171,76 @@ static void stubInitXSharedMemory(Display *dpy)
#endif
}
-void stubInitXDamageExtension(ContextInfo *pContext)
+void stubQueryXDamageExtension(Display *dpy, ContextInfo *pContext)
{
int erb, vma, vmi;
CRASSERT(pContext);
- if (pContext->damageInitFailed || pContext->damageDpy)
+ if (pContext->damageQueryFailed)
return;
- pContext->damageInitFailed = True;
-
- /* Open second xserver connection to make sure we'd receive all the xdamage messages
- * and those wouldn't be eaten by application even queue */
- pContext->damageDpy = XOpenDisplay(DisplayString(pContext->dpy));
-
- if (!pContext->damageDpy)
- {
- crWarning("XDamage: Can't connect to display %s", DisplayString(pContext->dpy));
- return;
- }
+ pContext->damageQueryFailed = True;
- if (!XDamageQueryExtension(pContext->damageDpy, &pContext->damageEventsBase, &erb)
- || !XDamageQueryVersion(pContext->damageDpy, &vma, &vmi))
+ if (!XDamageQueryExtension(dpy, &pContext->damageEventsBase, &erb)
+ || !XDamageQueryVersion(dpy, &vma, &vmi))
{
crWarning("XDamage not found or old version (%i.%i), going to run *very* slow", vma, vmi);
- XCloseDisplay(pContext->damageDpy);
- pContext->damageDpy = NULL;
return;
}
crDebug("XDamage %i.%i", vma, vmi);
- pContext->damageInitFailed = False;
+ pContext->damageQueryFailed = False;
}
-static void stubCheckXDamageCB(unsigned long key, void *data1, void *data2)
+static void stubFetchDamageOnDrawable(Display *dpy, GLX_Pixmap_t *pGlxPixmap)
{
- GLX_Pixmap_t *pGlxPixmap = (GLX_Pixmap_t *) data1;
- XDamageNotifyEvent *e = (XDamageNotifyEvent *) data2;
+ Damage damage = pGlxPixmap->hDamage;
- if (pGlxPixmap->hDamage==e->damage)
+ if (damage)
{
- /*crDebug("Event: Damage for pixmap 0x%lx(drawable 0x%x), handle 0x%x (level=%i) [%i,%i,%i,%i]",
- key, (unsigned int) e->drawable, (unsigned int) e->damage, (int) e->level,
- e->area.x, e->area.y, e->area.width, e->area.height);*/
+ XRectangle *returnRects;
+ int nReturnRects;
+
+ /* Get the damage region as a server region */
+ XserverRegion serverDamageRegion = XFixesCreateRegion (dpy, NULL, 0);
+
+ /* Unite damage region with server region and clear damage region */
+ XDamageSubtract (dpy,
+ damage,
+ None, /* subtract all damage from this region */
+ serverDamageRegion /* save in serverDamageRegion */);
+
+ /* Fetch damage rectangles */
+ returnRects = XFixesFetchRegion (dpy, serverDamageRegion, &nReturnRects);
+
+ /* Delete region */
+ XFixesDestroyRegion (dpy, serverDamageRegion);
if (pGlxPixmap->pDamageRegion)
{
/* If it's dirty and regions are empty, it marked for full update, so do nothing.*/
if (!pGlxPixmap->bPixmapImageDirty || !XEmptyRegion(pGlxPixmap->pDamageRegion))
{
- if (CR_MAX_DAMAGE_REGIONS_TRACKED <= pGlxPixmap->pDamageRegion->numRects)
+ int i = 0;
+ for (; i < nReturnRects; ++i)
{
- /* Mark for full update */
- EMPTY_REGION(pGlxPixmap->pDamageRegion);
- }
- else
- {
- /* Add to damage regions */
- XUnionRectWithRegion(&e->area, pGlxPixmap->pDamageRegion, pGlxPixmap->pDamageRegion);
+ if (CR_MAX_DAMAGE_REGIONS_TRACKED <= pGlxPixmap->pDamageRegion->numRects)
+ {
+ /* Mark for full update */
+ EMPTY_REGION(pGlxPixmap->pDamageRegion);
+ }
+ else
+ {
+ /* Add to damage regions */
+ XUnionRectWithRegion(&returnRects[i], pGlxPixmap->pDamageRegion, pGlxPixmap->pDamageRegion);
+ }
}
}
}
+ XFree(returnRects);
+
pGlxPixmap->bPixmapImageDirty = True;
}
}
@@ -2338,9 +2344,9 @@ static GLX_Pixmap_t* stubInitGlxPixmap(GLX_Pixmap_t* pCreateInfoPixmap, Display
XUNLOCK(dpy);
/* If there's damage extension, then get handle for damage events related to this pixmap */
- if (pContext->damageDpy)
+ if (!pContext->damageQueryFailed)
{
- pGlxPixmap->hDamage = XDamageCreate(pContext->damageDpy, (Pixmap)draw, XDamageReportRawRectangles);
+ pGlxPixmap->hDamage = XDamageCreate(dpy, (Pixmap)draw, XDamageReportNonEmpty);
/*crDebug("Create: Damage for drawable 0x%x, handle 0x%x (level=%i)",
(unsigned int) draw, (unsigned int) pGlxPixmap->damage, (int) XDamageReportRawRectangles);*/
pGlxPixmap->pDamageRegion = XCreateRegion();
@@ -2532,24 +2538,14 @@ DECLEXPORT(void) VBOXGLXTAG(glXBindTexImageEXT)(Display *dpy, GLXDrawable draw,
}
/* If there's damage extension, then process incoming events as we need the information right now */
- if (context->damageDpy)
+ if (!context->damageQueryFailed)
{
- /* Sync connections, note that order of syncs is important here.
- * First make sure client commands are finished, then make sure we get all the damage events back*/
+ /* Sync connection */
XLOCK(dpy);
XSync(dpy, False);
XUNLOCK(dpy);
- XSync(context->damageDpy, False);
- while (XPending(context->damageDpy))
- {
- XEvent event;
- XNextEvent(context->damageDpy, &event);
- if (event.type==context->damageEventsBase+XDamageNotify)
- {
- crHashtableWalk(context->pGLXPixmapsHash, stubCheckXDamageCB, &event);
- }
- }
+ stubFetchDamageOnDrawable(dpy, pGlxPixmap);
}
/* No shared memory? Rollback to use slow x protocol then */
@@ -2597,7 +2593,7 @@ DECLEXPORT(void) VBOXGLXTAG(glXBindTexImageEXT)(Display *dpy, GLXDrawable draw,
else /* Use shm to get pixmap data */
{
/* Check if we have damage extension */
- if (context->damageDpy)
+ if (!context->damageQueryFailed)
{
if (pGlxPixmap->bPixmapImageDirty)
{
diff --git a/src/VBox/Additions/common/crOpenGL/glx_c_exports.c b/src/VBox/Additions/common/crOpenGL/glx_c_exports.c
index 4f94870a..183c0219 100644
--- a/src/VBox/Additions/common/crOpenGL/glx_c_exports.c
+++ b/src/VBox/Additions/common/crOpenGL/glx_c_exports.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/glx_proto.h b/src/VBox/Additions/common/crOpenGL/glx_proto.h
index 2ab6d05c..61084749 100644
--- a/src/VBox/Additions/common/crOpenGL/glx_proto.h
+++ b/src/VBox/Additions/common/crOpenGL/glx_proto.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/icd_drv.c b/src/VBox/Additions/common/crOpenGL/icd_drv.c
index 22a9eadb..cff7f9ac 100644
--- a/src/VBox/Additions/common/crOpenGL/icd_drv.c
+++ b/src/VBox/Additions/common/crOpenGL/icd_drv.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/icd_drv.h b/src/VBox/Additions/common/crOpenGL/icd_drv.h
index e610de15..46c0b56c 100644
--- a/src/VBox/Additions/common/crOpenGL/icd_drv.h
+++ b/src/VBox/Additions/common/crOpenGL/icd_drv.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/crOpenGL/load.c b/src/VBox/Additions/common/crOpenGL/load.c
index a9cf34e1..35d1f72a 100644
--- a/src/VBox/Additions/common/crOpenGL/load.c
+++ b/src/VBox/Additions/common/crOpenGL/load.c
@@ -47,10 +47,6 @@
#define PYTHON_EXE "python"
#endif
-#ifdef WINDOWS
-static char* gsViewportHackApps[] = {"googleearth.exe", NULL};
-#endif
-
static bool stub_initialized = 0;
#ifdef WINDOWS
static CRmutex stub_init_mutex;
@@ -213,16 +209,19 @@ static void stubCheckWindowsState(void)
return;
#endif
+ /* Try to keep a consistent locking order. */
+ crHashtableLock(stub.windowTable);
#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
crLockMutex(&stub.mutex);
#endif
stubCheckWindowState(context->currentDrawable, GL_TRUE);
- crHashtableWalk(stub.windowTable, stubCheckWindowsCB, context);
+ crHashtableWalkUnlocked(stub.windowTable, stubCheckWindowsCB, context);
#if defined(CR_NEWWINTRACK) && !defined(WINDOWS)
crUnlockMutex(&stub.mutex);
#endif
+ crHashtableUnlock(stub.windowTable);
}
@@ -246,20 +245,7 @@ static void SPU_APIENTRY trapViewport(GLint x, GLint y, GLsizei w, GLsizei h)
{
stubCheckWindowsState();
/* call the original SPU glViewport function */
- if (!stub.viewportHack)
- {
- origViewport(x, y, w, h);
- }
- else
- {
- ContextInfo *context = stubGetCurrentContext();
- int winX, winY;
- unsigned int winW, winH;
- WindowInfo *pWindow;
- pWindow = context->currentDrawable;
- stubGetWindowGeometry(pWindow, &winX, &winY, &winW, &winH);
- origViewport(0, 0, winW, winH);
- }
+ origViewport(x, y, w, h);
}
static void SPU_APIENTRY trapSwapBuffers(GLint window, GLint flags)
@@ -304,8 +290,6 @@ static void stubInitSPUDispatch(SPU *spu)
stub.spuDispatch.Clear = trapClear;
stub.spuDispatch.Viewport = trapViewport;
- if (stub.viewportHack)
- stub.spuDispatch.Scissor = trapScissor;
/*stub.spuDispatch.SwapBuffers = trapSwapBuffers;
stub.spuDispatch.DrawBuffer = trapDrawBuffer;*/
}
@@ -415,7 +399,7 @@ static void stubSPUSafeTearDown(void)
#if defined(CR_NEWWINTRACK)
crUnlockMutex(mutex);
# if defined(WINDOWS)
- if (RTThreadGetState(stub.hSyncThread)!=RTTHREADSTATE_TERMINATED)
+ if (stub.hSyncThread && RTThreadGetState(stub.hSyncThread)!=RTTHREADSTATE_TERMINATED)
{
HANDLE hNative;
DWORD ec=0;
@@ -752,30 +736,11 @@ void stubSetDefaultConfigurationOptions(void)
crNetSetNodeRange("iam0", "iamvis20");
crNetSetKey(key,sizeof(key));
stub.force_pbuffers = 0;
- stub.viewportHack = 0;
#ifdef WINDOWS
- {
- char name[1000];
- int i;
-
# ifdef VBOX_WITH_WDDM
- stub.bRunningUnderWDDM = false;
+ stub.bRunningUnderWDDM = false;
# endif
- /* Apply viewport hack only if we're running under wine */
- if (NULL!=GetModuleHandle("wined3d.dll") || NULL != GetModuleHandle("wined3dwddm.dll"))
- {
- crGetProcName(name, 1000);
- for (i=0; gsViewportHackApps[i]; ++i)
- {
- if (!stricmp(name, gsViewportHackApps[i]))
- {
- stub.viewportHack = 1;
- break;
- }
- }
- }
- }
#endif
}
@@ -819,161 +784,7 @@ static HRGN stubMakeRegionFromRects(PVBOXVIDEOCM_CMD_RECTS pRegions, uint32_t st
return hRgn;
}
-typedef struct VBOXCR_UPDATEWNDCB
-{
- VBOXDISPMP_REGIONS Regions;
- bool fSendUpdateMsg;
-} VBOXCR_UPDATEWNDCB, *PVBOXCR_UPDATEWNDCB;
-
-static void stubSyncTrUpdateWindowCB(unsigned long key, void *data1, void *data2)
-{
- WindowInfo *pWindow = (WindowInfo *) data1;
- PVBOXCR_UPDATEWNDCB pCbData = (PVBOXCR_UPDATEWNDCB) data2;
- VBOXDISPMP_REGIONS *pRegions = &pCbData->Regions;
- bool bChanged = false, bDoMap = false;
- HRGN hNewRgn = INVALID_HANDLE_VALUE;
-
- if (pRegions->hWnd != pWindow->hWnd)
- {
- return;
- }
-
- stub.spu->dispatch_table.VBoxPackSetInjectID(pWindow->u32ClientID);
-
- if (!stubSystemWindowExist(pWindow))
- {
- stubDestroyWindow(0, (GLint)pWindow->hWnd);
- return;
- }
-
- if (pRegions->pRegions->fFlags.bAddVisibleRects || pRegions->pRegions->fFlags.bSetViewRect)
- {
- if (!pWindow->mapped)
- {
- bDoMap = true;
- }
-
- /* ensure data integrity */
- Assert(!pRegions->pRegions->fFlags.bAddHiddenRects);
-
- if (pRegions->pRegions->fFlags.bSetViewRect)
- {
- int winX, winY;
- unsigned int winW, winH;
- BOOL bRc;
-
- winX = pRegions->pRegions->RectsInfo.aRects[0].left;
- winY = pRegions->pRegions->RectsInfo.aRects[0].top;
- winW = pRegions->pRegions->RectsInfo.aRects[0].right - winX;
- winH = pRegions->pRegions->RectsInfo.aRects[0].bottom - winY;
-
- if (stub.trackWindowPos && (bDoMap || winX!=pWindow->x || winY!=pWindow->y))
- {
- crDebug("Dispatched WindowPosition (%i)", pWindow->spuWindow);
- stub.spuDispatch.WindowPosition(pWindow->spuWindow, winX, winY);
- pWindow->x = winX;
- pWindow->y = winY;
- bChanged = true;
- }
-
- if (stub.trackWindowSize && (bDoMap || winW!=pWindow->width || winH!=pWindow->height))
- {
- crDebug("Dispatched WindowSize (%i)", pWindow->spuWindow);
- stub.spuDispatch.WindowSize(pWindow->spuWindow, winW, winH);
- pWindow->width = winW;
- pWindow->height = winH;
- bChanged = true;
- }
-
- bRc = MoveWindow(pRegions->hWnd, winX, winY, winW, winH, FALSE /*BOOL bRepaint*/);
- if (!bRc)
- {
- DWORD winEr = GetLastError();
- crWarning("stubSyncTrUpdateWindowCB: MoveWindow failed winEr(%d)", winEr);
- }
- }
-
- if (pRegions->pRegions->fFlags.bAddVisibleRects)
- {
- hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, pRegions->pRegions->fFlags.bSetViewRect ? 1 : 0);
- }
- }
- else if (!pRegions->pRegions->fFlags.bHide)
- {
- Assert(pRegions->pRegions->fFlags.bAddHiddenRects);
- hNewRgn = stubMakeRegionFromRects(pRegions->pRegions, 0);
- }
- else
- {
- Assert(pRegions->pRegions->fFlags.bAddHiddenRects);
- hNewRgn = CreateRectRgn(pWindow->x, pWindow->y, pWindow->x + pWindow->width, pWindow->y + pWindow->height);
- }
-
- if (hNewRgn!=INVALID_HANDLE_VALUE)
- {
- if (pRegions->pRegions->fFlags.bAddVisibleRects)
- {
- HRGN hEmptyRgn = CreateRectRgn(0, 0, 0, 0);
-
- if (hEmptyRgn!=INVALID_HANDLE_VALUE)
- {
- if (pWindow->hVisibleRegion==INVALID_HANDLE_VALUE || EqualRgn(pWindow->hVisibleRegion, hEmptyRgn))
- {
- pCbData->fSendUpdateMsg = true;
- }
-
- DeleteObject(hEmptyRgn);
- }
- else
- {
- crWarning("Failed to created empty region!");
- }
- }
-
- OffsetRgn(hNewRgn, -pWindow->x, -pWindow->y);
-
- if (pWindow->hVisibleRegion!=INVALID_HANDLE_VALUE)
- {
- CombineRgn(hNewRgn, pWindow->hVisibleRegion, hNewRgn,
- pRegions->pRegions->fFlags.bAddHiddenRects ? RGN_DIFF:RGN_OR);
-
- if (!EqualRgn(pWindow->hVisibleRegion, hNewRgn))
- {
- DeleteObject(pWindow->hVisibleRegion);
- pWindow->hVisibleRegion = hNewRgn;
- stubDispatchVisibleRegions(pWindow);
- bChanged = true;
- }
- else
- {
- DeleteObject(hNewRgn);
- }
- }
- else
- {
- if (pRegions->pRegions->fFlags.bAddVisibleRects)
- {
- pWindow->hVisibleRegion = hNewRgn;
- stubDispatchVisibleRegions(pWindow);
- bChanged = true;
- }
- }
- }
-
- if (bDoMap)
- {
- pWindow->mapped = GL_TRUE;
- bChanged = true;
- crDebug("Dispatched: WindowShow(%i, %i)", pWindow->spuWindow, pWindow->mapped);
- stub.spu->dispatch_table.WindowShow(pWindow->spuWindow, pWindow->mapped);
- }
-
- if (bChanged)
- {
- stub.spu->dispatch_table.Flush();
- }
-}
-# endif
+# endif /* VBOX_WITH_WDDM */
static void stubSyncTrCheckWindowsCB(unsigned long key, void *data1, void *data2)
{
@@ -1010,10 +821,7 @@ static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
#ifdef WINDOWS
MSG msg;
# ifdef VBOX_WITH_WDDM
- static VBOXDISPMP_CALLBACKS VBoxDispMpTstCallbacks = {NULL, NULL, NULL};
HMODULE hVBoxD3D = NULL;
- VBOXCR_UPDATEWNDCB RegionsData;
- HRESULT hr;
GLint spuConnection = 0;
# endif
#endif
@@ -1024,42 +832,18 @@ static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
#ifdef WINDOWS
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
# ifdef VBOX_WITH_WDDM
- hVBoxD3D = GetModuleHandle(VBOX_MODNAME_DISPD3D);
- if (hVBoxD3D)
+ hVBoxD3D = NULL;
+ if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
{
- hVBoxD3D = LoadLibrary(VBOX_MODNAME_DISPD3D);
+ crDebug("GetModuleHandleEx failed err %d", GetLastError());
+ hVBoxD3D = NULL;
}
if (hVBoxD3D)
{
- PFNVBOXDISPMP_GETCALLBACKS pfnVBoxDispMpGetCallbacks;
- pfnVBoxDispMpGetCallbacks = (PFNVBOXDISPMP_GETCALLBACKS)GetProcAddress(hVBoxD3D, TEXT("VBoxDispMpGetCallbacks"));
- if (pfnVBoxDispMpGetCallbacks)
- {
- hr = pfnVBoxDispMpGetCallbacks(VBOXDISPMP_VERSION, &VBoxDispMpTstCallbacks);
- if (S_OK==hr)
- {
- CRASSERT(VBoxDispMpTstCallbacks.pfnEnableEvents);
- CRASSERT(VBoxDispMpTstCallbacks.pfnDisableEvents);
- CRASSERT(VBoxDispMpTstCallbacks.pfnGetRegions);
-
- hr = VBoxDispMpTstCallbacks.pfnEnableEvents();
- if (hr != S_OK)
- {
- crWarning("VBoxDispMpTstCallbacks.pfnEnableEvents failed");
- }
- else
- {
crDebug("running with " VBOX_MODNAME_DISPD3D);
stub.trackWindowVisibleRgn = 0;
stub.bRunningUnderWDDM = true;
- }
- }
- else
- {
- crWarning("VBoxDispMpGetCallbacks failed");
- }
- }
}
# endif /* VBOX_WITH_WDDM */
#endif /* WINDOWS */
@@ -1085,38 +869,9 @@ static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
# ifdef VBOX_WITH_WDDM
- if (VBoxDispMpTstCallbacks.pfnGetRegions)
+ if (stub.bRunningUnderWDDM)
{
- hr = VBoxDispMpTstCallbacks.pfnGetRegions(&RegionsData.Regions, 50);
- if (S_OK==hr)
- {
- RegionsData.fSendUpdateMsg = false;
-# if 0
- uint32_t i;
- crDebug(">>>Regions for HWND(0x%x)>>>", RegionsData.Regions.hWnd);
- crDebug("Flags(0x%x)", RegionsData.Regions.pRegions->fFlags.Value);
- for (i = 0; i < RegionsData.Regions.pRegions->RectsInfo.cRects; ++i)
- {
- RECT *pRect = &RegionsData.Regions.pRegions->RectsInfo.aRects[i];
- crDebug("Rect(%d): left(%d), top(%d), right(%d), bottom(%d)", i, pRect->left, pRect->top, pRect->right, pRect->bottom);
- }
- crDebug("<<<<<");
-# endif
- /*hacky way to make sure window wouldn't be deleted in another thread as we hold hashtable lock here*/
- crHashtableWalk(stub.windowTable, stubSyncTrUpdateWindowCB, &RegionsData);
- if (RegionsData.fSendUpdateMsg)
- {
- SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_NORMAL, 1000, NULL);
- }
- }
- else
- {
- if (WAIT_TIMEOUT!=hr)
- {
- crWarning("VBoxDispMpTstCallbacks.pfnGetRegions failed with 0x%x", hr);
- }
- crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
- }
+
}
else
# endif
@@ -1139,18 +894,17 @@ static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
}
}
#else
+ /* Try to keep a consistent locking order. */
+ crHashtableLock(stub.windowTable);
crLockMutex(&stub.mutex);
- crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
+ crHashtableWalkUnlocked(stub.windowTable, stubSyncTrCheckWindowsCB, NULL);
crUnlockMutex(&stub.mutex);
+ crHashtableUnlock(stub.windowTable);
RTThreadSleep(50);
#endif
}
#ifdef VBOX_WITH_WDDM
- if (VBoxDispMpTstCallbacks.pfnDisableEvents)
- {
- VBoxDispMpTstCallbacks.pfnDisableEvents();
- }
if (spuConnection)
{
stub.spu->dispatch_table.VBoxConDestroy(spuConnection);
@@ -1163,7 +917,7 @@ static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser)
crDebug("Sync thread stopped");
return 0;
}
-#endif
+#endif /* CR_NEWWINTRACK */
/**
* Do one-time initializations for the faker.
@@ -1188,6 +942,9 @@ stubInitLocked(void)
const char *app_id;
int i;
int disable_sync = 0;
+#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
+ HMODULE hVBoxD3D = NULL;
+#endif
stubInitVars();
@@ -1230,15 +987,6 @@ stubInitLocked(void)
{
crNetFreeConnection(ns.conn);
}
-#if 0 && defined(CR_NEWWINTRACK)
- {
- Status st = XInitThreads();
- if (st==0)
- {
- crWarning("XInitThreads returned %i", (int)st);
- }
- }
-#endif
}
#endif
@@ -1256,6 +1004,27 @@ stubInitLocked(void)
stubSetDefaultConfigurationOptions();
+#if defined(WINDOWS) && defined(VBOX_WITH_WDDM)
+ hVBoxD3D = NULL;
+ if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D))
+ {
+ crDebug("GetModuleHandleEx failed err %d", GetLastError());
+ hVBoxD3D = NULL;
+ }
+
+ if (hVBoxD3D)
+ {
+ disable_sync = 1;
+ crDebug("running with %s", VBOX_MODNAME_DISPD3D);
+ stub.trackWindowVisibleRgn = 0;
+ /* @todo: should we enable that? */
+ stub.trackWindowSize = 0;
+ stub.trackWindowPos = 0;
+ stub.trackWindowVisibility = 0;
+ stub.bRunningUnderWDDM = true;
+ }
+#endif
+
stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL );
crFree( spuchain );
@@ -1296,7 +1065,7 @@ raise(SIGINT);*/
{
int rc;
- RTR3InitDll(0);
+ RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
if (!disable_sync)
{
@@ -1358,14 +1127,144 @@ stubInit(void)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-#ifdef DEBUG_misha
+#if 1//def DEBUG_misha
/* debugging: this is to be able to catch first-chance notifications
* for exceptions other than EXCEPTION_BREAKPOINT in kernel debugger */
# define VDBG_VEHANDLER
#endif
#ifdef VDBG_VEHANDLER
-static PVOID g_VBoxWDbgVEHandler = NULL;
+# include <dbghelp.h>
+static PVOID g_VBoxVehHandler = NULL;
+static DWORD g_VBoxVehEnable = 0;
+
+/* generate a crash dump on exception */
+#define VBOXVEH_F_DUMP 0x00000001
+/* generate a debugger breakpoint exception */
+#define VBOXVEH_F_BREAK 0x00000002
+/* exit on exception */
+#define VBOXVEH_F_EXIT 0x00000004
+
+static DWORD g_VBoxVehFlags = 0
+#ifdef DEBUG_misha
+ | VBOXVEH_F_BREAK
+#else
+ | VBOXVEH_F_DUMP
+#endif
+ ;
+
+typedef BOOL WINAPI FNVBOXDBG_MINIDUMPWRITEDUMP(HANDLE hProcess,
+ DWORD ProcessId,
+ HANDLE hFile,
+ MINIDUMP_TYPE DumpType,
+ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+typedef FNVBOXDBG_MINIDUMPWRITEDUMP *PFNVBOXDBG_MINIDUMPWRITEDUMP;
+
+static HMODULE g_hVBoxMdDbgHelp = NULL;
+static PFNVBOXDBG_MINIDUMPWRITEDUMP g_pfnVBoxMdMiniDumpWriteDump = NULL;
+static uint32_t g_cVBoxMdFilePrefixLen = 0;
+static WCHAR g_aszwVBoxMdFilePrefix[MAX_PATH];
+static WCHAR g_aszwVBoxMdDumpCount = 0;
+static MINIDUMP_TYPE g_enmVBoxMdDumpType = MiniDumpNormal
+ | MiniDumpWithDataSegs
+ | MiniDumpWithFullMemory
+ | MiniDumpWithHandleData
+//// | MiniDumpFilterMemory
+//// | MiniDumpScanMemory
+// | MiniDumpWithUnloadedModules
+//// | MiniDumpWithIndirectlyReferencedMemory
+//// | MiniDumpFilterModulePaths
+// | MiniDumpWithProcessThreadData
+// | MiniDumpWithPrivateReadWriteMemory
+//// | MiniDumpWithoutOptionalData
+// | MiniDumpWithFullMemoryInfo
+// | MiniDumpWithThreadInfo
+// | MiniDumpWithCodeSegs
+// | MiniDumpWithFullAuxiliaryState
+// | MiniDumpWithPrivateWriteCopyMemory
+// | MiniDumpIgnoreInaccessibleMemory
+// | MiniDumpWithTokenInformation
+//// | MiniDumpWithModuleHeaders
+//// | MiniDumpFilterTriage
+ ;
+
+
+
+#define VBOXMD_DUMP_DIR_PREFIX_DEFAULT L"C:\\dumps\\vboxdmp"
+
+static HMODULE loadSystemDll(const char *pszName)
+{
+ char szPath[MAX_PATH];
+ UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
+ size_t cbName = strlen(pszName) + 1;
+ if (cchPath + 1 + cbName > sizeof(szPath))
+ {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return NULL;
+ }
+ szPath[cchPath] = '\\';
+ memcpy(&szPath[cchPath + 1], pszName, cbName);
+ return LoadLibraryA(szPath);
+}
+
+static DWORD vboxMdMinidumpCreate(struct _EXCEPTION_POINTERS *pExceptionInfo)
+{
+ WCHAR aszwMdFileName[MAX_PATH];
+ HANDLE hProcess = GetCurrentProcess();
+ DWORD ProcessId = GetCurrentProcessId();
+ MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
+ HANDLE hFile;
+ DWORD winErr = ERROR_SUCCESS;
+
+ if (!g_pfnVBoxMdMiniDumpWriteDump)
+ {
+ if (!g_hVBoxMdDbgHelp)
+ {
+ g_hVBoxMdDbgHelp = loadSystemDll("DbgHelp.dll");
+ if (!g_hVBoxMdDbgHelp)
+ return GetLastError();
+ }
+
+ g_pfnVBoxMdMiniDumpWriteDump = (PFNVBOXDBG_MINIDUMPWRITEDUMP)GetProcAddress(g_hVBoxMdDbgHelp, "MiniDumpWriteDump");
+ if (!g_pfnVBoxMdMiniDumpWriteDump)
+ return GetLastError();
+ }
+
+ /* @todo: this is a tmp stuff until we get that info from the settings properly */
+ if (!g_cVBoxMdFilePrefixLen)
+ {
+ g_cVBoxMdFilePrefixLen = sizeof (VBOXMD_DUMP_DIR_PREFIX_DEFAULT)/sizeof (g_aszwVBoxMdFilePrefix[0]) - 1 /* <- don't include nul terminator */;
+ memcpy(g_aszwVBoxMdFilePrefix, VBOXMD_DUMP_DIR_PREFIX_DEFAULT, sizeof (VBOXMD_DUMP_DIR_PREFIX_DEFAULT));
+ }
+
+
+ if (RT_ELEMENTS(aszwMdFileName) <= g_cVBoxMdFilePrefixLen)
+ {
+ return ERROR_INVALID_STATE;
+ }
+
+ ++g_aszwVBoxMdDumpCount;
+
+ memcpy(aszwMdFileName, g_aszwVBoxMdFilePrefix, g_cVBoxMdFilePrefixLen * sizeof (g_aszwVBoxMdFilePrefix[0]));
+ swprintf(aszwMdFileName + g_cVBoxMdFilePrefixLen, RT_ELEMENTS(aszwMdFileName) - g_cVBoxMdFilePrefixLen, L"%d_%d.dmp", ProcessId, g_aszwVBoxMdDumpCount);
+
+ hFile = CreateFileW(aszwMdFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return GetLastError();
+
+ ExceptionInfo.ThreadId = GetCurrentThreadId();
+ ExceptionInfo.ExceptionPointers = pExceptionInfo;
+ ExceptionInfo.ClientPointers = FALSE;
+
+ if (!g_pfnVBoxMdMiniDumpWriteDump(hProcess, ProcessId, hFile, g_enmVBoxMdDumpType, &ExceptionInfo, NULL, NULL))
+ winErr = GetLastError();
+
+ CloseHandle(hFile);
+ return winErr;
+}
+
LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
{
PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
@@ -1380,7 +1279,33 @@ LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_ILLEGAL_INSTRUCTION:
- CRASSERT(0);
+ if (g_VBoxVehFlags & VBOXVEH_F_BREAK)
+ {
+ BOOL fBreak = TRUE;
+#ifndef DEBUG_misha
+ if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
+ {
+ HANDLE hProcess = GetCurrentProcess();
+ BOOL fDebuggerPresent = FALSE;
+ /* we do not want to generate breakpoint exceptions recursively, so do it only when running under debugger */
+ if (CheckRemoteDebuggerPresent(hProcess, &fDebuggerPresent))
+ fBreak = !!fDebuggerPresent;
+ else
+ fBreak = FALSE; /* <- the function has failed, don't break for sanity */
+ }
+#endif
+
+ if (fBreak)
+ {
+ RT_BREAKPOINT();
+ }
+ }
+
+ if (g_VBoxVehFlags & VBOXVEH_F_DUMP)
+ vboxMdMinidumpCreate(pExceptionInfo);
+
+ if (g_VBoxVehFlags & VBOXVEH_F_EXIT)
+ exit(1);
break;
default:
break;
@@ -1390,19 +1315,19 @@ LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
void vboxVDbgVEHandlerRegister()
{
- CRASSERT(!g_VBoxWDbgVEHandler);
- g_VBoxWDbgVEHandler = AddVectoredExceptionHandler(1,vboxVDbgVectoredHandler);
- CRASSERT(g_VBoxWDbgVEHandler);
+ CRASSERT(!g_VBoxVehHandler);
+ g_VBoxVehHandler = AddVectoredExceptionHandler(1,vboxVDbgVectoredHandler);
+ CRASSERT(g_VBoxVehHandler);
}
void vboxVDbgVEHandlerUnregister()
{
ULONG uResult;
- if (g_VBoxWDbgVEHandler)
+ if (g_VBoxVehHandler)
{
- uResult = RemoveVectoredExceptionHandler(g_VBoxWDbgVEHandler);
+ uResult = RemoveVectoredExceptionHandler(g_VBoxVehHandler);
CRASSERT(uResult);
- g_VBoxWDbgVEHandler = NULL;
+ g_VBoxVehHandler = NULL;
}
}
#endif
@@ -1425,7 +1350,12 @@ BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
crInitMutex(&stub_init_mutex);
#ifdef VDBG_VEHANDLER
- vboxVDbgVEHandlerRegister();
+ g_VBoxVehEnable = !!crGetenv("CR_DBG_VEH_ENABLE");
+# ifdef DEBUG_misha
+ g_VBoxVehEnable = 1;
+# endif
+ if (g_VBoxVehEnable)
+ vboxVDbgVEHandlerRegister();
#endif
crNetInit(NULL, NULL);
@@ -1440,12 +1370,15 @@ BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
{
crDebug("Failed to connect to host (is guest 3d acceleration enabled?), aborting ICD load.");
#ifdef VDBG_VEHANDLER
- vboxVDbgVEHandlerUnregister();
+ if (g_VBoxVehEnable)
+ vboxVDbgVEHandlerUnregister();
#endif
return FALSE;
}
else
+ {
crNetFreeConnection(ns.conn);
+ }
break;
}
@@ -1468,7 +1401,8 @@ BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
#endif
#ifdef VDBG_VEHANDLER
- vboxVDbgVEHandlerUnregister();
+ if (g_VBoxVehEnable)
+ vboxVDbgVEHandlerUnregister();
#endif
break;
}
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu.h b/src/VBox/Additions/common/crOpenGL/pack/packspu.h
index 27f3526f..942761a8 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu.h
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu.h
@@ -19,6 +19,9 @@
#include "cr_spu.h"
#include "cr_threads.h"
#include "state/cr_client.h"
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+# include "cr_dump.h"
+#endif
typedef struct thread_info_t ThreadInfo;
typedef struct context_info_t ContextInfo;
@@ -70,6 +73,13 @@ typedef struct {
bool bRunningUnderWDDM;
#endif
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ SPUDispatchTable self;
+
+ CR_RECORDER Recorder;
+ CR_DBGPRINT_DUMPER Dumper;
+#endif
+
int numContexts;
ContextInfo context[CR_MAX_CONTEXTS];
} PackSPU;
@@ -82,7 +92,8 @@ extern PackSPU pack_spu;
extern CRmutex _PackMutex;
extern CRtsd _PackTSD;
#define GET_THREAD_VAL() (crGetTSD(&_PackTSD))
-#define GET_THREAD_VAL_ID(_id) (&(pack_spu.thread[(_id) - THREAD_OFFSET_MAGIC]))
+#define GET_THREAD_IDX(_id) ((_id) - THREAD_OFFSET_MAGIC)
+#define GET_THREAD_VAL_ID(_id) (&(pack_spu.thread[GET_THREAD_IDX(_id)]))
#else
#define GET_THREAD_VAL() (&(pack_spu.thread[0]))
#endif
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_bufferobject.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_bufferobject.c
index 8a741137..53cd3aff 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_bufferobject.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_bufferobject.c
@@ -130,3 +130,31 @@ packspu_BindBufferARB( GLenum target, GLuint buffer )
crStateBindBufferARB(target, buffer);
crPackBindBufferARB(target, buffer);
}
+
+void PACKSPU_APIENTRY packspu_GenBuffersARB( GLsizei n, GLuint * buffer )
+{
+ GET_THREAD(thread);
+ int writeback = 1;
+ if (!CRPACKSPU_IS_WDDM_CRHGSMI() && !(pack_spu.thread[pack_spu.idxThreadInUse].netServer.conn->actual_network))
+ {
+ crError( "packspu_GenBuffersARB doesn't work when there's no actual network involved!\nTry using the simplequery SPU in your chain!" );
+ }
+ if (pack_spu.swap)
+ {
+ crPackGenBuffersARBSWAP( n, buffer, &writeback );
+ }
+ else
+ {
+ crPackGenBuffersARB( n, buffer, &writeback );
+ }
+ packspuFlush( (void *) thread );
+ CRPACKSPU_WRITEBACK_WAIT(thread, writeback);
+
+ crStateRegBuffers(n, buffer);
+}
+
+void PACKSPU_APIENTRY packspu_DeleteBuffersARB( GLsizei n, const GLuint * buffer )
+{
+ crStateDeleteBuffersARB( n, buffer );
+ crPackDeleteBuffersARB(n, buffer);
+}
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_context.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_context.c
index 90fb5f90..08e41300 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_context.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_context.c
@@ -130,6 +130,8 @@ packspu_VBoxConFlush(GLint con)
CRASSERT(CRPACKSPU_IS_WDDM_CRHGSMI());
CRASSERT(thread->packer);
packspuFlush((void *) thread);
+#else
+ crError("VBoxConFlush not implemented!");
#endif
}
@@ -148,8 +150,17 @@ packspu_VBoxConDestroy(GLint con)
crPackDeleteContext(thread->packer);
+ if (thread->buffer.pack)
+ {
+ crNetFree(thread->netServer.conn, thread->buffer.pack);
+ thread->buffer.pack = NULL;
+ }
+
crNetFreeConnection(thread->netServer.conn);
+ if (thread->netServer.name)
+ crFree(thread->netServer.name);
+
pack_spu.numThreads--;
/*note can't shift the array here, because other threads have TLS references to array elements*/
crMemZero(thread, sizeof(ThreadInfo));
@@ -173,6 +184,63 @@ packspu_VBoxConDestroy(GLint con)
#endif
}
+GLvoid PACKSPU_APIENTRY
+packspu_VBoxConChromiumParameteriCR(GLint con, GLenum param, GLint value)
+{
+ GET_THREAD(thread);
+ CRPackContext * curPacker = crPackGetContext();
+ ThreadInfo *curThread = thread;
+ int writeback = 1;
+ GLint serverCtx = (GLint) -1;
+
+ CRASSERT(!curThread == !curPacker);
+ CRASSERT(!curThread || !curPacker || curThread->packer == curPacker);
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&_PackMutex);
+#endif
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ CRASSERT(!con == !CRPACKSPU_IS_WDDM_CRHGSMI());
+#endif
+
+ if (CRPACKSPU_IS_WDDM_CRHGSMI())
+ {
+ if (!con)
+ {
+ crError("connection should be specified!");
+ return;
+ }
+ thread = GET_THREAD_VAL_ID(con);
+ }
+ else
+ {
+ CRASSERT(!con);
+ if (!thread)
+ {
+ thread = packspuNewThread(
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ NULL
+#endif
+ );
+ }
+ }
+ CRASSERT(thread);
+ CRASSERT(thread->packer);
+
+ crPackSetContext( thread->packer );
+
+ packspu_ChromiumParameteriCR(param, value);
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&_PackMutex);
+#endif
+
+ if (CRPACKSPU_IS_WDDM_CRHGSMI())
+ {
+ /* restore the packer context to the tls */
+ crPackSetContext(curPacker);
+ }
+}
GLint PACKSPU_APIENTRY
packspu_VBoxCreateContext( GLint con, const char *dpyName, GLint visual, GLint shareCtx )
@@ -412,7 +480,7 @@ void PACKSPU_APIENTRY packspu_MakeCurrent( GLint window, GLint nativeWindow, GLi
}
else
{
- if (!newCtx->fAutoFlush)
+ if (newCtx->fAutoFlush)
{
if (newCtx->currentThread && newCtx->currentThread != thread)
{
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_framebuffer.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_framebuffer.c
index 555e60cd..ed555c48 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_framebuffer.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_framebuffer.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -59,8 +59,8 @@ packspu_DeleteFramebuffersEXT(GLsizei n, const GLuint * framebuffers)
void PACKSPU_APIENTRY
packspu_DeleteRenderbuffersEXT(GLsizei n, const GLuint * renderbuffers)
{
- crStateDeleteFramebuffersEXT(n, renderbuffers);
- crPackDeleteFramebuffersEXT(n, renderbuffers);
+ crStateDeleteRenderbuffersEXT(n, renderbuffers);
+ crPackDeleteRenderbuffersEXT(n, renderbuffers);
}
void PACKSPU_APIENTRY
@@ -97,3 +97,47 @@ packspu_CheckFramebufferStatusEXT(GLenum target)
crStateSetFramebufferStatus(target, status);
return status;
}
+
+void PACKSPU_APIENTRY packspu_GenFramebuffersEXT( GLsizei n, GLuint * framebuffers )
+{
+ GET_THREAD(thread);
+ int writeback = 1;
+ if (!CRPACKSPU_IS_WDDM_CRHGSMI() && !(pack_spu.thread[pack_spu.idxThreadInUse].netServer.conn->actual_network))
+ {
+ crError( "packspu_GenFramebuffersEXT doesn't work when there's no actual network involved!\nTry using the simplequery SPU in your chain!" );
+ }
+ if (pack_spu.swap)
+ {
+ crPackGenFramebuffersEXTSWAP( n, framebuffers, &writeback );
+ }
+ else
+ {
+ crPackGenFramebuffersEXT( n, framebuffers, &writeback );
+ }
+ packspuFlush( (void *) thread );
+ CRPACKSPU_WRITEBACK_WAIT(thread, writeback);
+
+ crStateRegFramebuffers(n, framebuffers);
+}
+
+void PACKSPU_APIENTRY packspu_GenRenderbuffersEXT( GLsizei n, GLuint * renderbuffers )
+{
+ GET_THREAD(thread);
+ int writeback = 1;
+ if (!CRPACKSPU_IS_WDDM_CRHGSMI() && !(pack_spu.thread[pack_spu.idxThreadInUse].netServer.conn->actual_network))
+ {
+ crError( "packspu_GenRenderbuffersEXT doesn't work when there's no actual network involved!\nTry using the simplequery SPU in your chain!" );
+ }
+ if (pack_spu.swap)
+ {
+ crPackGenRenderbuffersEXTSWAP( n, renderbuffers, &writeback );
+ }
+ else
+ {
+ crPackGenRenderbuffersEXT( n, renderbuffers, &writeback );
+ }
+ packspuFlush( (void *) thread );
+ CRPACKSPU_WRITEBACK_WAIT(thread, writeback);
+
+ crStateRegRenderbuffers(n, renderbuffers);
+}
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_get.py b/src/VBox/Additions/common/crOpenGL/pack/packspu_get.py
index 25aa4de2..82f00a85 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_get.py
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_get.py
@@ -48,7 +48,6 @@ GLboolean crPackIsPixelStoreParm(GLenum pname)
"""
from get_sizes import *
-from get_components import *
easy_swaps = {
'GenTextures': '(unsigned int) n',
@@ -117,6 +116,11 @@ for func_name in keys:
#ifdef CR_ARB_vertex_program
|| pname == GL_MAX_VERTEX_ATTRIBS_ARB
#endif
+#ifndef GL_EXT_framebuffer_object
+ || pname == GL_FRAMEBUFFER_BINDING_EXT
+ || pname == GL_READ_FRAMEBUFFER_BINDING_EXT
+ || pname == GL_DRAW_FRAMEBUFFER_BINDING_EXT
+#endif
)
{
#ifdef DEBUG
@@ -200,7 +204,7 @@ for func_name in keys:
if func_name in hard_funcs.keys():
print '\tif (pack_spu.swap)'
print '\t{'
- print '\t\tfor (i = 0 ; i < lookupComponents(pname) ; i++)'
+ print '\t\tfor (i = 0 ; i < crStateHlpComponentsCount(pname) ; i++)'
print '\t\t{'
if hard_funcs[func_name] == 'SWAPDOUBLE':
print '\t\t\t%s[i] = %s(%s[i]);' % (lastParamName, hard_funcs[func_name], lastParamName)
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_getshaders.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_getshaders.c
index d0cc9040..6b3271d5 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_getshaders.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_getshaders.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -98,7 +98,7 @@ void PACKSPU_APIENTRY packspu_GetAttachedShaders(GLuint program, GLsizei maxCoun
crFree(pLocal);
}
-void PACKSPU_APIENTRY packspu_GetAttachedObjectsARB(GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj)
+void PACKSPU_APIENTRY packspu_GetAttachedObjectsARB(VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * count, VBoxGLhandleARB * obj)
{
GET_THREAD(thread);
int writeback = 1;
@@ -106,7 +106,7 @@ void PACKSPU_APIENTRY packspu_GetAttachedObjectsARB(GLhandleARB containerObj, GL
if (!obj) return;
- pLocal = (GLsizei*) crAlloc(maxCount*sizeof(GLhandleARB)+sizeof(GLsizei));
+ pLocal = (GLsizei*) crAlloc(maxCount*sizeof(VBoxGLhandleARB)+sizeof(GLsizei));
if (!pLocal) return;
crPackGetAttachedObjectsARB(containerObj, maxCount, pLocal, NULL, &writeback);
@@ -115,13 +115,13 @@ void PACKSPU_APIENTRY packspu_GetAttachedObjectsARB(GLhandleARB containerObj, GL
CRPACKSPU_WRITEBACK_WAIT(thread, writeback);
if (count) *count=*pLocal;
- crMemcpy(obj, &pLocal[1], *pLocal*sizeof(GLhandleARB));
+ crMemcpy(obj, &pLocal[1], *pLocal*sizeof(VBoxGLhandleARB));
crFree(pLocal);
}
AssertCompile(sizeof(GLsizei) == 4);
-void PACKSPU_APIENTRY packspu_GetInfoLogARB(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog)
+void PACKSPU_APIENTRY packspu_GetInfoLogARB(VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog)
{
GET_THREAD(thread);
int writeback = 1;
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_glsl.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_glsl.c
index e19959a3..d58202ef 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_glsl.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_glsl.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -129,12 +129,14 @@ void PACKSPU_APIENTRY packspu_DeleteProgram(GLuint program)
crPackDeleteProgram(program);
}
-void PACK_APIENTRY packspu_DeleteObjectARB(GLhandleARB obj)
+void PACK_APIENTRY packspu_DeleteObjectARB(VBoxGLhandleARB obj)
{
GLuint hwid = crStateGetProgramHWID(obj);
CRASSERT(obj);
+ /* we do not track shader creation inside guest since it is not needed currently.
+ * this is why we only care about programs here */
if (hwid)
{
crStateDeleteProgram(obj);
@@ -143,8 +145,57 @@ void PACK_APIENTRY packspu_DeleteObjectARB(GLhandleARB obj)
crPackDeleteObjectARB(obj);
}
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+static void packspu_RecCheckInitRec()
+{
+ if (pack_spu.Recorder.pDumper)
+ return;
+
+ crDmpDbgPrintInit(&pack_spu.Dumper);
+
+ crRecInit(&pack_spu.Recorder, NULL /*pBlitter: we do not support blitter operations here*/, &pack_spu.self, &pack_spu.Dumper.Base);
+}
+#endif
+
void PACKSPU_APIENTRY packspu_LinkProgram(GLuint program)
{
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ GLint linkStatus = 0;
+#endif
+
crStateLinkProgram(program);
crPackLinkProgram(program);
+
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ pack_spu.self.GetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linkStatus);
+ Assert(linkStatus);
+ if (!linkStatus)
+ {
+ CRContext *ctx = crStateGetCurrent();
+ packspu_RecCheckInitRec();
+ crRecDumpProgram(&pack_spu.Recorder, ctx, program, program);
+ }
+#endif
}
+
+void PACKSPU_APIENTRY packspu_CompileShader(GLuint shader)
+{
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ GLint compileStatus = 0;
+#endif
+
+// crStateCompileShader(shader);
+ crPackCompileShader(shader);
+
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ pack_spu.self.GetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus);
+ Assert(compileStatus);
+ if (!compileStatus)
+ {
+ CRContext *ctx = crStateGetCurrent();
+ packspu_RecCheckInitRec();
+ crRecDumpShader(&pack_spu.Recorder, ctx, shader, shader);
+ }
+#endif
+}
+
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_init.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_init.c
index 6682058d..2781fa6f 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_init.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_init.c
@@ -50,6 +50,10 @@ packSPUInit( int id, SPU *child, SPU *self,
pack_spu.bRunningUnderWDDM = !!GetModuleHandle(VBOX_MODNAME_DISPD3D);
#endif
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ memset(&pack_spu.Dumper, 0, sizeof (pack_spu.Dumper));
+#endif
+
if (!CRPACKSPU_IS_WDDM_CRHGSMI())
{
/* This connects to the server, sets up the packer, etc. */
@@ -75,7 +79,12 @@ packSPUInit( int id, SPU *child, SPU *self,
static void
packSPUSelfDispatch(SPUDispatchTable *self)
{
+#ifdef VBOX_WITH_CRPACKSPU_DUMPER
+ crSPUInitDispatchTable( &(pack_spu.self) );
+ crSPUCopyDispatchTable( &(pack_spu.self), self );
+#else
(void)self;
+#endif
}
static int
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_misc.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_misc.c
index ee4d4f88..3048bbc3 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_misc.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_misc.c
@@ -615,9 +615,18 @@ void PACKSPU_APIENTRY packspu_VBoxDetachThread()
crPackSetContext(NULL);
CR_UNLOCK_PACKER_CONTEXT(thread->packer);
crPackDeleteContext(pack_spu.thread[i].packer);
+
+ if (pack_spu.thread[i].buffer.pack)
+ {
+ crNetFree(pack_spu.thread[i].netServer.conn, pack_spu.thread[i].buffer.pack);
+ pack_spu.thread[i].buffer.pack = NULL;
+ }
}
crNetFreeConnection(pack_spu.thread[i].netServer.conn);
+ if (pack_spu.thread[i].netServer.name)
+ crFree(pack_spu.thread[i].netServer.name);
+
pack_spu.numThreads--;
/*note can't shift the array here, because other threads have TLS references to array elements*/
crMemZero(&pack_spu.thread[i], sizeof(ThreadInfo));
@@ -712,3 +721,11 @@ void PACKSPU_APIENTRY packspu_VBoxPackDetachThread()
{
}
#endif /*CHROMIUM_THREADSAFE*/
+
+void PACKSPU_APIENTRY packspu_VBoxPresentComposition(GLint win, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry)
+{
+}
+
+void PACKSPU_APIENTRY packspu_StringMarkerGREMEDY(GLsizei len, const GLvoid *string)
+{
+}
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_special b/src/VBox/Additions/common/crOpenGL/pack/packspu_special
index 6b9edd95..d7a12124 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_special
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_special
@@ -107,11 +107,13 @@ VBoxPackSetInjectID
VBoxAttachThread
VBoxDetachThread
VBoxCreateContext
+VBoxConChromiumParameteriCR
VBoxWindowCreate
VBoxWindowDestroy
VBoxConCreate
VBoxConDestroy
VBoxConFlush
+VBoxPresentComposition
ChromiumParameteriCR
CompressedTexImage1DARB
CompressedTexImage2DARB
@@ -119,3 +121,12 @@ CompressedTexImage3DARB
CompressedTexSubImage1DARB
CompressedTexSubImage2DARB
CompressedTexSubImage3DARB
+GenFramebuffersEXT
+GenRenderbuffersEXT
+DeleteFramebuffersEXT
+DeleteRenderbuffersEXT
+GenBuffersARB
+DeleteBuffersARB
+StringMarkerGREMEDY
+GenTextures
+CompileShader \ No newline at end of file
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_texture.c b/src/VBox/Additions/common/crOpenGL/pack/packspu_texture.c
index b5c60aec..fca7fe66 100644
--- a/src/VBox/Additions/common/crOpenGL/pack/packspu_texture.c
+++ b/src/VBox/Additions/common/crOpenGL/pack/packspu_texture.c
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -39,3 +39,32 @@ void PACKSPU_APIENTRY packspu_DeleteTextures(GLsizei n, const GLuint * textures)
crPackDeleteTextures(n, textures);
}
+void PACKSPU_APIENTRY packspu_GenTextures( GLsizei n, GLuint * textures )
+{
+ GET_THREAD(thread);
+ int writeback = 1;
+ unsigned int i;
+ if (!CRPACKSPU_IS_WDDM_CRHGSMI() && !(pack_spu.thread[pack_spu.idxThreadInUse].netServer.conn->actual_network))
+ {
+ crError( "packspu_GenTextures doesn't work when there's no actual network involved!\nTry using the simplequery SPU in your chain!" );
+ }
+ if (pack_spu.swap)
+ {
+ crPackGenTexturesSWAP( n, textures, &writeback );
+ }
+ else
+ {
+ crPackGenTextures( n, textures, &writeback );
+ }
+ packspuFlush( (void *) thread );
+ CRPACKSPU_WRITEBACK_WAIT(thread, writeback);
+ if (pack_spu.swap)
+ {
+ for (i = 0 ; i < (unsigned int) n ; i++)
+ {
+ textures[i] = SWAP32(textures[i]);
+ }
+ }
+
+ crStateRegTextures(n, textures);
+}
diff --git a/src/VBox/Additions/common/crOpenGL/stub.c b/src/VBox/Additions/common/crOpenGL/stub.c
index 5131d4bf..5f0f3745 100644
--- a/src/VBox/Additions/common/crOpenGL/stub.c
+++ b/src/VBox/Additions/common/crOpenGL/stub.c
@@ -142,7 +142,7 @@ void APIENTRY crWindowPosition( GLint window, GLint x, GLint y )
}
}
-void APIENTRY crWindowVisibleRegion( GLint window, GLint cRects, void *pRects )
+void APIENTRY crWindowVisibleRegion( GLint window, GLint cRects, const void *pRects )
{
const WindowInfo *winInfo = (const WindowInfo *)
crHashtableSearch(stub.windowTable, (unsigned int) window);
@@ -153,6 +153,11 @@ void APIENTRY crWindowVisibleRegion( GLint window, GLint cRects, void *pRects )
}
}
+void APIENTRY crVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects)
+{
+ crError("not expected!");
+}
+
void APIENTRY crWindowShow( GLint window, GLint flag )
{
WindowInfo *winInfo = (WindowInfo *)
diff --git a/src/VBox/Additions/common/crOpenGL/stub.h b/src/VBox/Additions/common/crOpenGL/stub.h
index 61ca2b92..f398e134 100644
--- a/src/VBox/Additions/common/crOpenGL/stub.h
+++ b/src/VBox/Additions/common/crOpenGL/stub.h
@@ -146,8 +146,7 @@ struct context_info_t
Bool direct;
GLXContext glxContext;
CRHashTable *pGLXPixmapsHash;
- Bool damageInitFailed;
- Display *damageDpy; /* second display connection to read xdamage extension data */
+ Bool damageQueryFailed;
int damageEventsBase;
#endif
};
@@ -222,7 +221,6 @@ typedef struct {
int trackWindowVisibleRgn;
char *spu_dir;
int force_pbuffers;
- int viewportHack;
/* thread safety stuff */
GLboolean threadSafe;
@@ -343,6 +341,9 @@ extern ContextInfo *stubNewContext( const char *dpyName, GLint visBits, ContextT
, struct VBOXUHGSMI *pHgsmi
#endif
);
+extern void stubConChromiumParameteriCR(GLint con, GLenum param, GLint value);
+extern GLboolean stubCtxCreate(ContextInfo *context);
+extern GLboolean stubCtxCheckCreate(ContextInfo *context);
extern void stubDestroyContext( unsigned long contextId );
extern GLboolean stubMakeCurrent( WindowInfo *window, ContextInfo *context );
extern GLint stubNewWindow( const char *dpyName, GLint visBits );
@@ -354,6 +355,7 @@ extern GLboolean stubIsWindowVisible(WindowInfo *win);
extern bool stubInit(void);
extern void stubForcedFlush(GLint con);
+extern void stubConFlush(GLint con);
extern void APIENTRY stub_GetChromiumParametervCR( GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid *values );
extern void APIENTRY glBoundsInfoCR(const CRrecti *, const GLbyte *, GLint, GLint);
diff --git a/src/VBox/Additions/common/crOpenGL/wgl.c b/src/VBox/Additions/common/crOpenGL/wgl.c
index 71166343..a2ccf751 100644
--- a/src/VBox/Additions/common/crOpenGL/wgl.c
+++ b/src/VBox/Additions/common/crOpenGL/wgl.c
@@ -16,6 +16,8 @@
#include <windows.h>
#include <stdio.h>
+#include <iprt/cdefs.h>
+
/* Currently host part will misbehave re-creating context with proper visual bits
* if contexts with alternative visual bits is requested.
* For now we just report a superset of all visual bits to avoid that.
@@ -65,7 +67,7 @@ static GLuint ComputeVisBits( HDC hdc )
}
#endif
-int WINAPI wglChoosePixelFormat_prox( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
+DECLEXPORT(int) WINAPI wglChoosePixelFormat_prox( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
{
DWORD okayFlags;
@@ -162,7 +164,7 @@ int WINAPI wglChoosePixelFormat_prox( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd
return 1;
}
-BOOL WINAPI wglSetPixelFormat_prox( HDC hdc, int pixelFormat,
+DECLEXPORT(BOOL) WINAPI wglSetPixelFormat_prox( HDC hdc, int pixelFormat,
CONST PIXELFORMATDESCRIPTOR *pdf )
{
CR_DDI_PROLOGUE();
@@ -174,14 +176,14 @@ BOOL WINAPI wglSetPixelFormat_prox( HDC hdc, int pixelFormat,
return 1;
}
-BOOL WINAPI wglDeleteContext_prox( HGLRC hglrc )
+DECLEXPORT(BOOL) WINAPI wglDeleteContext_prox( HGLRC hglrc )
{
CR_DDI_PROLOGUE();
stubDestroyContext( (unsigned long) hglrc );
return 1;
}
-BOOL WINAPI wglMakeCurrent_prox( HDC hdc, HGLRC hglrc )
+DECLEXPORT(BOOL) WINAPI wglMakeCurrent_prox( HDC hdc, HGLRC hglrc )
{
ContextInfo *context;
WindowInfo *window;
@@ -208,14 +210,14 @@ BOOL WINAPI wglMakeCurrent_prox( HDC hdc, HGLRC hglrc )
return ret;
}
-HGLRC WINAPI wglGetCurrentContext_prox( void )
+DECLEXPORT(HGLRC) WINAPI wglGetCurrentContext_prox( void )
{
ContextInfo *context = stubGetCurrentContext();
CR_DDI_PROLOGUE();
return (HGLRC) (context ? context->id : 0);
}
-HDC WINAPI wglGetCurrentDC_prox( void )
+DECLEXPORT(HDC) WINAPI wglGetCurrentDC_prox( void )
{
ContextInfo *context = stubGetCurrentContext();
CR_DDI_PROLOGUE();
@@ -225,14 +227,14 @@ HDC WINAPI wglGetCurrentDC_prox( void )
return (HDC) NULL;
}
-int WINAPI wglGetPixelFormat_prox( HDC hdc )
+DECLEXPORT(int) WINAPI wglGetPixelFormat_prox( HDC hdc )
{
CR_DDI_PROLOGUE();
/* this is what we call our generic pixelformat, regardless of the HDC */
return 1;
}
-int WINAPI wglDescribePixelFormat_prox( HDC hdc, int pixelFormat, UINT nBytes,
+DECLEXPORT(int) WINAPI wglDescribePixelFormat_prox( HDC hdc, int pixelFormat, UINT nBytes,
LPPIXELFORMATDESCRIPTOR pfd )
{
CR_DDI_PROLOGUE();
@@ -286,15 +288,37 @@ int WINAPI wglDescribePixelFormat_prox( HDC hdc, int pixelFormat, UINT nBytes,
return 1;
}
-BOOL WINAPI wglShareLists_prox( HGLRC hglrc1, HGLRC hglrc2 )
+DECLEXPORT(BOOL) WINAPI wglShareLists_prox( HGLRC hglrc1, HGLRC hglrc2 )
{
CR_DDI_PROLOGUE();
crWarning( "wglShareLists: unsupported" );
return 0;
}
+DECLEXPORT(void) WINAPI VBoxCtxChromiumParameteriCR(HGLRC hglrc, GLenum param, GLint value)
+{
+ ContextInfo *context;
+
+ CR_DDI_PROLOGUE();
+
+// crHashtableLock(stub.windowTable);
+ crHashtableLock(stub.contextTable);
+
+ context = (ContextInfo *) crHashtableSearch(stub.contextTable, (unsigned long) hglrc);
+
+ if (context)
+ {
+ stubCtxCheckCreate(context);
+ stubConChromiumParameteriCR(CR_CTX_CON(context), param, value);
+ }
+ else
+ crWarning("invalid context %#x", hglrc);
-HGLRC WINAPI VBoxCreateContext( HDC hdc, struct VBOXUHGSMI *pHgsmi )
+ crHashtableUnlock(stub.contextTable);
+// crHashtableUnlock(stub.windowTable);
+}
+
+DECLEXPORT(HGLRC) WINAPI VBoxCreateContext( HDC hdc, struct VBOXUHGSMI *pHgsmi )
{
char dpyName[MAX_DPY_NAME];
ContextInfo *context;
@@ -324,12 +348,97 @@ HGLRC WINAPI VBoxCreateContext( HDC hdc, struct VBOXUHGSMI *pHgsmi )
return (HGLRC) context->id;
}
-HGLRC WINAPI wglCreateContext_prox( HDC hdc )
+DECLEXPORT(GLint) WINAPI VBoxGetWindowId( HDC hdc )
+{
+ WindowInfo *window;
+ GLint winid = 0;
+
+ CR_DDI_PROLOGUE();
+
+ crHashtableLock(stub.windowTable);
+
+ window = stubGetWindowInfo(hdc);
+ if (!window)
+ {
+ crWarning("stubGetWindowInfo: window not found!");
+ goto end;
+ }
+ if (!window->spuWindow)
+ {
+ crWarning("stubGetWindowInfo: window is null!");
+ goto end;
+ }
+
+ winid = window->spuWindow;
+
+end:
+ crHashtableUnlock(stub.windowTable);
+ return winid;
+}
+
+DECLEXPORT(GLint) WINAPI VBoxGetContextId( HGLRC hglrc )
+{
+ ContextInfo *context;
+ GLint ctxid = 0;
+
+ CR_DDI_PROLOGUE();
+
+// crHashtableLock(stub.windowTable);
+ crHashtableLock(stub.contextTable);
+
+ context = (ContextInfo *) crHashtableSearch(stub.contextTable, (unsigned long) hglrc);
+ if (!context)
+ {
+ crWarning("crHashtableSearch: context not found!");
+ goto end;
+ }
+
+ if (context->type != CHROMIUM)
+ {
+ crWarning("unexpected context type %d", context->type);
+ goto end;
+ }
+
+ if (context->spuContext <= 0)
+ {
+ crWarning("no spuSontext defined");
+ goto end;
+ }
+
+ ctxid = context->spuContext;
+
+end:
+ crHashtableUnlock(stub.contextTable);
+ return ctxid;
+}
+
+
+DECLEXPORT(HGLRC) WINAPI wglCreateContext_prox( HDC hdc )
{
return VBoxCreateContext(hdc, NULL);
}
-BOOL WINAPI
+DECLEXPORT(void) WINAPI VBoxFlushToHost ( HGLRC hglrc )
+{
+ ContextInfo *context;
+
+ CR_DDI_PROLOGUE();
+
+// crHashtableLock(stub.windowTable);
+ crHashtableLock(stub.contextTable);
+
+ context = (ContextInfo *) crHashtableSearch(stub.contextTable, (unsigned long) hglrc);
+
+ if (context)
+ stubConFlush(CR_CTX_CON(context));
+ else
+ crWarning("invalid context %#x", hglrc);
+
+ crHashtableUnlock(stub.contextTable);
+// crHashtableUnlock(stub.windowTable);
+}
+
+DECLEXPORT(BOOL) WINAPI
wglSwapBuffers_prox( HDC hdc )
{
WindowInfo *window = stubGetWindowInfo(hdc);
@@ -338,14 +447,14 @@ wglSwapBuffers_prox( HDC hdc )
return 1;
}
-BOOL WINAPI wglCopyContext_prox( HGLRC src, HGLRC dst, UINT mask )
+DECLEXPORT(BOOL) WINAPI wglCopyContext_prox( HGLRC src, HGLRC dst, UINT mask )
{
CR_DDI_PROLOGUE();
crWarning( "wglCopyContext: unsupported" );
return 0;
}
-HGLRC WINAPI wglCreateLayerContext_prox( HDC hdc, int layerPlane )
+DECLEXPORT(HGLRC) WINAPI wglCreateLayerContext_prox( HDC hdc, int layerPlane )
{
CR_DDI_PROLOGUE();
stubInit();
@@ -353,27 +462,27 @@ HGLRC WINAPI wglCreateLayerContext_prox( HDC hdc, int layerPlane )
return 0;
}
-PROC WINAPI wglGetProcAddress_prox( LPCSTR name )
+DECLEXPORT(PROC) WINAPI wglGetProcAddress_prox( LPCSTR name )
{
CR_DDI_PROLOGUE();
return (PROC) crGetProcAddress( name );
}
-BOOL WINAPI wglUseFontBitmapsA_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase )
+DECLEXPORT(BOOL) WINAPI wglUseFontBitmapsA_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase )
{
CR_DDI_PROLOGUE();
crWarning( "wglUseFontBitmapsA: unsupported" );
return 0;
}
-BOOL WINAPI wglUseFontBitmapsW_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase )
+DECLEXPORT(BOOL) WINAPI wglUseFontBitmapsW_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase )
{
CR_DDI_PROLOGUE();
crWarning( "wglUseFontBitmapsW: unsupported" );
return 0;
}
-BOOL WINAPI wglDescribeLayerPlane_prox( HDC hdc, int pixelFormat, int layerPlane,
+DECLEXPORT(BOOL) WINAPI wglDescribeLayerPlane_prox( HDC hdc, int pixelFormat, int layerPlane,
UINT nBytes, LPLAYERPLANEDESCRIPTOR lpd )
{
CR_DDI_PROLOGUE();
@@ -381,7 +490,7 @@ BOOL WINAPI wglDescribeLayerPlane_prox( HDC hdc, int pixelFormat, int layerPlane
return 0;
}
-int WINAPI wglSetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
+DECLEXPORT(int) WINAPI wglSetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
int entries, CONST COLORREF *cr )
{
CR_DDI_PROLOGUE();
@@ -389,7 +498,7 @@ int WINAPI wglSetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
return 0;
}
-int WINAPI wglGetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
+DECLEXPORT(int) WINAPI wglGetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
int entries, COLORREF *cr )
{
CR_DDI_PROLOGUE();
@@ -397,21 +506,21 @@ int WINAPI wglGetLayerPaletteEntries_prox( HDC hdc, int layerPlane, int start,
return 0;
}
-BOOL WINAPI wglRealizeLayerPalette_prox( HDC hdc, int layerPlane, BOOL realize )
+DECLEXPORT(BOOL) WINAPI wglRealizeLayerPalette_prox( HDC hdc, int layerPlane, BOOL realize )
{
CR_DDI_PROLOGUE();
crWarning( "wglRealizeLayerPalette: unsupported" );
return 0;
}
-DWORD WINAPI wglSwapMultipleBuffers_prox( UINT a, CONST void *b )
+DECLEXPORT(DWORD) WINAPI wglSwapMultipleBuffers_prox( UINT a, CONST void *b )
{
CR_DDI_PROLOGUE();
crWarning( "wglSwapMultipleBuffer: unsupported" );
return 0;
}
-BOOL WINAPI wglUseFontOutlinesA_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase,
+DECLEXPORT(BOOL) WINAPI wglUseFontOutlinesA_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase,
FLOAT deviation, FLOAT extrusion, int format,
LPGLYPHMETRICSFLOAT gmf )
{
@@ -420,7 +529,7 @@ BOOL WINAPI wglUseFontOutlinesA_prox( HDC hdc, DWORD first, DWORD count, DWORD l
return 0;
}
-BOOL WINAPI wglUseFontOutlinesW_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase,
+DECLEXPORT(BOOL) WINAPI wglUseFontOutlinesW_prox( HDC hdc, DWORD first, DWORD count, DWORD listBase,
FLOAT deviation, FLOAT extrusion, int format,
LPGLYPHMETRICSFLOAT gmf )
{
@@ -429,7 +538,7 @@ BOOL WINAPI wglUseFontOutlinesW_prox( HDC hdc, DWORD first, DWORD count, DWORD l
return 0;
}
-BOOL WINAPI wglSwapLayerBuffers_prox( HDC hdc, UINT planes )
+DECLEXPORT(BOOL) WINAPI wglSwapLayerBuffers_prox( HDC hdc, UINT planes )
{
CR_DDI_PROLOGUE();
if (planes == WGL_SWAP_MAIN_PLANE)
@@ -443,7 +552,7 @@ BOOL WINAPI wglSwapLayerBuffers_prox( HDC hdc, UINT planes )
}
}
-BOOL WINAPI wglChoosePixelFormatEXT_prox
+DECLEXPORT(BOOL) WINAPI wglChoosePixelFormatEXT_prox
(HDC hdc, const int *piAttributes, const FLOAT *pfAttributes, UINT nMaxFormats, int *piFormats, UINT *nNumFormats)
{
int *pi;
@@ -565,7 +674,7 @@ BOOL WINAPI wglChoosePixelFormatEXT_prox
return 1;
}
-BOOL WINAPI wglGetPixelFormatAttribivEXT_prox
+DECLEXPORT(BOOL) WINAPI wglGetPixelFormatAttribivEXT_prox
(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *pValues)
{
UINT i;
@@ -700,7 +809,7 @@ BOOL WINAPI wglGetPixelFormatAttribivEXT_prox
return 1;
}
-BOOL WINAPI wglGetPixelFormatAttribfvEXT_prox
+DECLEXPORT(BOOL) WINAPI wglGetPixelFormatAttribfvEXT_prox
(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, float *pValues)
{
UINT i;
@@ -835,13 +944,13 @@ BOOL WINAPI wglGetPixelFormatAttribfvEXT_prox
return 1;
}
-BOOL WINAPI wglSwapIntervalEXT_prox(int interval)
+DECLEXPORT(BOOL) WINAPI wglSwapIntervalEXT_prox(int interval)
{
CR_DDI_PROLOGUE();
return TRUE;
}
-int WINAPI wglGetSwapIntervalEXT_prox()
+DECLEXPORT(int) WINAPI wglGetSwapIntervalEXT_prox()
{
CR_DDI_PROLOGUE();
return 1;
@@ -849,13 +958,13 @@ int WINAPI wglGetSwapIntervalEXT_prox()
static GLubyte *gsz_wgl_extensions = "WGL_EXT_pixel_format WGL_ARB_pixel_format WGL_ARB_multisample";
-const GLubyte * WINAPI wglGetExtensionsStringEXT_prox()
+DECLEXPORT(const GLubyte *) WINAPI wglGetExtensionsStringEXT_prox()
{
CR_DDI_PROLOGUE();
return gsz_wgl_extensions;
}
-const GLubyte * WINAPI wglGetExtensionsStringARB_prox(HDC hdc)
+DECLEXPORT(const GLubyte *) WINAPI wglGetExtensionsStringARB_prox(HDC hdc)
{
CR_DDI_PROLOGUE();
(void) hdc;
diff --git a/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py b/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py
index 5de8cee9..fc167bed 100644
--- a/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py
+++ b/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py
@@ -37,7 +37,7 @@ static struct name_address functions[] = {
"""
-keys = apiutil.GetAllFunctions(sys.argv[1]+"/APIspec.txt")
+keys = apiutil.GetAllFunctionsAndOmittedAliases(sys.argv[1]+"/APIspec.txt")
for func_name in keys:
if "Chromium" == apiutil.Category(func_name):
continue
@@ -48,9 +48,16 @@ for func_name in keys:
if "GL_chromium" == apiutil.Category(func_name):
pass #continue
+ # alias is the function we're aliasing
+ proc_name = func_name
+ if "omit" in apiutil.ChromiumProps(func_name):
+ alias = apiutil.Alias(func_name)
+ if alias:
+ proc_name = alias
+
wrap = apiutil.GetCategoryWrapper(func_name)
name = "gl" + func_name
- address = "cr_gl" + func_name
+ address = "cr_gl" + proc_name
if wrap:
print '#ifdef CR_%s' % wrap
print '\t{ "%s", (CR_PROC) %s },' % (name, address)
@@ -136,18 +143,7 @@ CR_PROC CR_APIENTRY crGetProcAddress( const char *name )
if (!crStrcmp( name, "wglSwapIntervalEXT" )) return (CR_PROC) wglSwapIntervalEXT;
- /* this is needed for VSG Open Inventor stuff.
- * @todo: make all these auto-generated!!! */
- if (!crStrcmp( name, "glBeginQuery" )) return (CR_PROC) cr_glBeginQueryARB;
- if (!crStrcmp( name, "glDeleteQueries" )) return (CR_PROC) cr_glDeleteQueriesARB;
- if (!crStrcmp( name, "glEndQuery" )) return (CR_PROC) cr_glEndQueryARB;
- if (!crStrcmp( name, "glGenQueries" )) return (CR_PROC) cr_glGenQueriesARB;
- if (!crStrcmp( name, "glGetQueryObjectiv" )) return (CR_PROC) cr_glGetQueryObjectivARB;
- if (!crStrcmp( name, "glGetQueryObjectuiv" )) return (CR_PROC) cr_glGetQueryObjectuivARB;
- if (!crStrcmp( name, "glGetQueryiv" )) return (CR_PROC) cr_glGetQueryivARB;
- if (!crStrcmp( name, "glIsQuery" )) return (CR_PROC) cr_glIsQueryARB;
-
- crWarning("Returning GetProcAddress:NULL for %s", name);
+ crDebug("Returning GetProcAddress:NULL for %s", name);
return NULL;
}
diff --git a/src/VBox/Additions/common/pam/pam_vbox.cpp b/src/VBox/Additions/common/pam/pam_vbox.cpp
index b8d85fda..4852f033 100644
--- a/src/VBox/Additions/common/pam/pam_vbox.cpp
+++ b/src/VBox/Additions/common/pam/pam_vbox.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/common/testcase/tstPageFusion.cpp b/src/VBox/Additions/common/testcase/tstPageFusion.cpp
index 321d3bff..74a010f2 100644
--- a/src/VBox/Additions/common/testcase/tstPageFusion.cpp
+++ b/src/VBox/Additions/common/testcase/tstPageFusion.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;