VBoxServiceVMInfo.cpp revision 14f3cbbf0eaece196c9a3225e2b142b7385676f9
/* $Id$ */
/** @file
* VBoxVMInfo - Virtual machine (guest) information for the host.
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef RT_OS_WINDOWS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <Ntsecapi.h>
#else
# define __STDC_LIMIT_MACROS
# include <errno.h>
# include <unistd.h>
# include <utmp.h>
# ifdef RT_OS_SOLARIS
# endif
#endif
#include <iprt/semaphore.h>
#include <VBox/VBoxGuestLib.h>
#include "VBoxServiceInternal.h"
#include "VBoxServiceUtils.h"
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The vminfo interval (millseconds). */
uint32_t g_VMInfoInterval = 0;
/** The semaphore we're blocking on. */
/** The guest property service client ID. */
static uint32_t g_VMInfoGuestPropSvcClientID = 0;
/** Number of logged in users in OS. */
#ifdef RT_OS_WINDOWS
/** Function prototypes for dynamic loading. */
/** External functions. */
#endif
/** @copydoc VBOXSERVICE::pfnPreInit */
static DECLCALLBACK(int) VBoxServiceVMInfoPreInit(void)
{
return VINF_SUCCESS;
}
/** @copydoc VBOXSERVICE::pfnOption */
static DECLCALLBACK(int) VBoxServiceVMInfoOption(const char **ppszShort, int argc, char **argv, int *pi)
{
int rc = -1;
if (ppszShort)
/* no short options */;
return rc;
}
/** @copydoc VBOXSERVICE::pfnInit */
static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
{
/*
* If not specified, find the right interval default.
* Then create the event sem to block on.
*/
if (!g_VMInfoInterval)
if (!g_VMInfoInterval)
#ifdef RT_OS_WINDOWS
/* Get function pointers. */
{
g_pfnWTSGetActiveConsoleSessionId = (fnWTSGetActiveConsoleSessionId)GetProcAddress(hKernel32, "WTSGetActiveConsoleSessionId");
}
#endif
if (RT_SUCCESS(rc))
else
{
}
return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
{
int rc = VINF_SUCCESS;
/*
* Tell the control thread that it can continue
* spawning services.
*/
#ifdef RT_OS_WINDOWS
/* Required for network information (must be called per thread). */
}
#endif /* !RT_OS_WINDOWS */
/* First get information that won't change while the OS is running. */
char szInfo[256] = {0};
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Product", "%s", szInfo);
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Release", "%s", szInfo);
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Version", "%s", szInfo);
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/ServicePack", "%s", szInfo);
/* Retrieve version information about Guest Additions and installed files (components). */
#ifdef RT_OS_WINDOWS
#else
/* VBoxServiceGetAddsVersion !RT_OS_WINDOWS */
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Version", "%s", VBOX_VERSION_STRING);
char szRevision[32];
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Revision", "%s", szRevision);
#endif
/* Now enter the loop retrieving runtime data continuously. */
unsigned cErrors = 0;
for (;;)
{
/* Enumerate logged in users. */
uint32_t uiUserCount = 0;
char szUserList[4096] = {0};
#ifdef RT_OS_WINDOWS
#ifndef TARGET_NT4
NTSTATUS r = 0;
/* This function can report stale or orphaned interactive logon sessions of already logged
off users (especially in Windows 2000). */
if (r != STATUS_SUCCESS)
{
return 1;
}
for (int i = 0; i<(int)ulCount; i++)
{
{
if (uiUserCount > 0)
uiUserCount++;
}
}
#endif /* TARGET_NT4 */
#elif defined(RT_OS_FREEBSD)
/** @todo FreeBSD: Port logged on user info retrival. */
#else
if (rc != 0)
{
}
setutent();
{
/* Make sure we don't add user names which are not
* part of type USER_PROCESS and don't add same users twice. */
{
/** @todo Do we really want to filter out double user names? (Same user logged in twice) */
if (uiUserCount > 0)
uiUserCount++;
}
}
endutent();
#endif /* !RT_OS_WINDOWS */
if (uiUserCount > 0)
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", "%s", szUserList);
else
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL);
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%u", uiUserCount);
{
/* Update this property ONLY if there is a real change from no users to
* users or vice versa. The only exception is that the initialization
* forces an update, but only once. This ensures consistent property
* settings even if the VM aborted previously. */
if (uiUserCount == 0)
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", "true");
else if (g_VMInfoLoggedInUsers == 0)
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", "false");
}
/* Get network configuration. */
int nNumInterfaces = 0;
#ifdef RT_OS_WINDOWS
{
return -1;
}
unsigned long nBytesReturned = 0;
0,
0,
sizeof(InterfaceList),
0,
0) == SOCKET_ERROR)
{
return -1;
}
#else
if (sd < 0) /* Socket invalid. */
{
return -1;
}
char buffer[1024] = {0};
{
return -1;
}
#endif
char szPropPath [FILENAME_MAX];
char szTemp [FILENAME_MAX];
int iCurIface = 0;
/** @todo Use GetAdaptersInfo() and GetAdapterAddresses (IPv4 + IPv6) for more information. */
for (int i = 0; i < nNumInterfaces; ++i)
{
#ifdef RT_OS_WINDOWS
continue;
#else
{
return -1;
}
continue;
#endif
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
#ifdef RT_OS_WINDOWS
#else
{
return -1;
}
#endif
RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/Broadcast", iCurIface);
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
#ifdef RT_OS_WINDOWS
#else
{
return -1;
}
#else
#endif
#endif
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
iCurIface++;
}
#ifdef RT_OS_WINDOWS
#else
#endif /* !RT_OS_WINDOWS */
/*
* Block for a while.
*
* The event semaphore takes care of ignoring interruptions and it
* allows us to implement service wakeup later.
*/
if (*pfShutdown)
break;
if (*pfShutdown)
break;
{
break;
}
}
#ifdef RT_OS_WINDOWS
WSACleanup();
#endif /* !RT_OS_WINDOWS */
return rc;
}
/** @copydoc VBOXSERVICE::pfnStop */
static DECLCALLBACK(void) VBoxServiceVMInfoStop(void)
{
}
/** @copydoc VBOXSERVICE::pfnTerm */
static DECLCALLBACK(void) VBoxServiceVMInfoTerm(void)
{
int rc;
if (g_VMInfoEvent != NIL_RTSEMEVENTMULTI)
{
/** @todo temporary solution: Zap all values which are not valid
* be replaced with "temporary properties" later.
*
* @todo r=bird: This code isn't called on non-Windows systems. We need
* a more formal way of shutting down the service for that to work.
*/
rc = VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL);
rc = VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%d", 0);
if (g_VMInfoLoggedInUsers > 0)
VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", "true");
rc = VBoxServiceWritePropF(g_VMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/Net/Count", "%d", 0);
/* Disconnect from guest properties service. */
if (RT_FAILURE(rc))
}
}
/**
* The 'vminfo' service description.
*/
{
/* pszName. */
"vminfo",
/* pszDescription. */
"Virtual Machine Information",
/* pszUsage. */
"[--vminfo-interval <ms>]"
,
/* pszOptions. */
" --vminfo-interval Specifies the interval at which to retrieve the\n"
" VM information. The default is 10000 ms.\n"
,
/* methods */
};